Files
wehub-resource-sync f2306a3d11
Lint and Test / lint_test (3.11) (push) Has been cancelled
Lint and Test / lint_test (3.10) (push) Has been cancelled
Lint and Test / lint_test (3.12) (push) Has been cancelled
Publish to PyPI and release / Build distribution (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Publish to PyPI and release / Publish to PyPI (push) Has been cancelled
Publish to PyPI and release / Make release (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:48:44 +08:00

277 lines
8.1 KiB
Python

import os
# To allow users to use arrow keys in the REPL.
import readline # noqa: F401
import sys
import typer
from click import UsageError
from click.types import Choice
from prompt_toolkit import PromptSession
from sgpt.config import cfg
from sgpt.function import get_openai_schemas
from sgpt.handlers.chat_handler import ChatHandler
from sgpt.handlers.default_handler import DefaultHandler
from sgpt.handlers.repl_handler import ReplHandler
from sgpt.llm_functions.init_functions import install_functions as inst_funcs
from sgpt.role import DefaultRoles, SystemRole
from sgpt.utils import (
get_edited_prompt,
get_sgpt_version,
install_shell_integration,
run_command,
)
def main(
prompt: str = typer.Argument(
"",
show_default=False,
help="The prompt to generate completions for.",
),
model: str = typer.Option(
cfg.get("DEFAULT_MODEL"),
help="Large language model to use.",
),
temperature: float = typer.Option(
cfg.get("DEFAULT_TEMPERATURE"),
min=0.0,
max=2.0,
help="Randomness of generated output.",
),
top_p: float = typer.Option(
1.0,
min=0.0,
max=1.0,
help="Limits highest probable tokens (words).",
),
md: bool = typer.Option(
cfg.get("PRETTIFY_MARKDOWN") == "true",
help="Prettify markdown output.",
),
shell: bool = typer.Option(
False,
"--shell",
"-s",
help="Generate and execute shell commands.",
rich_help_panel="Assistance Options",
),
interaction: bool = typer.Option(
cfg.get("SHELL_INTERACTION") == "true",
help="Interactive mode for --shell option.",
rich_help_panel="Assistance Options",
),
describe_shell: bool = typer.Option(
False,
"--describe-shell",
"-d",
help="Describe a shell command.",
rich_help_panel="Assistance Options",
),
code: bool = typer.Option(
False,
"--code",
"-c",
help="Generate only code.",
rich_help_panel="Assistance Options",
),
functions: bool = typer.Option(
cfg.get("OPENAI_USE_FUNCTIONS") == "true",
help="Allow function calls.",
rich_help_panel="Assistance Options",
),
editor: bool = typer.Option(
False,
help="Open $EDITOR to provide a prompt.",
),
cache: bool = typer.Option(
True,
help="Cache completion results.",
),
version: bool = typer.Option(
False,
"--version",
help="Show version.",
callback=get_sgpt_version,
),
chat: str = typer.Option(
None,
help="Follow conversation with id, " 'use "temp" for quick session.',
rich_help_panel="Chat Options",
),
repl: str = typer.Option(
None,
help="Start a REPL (Read-eval-print loop) session.",
rich_help_panel="Chat Options",
),
show_chat: str = typer.Option(
None,
help="Show all messages from provided chat id.",
rich_help_panel="Chat Options",
),
list_chats: bool = typer.Option(
False,
"--list-chats",
"-lc",
help="List all existing chat ids.",
callback=ChatHandler.list_ids,
rich_help_panel="Chat Options",
),
role: str = typer.Option(
None,
help="System role for GPT model.",
rich_help_panel="Role Options",
),
create_role: str = typer.Option(
None,
help="Create role.",
callback=SystemRole.create,
rich_help_panel="Role Options",
),
show_role: str = typer.Option(
None,
help="Show role.",
callback=SystemRole.show,
rich_help_panel="Role Options",
),
list_roles: bool = typer.Option(
False,
"--list-roles",
"-lr",
help="List roles.",
callback=SystemRole.list,
rich_help_panel="Role Options",
),
install_integration: bool = typer.Option(
False,
help="Install shell integration (ZSH and Bash only)",
callback=install_shell_integration,
hidden=True, # Hiding since should be used only once.
),
install_functions: bool = typer.Option(
False,
help="Install default functions.",
callback=inst_funcs,
hidden=True, # Hiding since should be used only once.
),
) -> None:
stdin_passed = not sys.stdin.isatty()
if stdin_passed:
stdin = ""
# TODO: This is very hacky.
# In some cases, we need to pass stdin along with inputs.
# When we want part of stdin to be used as a init prompt,
# but rest of the stdin to be used as a inputs. For example:
# echo "hello\n__sgpt__eof__\nThis is input" | sgpt --repl temp
# In this case, "hello" will be used as a init prompt, and
# "This is input" will be used as "interactive" input to the REPL.
# This is useful to test REPL with some initial context.
for line in sys.stdin:
if "__sgpt__eof__" in line:
break
stdin += line
prompt = f"{stdin}\n\n{prompt}" if prompt else stdin
try:
# Switch to stdin for interactive input.
if os.name == "posix":
sys.stdin = open("/dev/tty", "r")
elif os.name == "nt":
sys.stdin = open("CON", "r")
except OSError:
# Non-interactive shell.
pass
if show_chat:
ChatHandler.show_messages(show_chat, md)
if sum((shell, describe_shell, code)) > 1:
raise UsageError(
"Only one of --shell, --describe-shell, and --code options can be used at a time."
)
if chat and repl:
raise UsageError("--chat and --repl options cannot be used together.")
if editor and stdin_passed:
raise UsageError("--editor option cannot be used with stdin input.")
if editor:
prompt = get_edited_prompt()
role_class = (
DefaultRoles.check_get(shell, describe_shell, code)
if not role
else SystemRole.get(role)
)
function_schemas = (get_openai_schemas() or None) if functions else None
if repl:
# Will be in infinite loop here until user exits with Ctrl+C.
ReplHandler(repl, role_class, md).handle(
init_prompt=prompt,
model=model,
temperature=temperature,
top_p=top_p,
caching=cache,
functions=function_schemas,
)
if chat:
full_completion = ChatHandler(chat, role_class, md).handle(
prompt=prompt,
model=model,
temperature=temperature,
top_p=top_p,
caching=cache,
functions=function_schemas,
)
else:
full_completion = DefaultHandler(role_class, md).handle(
prompt=prompt,
model=model,
temperature=temperature,
top_p=top_p,
caching=cache,
functions=function_schemas,
)
session: PromptSession[str] = PromptSession()
while shell and interaction:
option = typer.prompt(
text="[E]xecute, [M]odify, [D]escribe, [A]bort",
type=Choice(("e", "m", "d", "a", "y"), case_sensitive=False),
default="e" if cfg.get("DEFAULT_EXECUTE_SHELL_CMD") == "true" else "a",
show_choices=False,
show_default=False,
)
if option in ("e", "y"):
# "y" option is for keeping compatibility with old version.
run_command(full_completion)
elif option == "m":
full_completion = session.prompt("", default=full_completion)
continue
elif option == "d":
DefaultHandler(DefaultRoles.DESCRIBE_SHELL.get_role(), md).handle(
full_completion,
model=model,
temperature=temperature,
top_p=top_p,
caching=cache,
functions=function_schemas,
)
continue
break
def entry_point() -> None:
typer.run(main)
if __name__ == "__main__":
entry_point()