chore: use primitives instead of typing imports and fixes completion … (#149)
Signed-off-by: Adrian Cole <adrian.cole@elastic.co>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
from functools import cache
|
||||
from pathlib import Path
|
||||
from typing import Callable, Dict, Mapping, Optional, Tuple
|
||||
from typing import Mapping, Optional
|
||||
|
||||
from rich import print
|
||||
from rich.panel import Panel
|
||||
@@ -20,7 +20,7 @@ RECOMMENDED_DEFAULT_PROVIDER = "openai"
|
||||
|
||||
|
||||
@cache
|
||||
def default_profiles() -> Mapping[str, Callable]:
|
||||
def default_profiles() -> Mapping[str, callable]:
|
||||
return load_plugins(group="goose.profile")
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ def session_path(name: str) -> Path:
|
||||
return SESSIONS_PATH.joinpath(f"{name}{SESSION_FILE_SUFFIX}")
|
||||
|
||||
|
||||
def write_config(profiles: Dict[str, Profile]) -> None:
|
||||
def write_config(profiles: dict[str, Profile]) -> None:
|
||||
"""Overwrite the config with the passed profiles"""
|
||||
PROFILES_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
converted = {name: profile.to_dict() for name, profile in profiles.items()}
|
||||
@@ -38,7 +38,7 @@ def write_config(profiles: Dict[str, Profile]) -> None:
|
||||
yaml.dump(converted, f)
|
||||
|
||||
|
||||
def ensure_config(name: Optional[str]) -> Tuple[str, Profile]:
|
||||
def ensure_config(name: Optional[str]) -> tuple[str, Profile]:
|
||||
"""Ensure that the config exists and has the default section"""
|
||||
# TODO we should copy a templated default config in to better document
|
||||
# but this is complicated a bit by autodetecting the provider
|
||||
@@ -70,7 +70,7 @@ def ensure_config(name: Optional[str]) -> Tuple[str, Profile]:
|
||||
return (name, default_profile)
|
||||
|
||||
|
||||
def read_config() -> Dict[str, Profile]:
|
||||
def read_config() -> dict[str, Profile]:
|
||||
"""Return config from the configuration file and validates its contents"""
|
||||
|
||||
yaml = YAML()
|
||||
@@ -80,7 +80,7 @@ def read_config() -> Dict[str, Profile]:
|
||||
return {name: Profile(**profile) for name, profile in data.items()}
|
||||
|
||||
|
||||
def default_model_configuration() -> Tuple[str, str, str]:
|
||||
def default_model_configuration() -> tuple[str, str, str]:
|
||||
providers = load_plugins(group="exchange.provider")
|
||||
for provider, cls in providers.items():
|
||||
try:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import re
|
||||
from typing import List
|
||||
|
||||
from prompt_toolkit.completion import CompleteEvent, Completer, Completion
|
||||
from prompt_toolkit.document import Document
|
||||
@@ -8,10 +7,10 @@ from goose.command.base import Command
|
||||
|
||||
|
||||
class GoosePromptCompleter(Completer):
|
||||
def __init__(self, commands: List[Command]) -> None:
|
||||
def __init__(self, commands: list[Command]) -> None:
|
||||
self.commands = commands
|
||||
|
||||
def get_command_completions(self, document: Document) -> List[Completion]:
|
||||
def get_command_completions(self, document: Document) -> list[Completion]:
|
||||
all_completions = []
|
||||
for command_name, command_instance in self.commands.items():
|
||||
pattern = rf"(?<!\S)\/{command_name}:([\S]*)$"
|
||||
@@ -25,7 +24,7 @@ class GoosePromptCompleter(Completer):
|
||||
all_completions.extend(completions)
|
||||
return all_completions
|
||||
|
||||
def get_command_name_completions(self, document: Document) -> List[Completion]:
|
||||
def get_command_name_completions(self, document: Document) -> list[Completion]:
|
||||
pattern = r"(?<!\S)\/([\S]*)$"
|
||||
text = document.text_before_cursor
|
||||
match = re.search(pattern=pattern, string=text)
|
||||
@@ -40,7 +39,7 @@ class GoosePromptCompleter(Completer):
|
||||
completions.append(Completion(command_name, start_position=-len(query), display=command_name))
|
||||
return completions
|
||||
|
||||
def get_completions(self, document: Document, _: CompleteEvent) -> List[Completion]:
|
||||
def get_completions(self, document: Document, _: CompleteEvent) -> list[Completion]:
|
||||
command_completions = self.get_command_completions(document)
|
||||
command_name_completions = self.get_command_name_completions(document)
|
||||
return command_name_completions + command_completions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
from typing import Callable, List, Tuple
|
||||
from typing import Callable
|
||||
|
||||
from prompt_toolkit.document import Document
|
||||
from prompt_toolkit.lexers import Lexer
|
||||
@@ -27,7 +27,7 @@ def value_for_command(command_string: str) -> re.Pattern[str]:
|
||||
|
||||
|
||||
class PromptLexer(Lexer):
|
||||
def __init__(self, command_names: List[str]) -> None:
|
||||
def __init__(self, command_names: list[str]) -> None:
|
||||
self.patterns = []
|
||||
for command_name in command_names:
|
||||
self.patterns.append((completion_for_command(command_name), "class:command"))
|
||||
@@ -35,7 +35,7 @@ class PromptLexer(Lexer):
|
||||
self.patterns.append((command_itself(command_name), "class:command"))
|
||||
|
||||
def lex_document(self, document: Document) -> Callable[[int], list]:
|
||||
def get_line_tokens(line_number: int) -> Tuple[str, str]:
|
||||
def get_line_tokens(line_number: int) -> tuple[str, str]:
|
||||
line = document.lines[line_number]
|
||||
tokens = []
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
from typing import Any
|
||||
|
||||
from rich.prompt import Prompt
|
||||
|
||||
|
||||
class OverwriteSessionPrompt(Prompt):
|
||||
def __init__(self, *args: tuple[Any], **kwargs: dict[str, Any]) -> None:
|
||||
def __init__(self, *args: tuple[any], **kwargs: dict[str, any]) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.choices = {
|
||||
"yes": "Overwrite the existing session",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
from typing import Optional
|
||||
|
||||
from exchange import Message, Text, ToolResult, ToolUse
|
||||
from rich import print
|
||||
@@ -62,7 +62,7 @@ class Session:
|
||||
profile: Optional[str] = None,
|
||||
plan: Optional[dict] = None,
|
||||
log_level: Optional[str] = "INFO",
|
||||
**kwargs: dict[str, Any],
|
||||
**kwargs: dict[str, any],
|
||||
) -> None:
|
||||
if name is None:
|
||||
self.name = droid()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from functools import cache
|
||||
from typing import Dict
|
||||
|
||||
from goose.command.base import Command
|
||||
from goose.utils import load_plugins
|
||||
@@ -11,5 +10,5 @@ def get_command(name: str) -> type[Command]:
|
||||
|
||||
|
||||
@cache
|
||||
def get_commands() -> Dict[str, type[Command]]:
|
||||
def get_commands() -> dict[str, type[Command]]:
|
||||
return load_plugins(group="goose.command")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from abc import ABC
|
||||
from typing import List, Optional
|
||||
from typing import Optional
|
||||
|
||||
from prompt_toolkit.completion import Completion
|
||||
|
||||
@@ -7,7 +7,7 @@ from prompt_toolkit.completion import Completion
|
||||
class Command(ABC):
|
||||
"""A command that can be executed by the CLI."""
|
||||
|
||||
def get_completions(self, query: str) -> List[Completion]:
|
||||
def get_completions(self, query: str) -> list[Completion]:
|
||||
"""
|
||||
Get completions for the command.
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import os
|
||||
from typing import List
|
||||
|
||||
from prompt_toolkit.completion import Completion
|
||||
|
||||
@@ -7,7 +6,7 @@ from goose.command.base import Command
|
||||
|
||||
|
||||
class FileCommand(Command):
|
||||
def get_completions(self, query: str) -> List[Completion]:
|
||||
def get_completions(self, query: str) -> list[Completion]:
|
||||
if query.startswith("/"):
|
||||
directory = os.path.dirname(query)
|
||||
search_term = os.path.basename(query)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict, List, Mapping, Type
|
||||
from typing import Mapping
|
||||
|
||||
from attrs import asdict, define, field
|
||||
|
||||
@@ -21,10 +21,10 @@ class Profile:
|
||||
processor: str
|
||||
accelerator: str
|
||||
moderator: str
|
||||
toolkits: List[ToolkitSpec] = field(factory=list, converter=ensure_list(ToolkitSpec))
|
||||
toolkits: list[ToolkitSpec] = field(factory=list, converter=ensure_list(ToolkitSpec))
|
||||
|
||||
@toolkits.validator
|
||||
def check_toolkit_requirements(self, _: Type["ToolkitSpec"], toolkits: List[ToolkitSpec]) -> None:
|
||||
def check_toolkit_requirements(self, _: type["ToolkitSpec"], toolkits: list[ToolkitSpec]) -> None:
|
||||
# checks that the list of toolkits in the profile have their requirements
|
||||
installed_toolkits = set([toolkit.name for toolkit in toolkits])
|
||||
|
||||
@@ -36,7 +36,7 @@ class Profile:
|
||||
msg = f"Toolkit {toolkit_name} requires {req} but it is not present"
|
||||
raise ValueError(msg)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
def to_dict(self) -> dict[str, any]:
|
||||
return asdict(self)
|
||||
|
||||
def profile_info(self) -> str:
|
||||
@@ -44,7 +44,7 @@ class Profile:
|
||||
return f"provider:{self.provider}, processor:{self.processor} toolkits: {', '.join(tookit_names)}"
|
||||
|
||||
|
||||
def default_profile(provider: str, processor: str, accelerator: str, **kwargs: Dict[str, Any]) -> Profile:
|
||||
def default_profile(provider: str, processor: str, accelerator: str, **kwargs: dict[str, any]) -> Profile:
|
||||
"""Get the default profile"""
|
||||
|
||||
# TODO consider if the providers should have recommended models
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import inspect
|
||||
from abc import ABC
|
||||
from typing import Callable, Mapping, Optional, Tuple, TypeVar
|
||||
from typing import Mapping, Optional, TypeVar
|
||||
|
||||
from attrs import define, field
|
||||
from exchange import Tool
|
||||
@@ -8,7 +8,7 @@ from exchange import Tool
|
||||
from goose.notifier import Notifier
|
||||
|
||||
# Create a type variable that can represent any function signature
|
||||
F = TypeVar("F", bound=Callable)
|
||||
F = TypeVar("F", bound=callable)
|
||||
|
||||
|
||||
def tool(func: F) -> F:
|
||||
@@ -55,7 +55,7 @@ class Toolkit(ABC):
|
||||
"""Get the addition to the system prompt for this toolkit."""
|
||||
return ""
|
||||
|
||||
def tools(self) -> Tuple[Tool, ...]:
|
||||
def tools(self) -> tuple[Tool, ...]:
|
||||
"""Get the tools for this toolkit
|
||||
|
||||
This default method looks for functions on the toolkit annotated
|
||||
|
||||
@@ -3,7 +3,6 @@ import re
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
from exchange import Message
|
||||
from goose.toolkit.base import Toolkit, tool
|
||||
@@ -35,9 +34,9 @@ class Developer(Toolkit):
|
||||
We also include some default shell strategies in the prompt, such as using ripgrep
|
||||
"""
|
||||
|
||||
def __init__(self, *args: object, **kwargs: Dict[str, object]) -> None:
|
||||
def __init__(self, *args: object, **kwargs: dict[str, object]) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.timestamps: Dict[str, float] = {}
|
||||
self.timestamps: dict[str, float] = {}
|
||||
|
||||
def system(self) -> str:
|
||||
"""Retrieve system configuration details for developer"""
|
||||
@@ -55,7 +54,7 @@ class Developer(Toolkit):
|
||||
return system_prompt
|
||||
|
||||
@tool
|
||||
def update_plan(self, tasks: List[dict]) -> List[dict]:
|
||||
def update_plan(self, tasks: list[dict]) -> list[dict]:
|
||||
"""
|
||||
Update the plan by overwriting all current tasks
|
||||
|
||||
@@ -63,7 +62,7 @@ class Developer(Toolkit):
|
||||
shown to the user directly, you do not need to reiterate it
|
||||
|
||||
Args:
|
||||
tasks (List(dict)): The list of tasks, where each task is a dictionary
|
||||
tasks (list(dict)): The list of tasks, where each task is a dictionary
|
||||
with a key for the task "description" and the task "status". The status
|
||||
MUST be one of "planned", "complete", "failed", "in-progress".
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import os
|
||||
from functools import cache
|
||||
from subprocess import CompletedProcess, run
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from exchange import Message
|
||||
|
||||
@@ -21,7 +20,7 @@ class RepoContext(Toolkit):
|
||||
|
||||
self.repo_project_root, self.is_git_repo, self.goose_session_root = self.determine_git_proj()
|
||||
|
||||
def determine_git_proj(self) -> Tuple[str, bool, str]:
|
||||
def determine_git_proj(self) -> tuple[str, bool, str]:
|
||||
"""Determines the root as well as where Goose is currently running
|
||||
|
||||
If the project is not part of a Github repo, the root of the project will be defined as the current working
|
||||
@@ -72,11 +71,11 @@ class RepoContext(Toolkit):
|
||||
return self.repo_size > 2000
|
||||
|
||||
@tool
|
||||
def summarize_current_project(self) -> Dict[str, str]:
|
||||
def summarize_current_project(self) -> dict[str, str]:
|
||||
"""Summarizes the current project based on repo root (if git repo) or current project_directory (if not)
|
||||
|
||||
Returns:
|
||||
summary (Dict[str, str]): Keys are file paths and values are the summaries
|
||||
summary (dict[str, str]): Keys are file paths and values are the summaries
|
||||
"""
|
||||
|
||||
self.notifier.log("Summarizing the most relevant files in the current project. This may take a while...")
|
||||
|
||||
@@ -2,7 +2,6 @@ import ast
|
||||
import concurrent.futures
|
||||
import os
|
||||
from collections import deque
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from exchange import Exchange
|
||||
|
||||
@@ -26,7 +25,7 @@ def get_repo_size(repo_path: str) -> int:
|
||||
return get_directory_size(git_dir) / (1024**2)
|
||||
|
||||
|
||||
def get_files_and_directories(root_dir: str) -> Dict[str, list]:
|
||||
def get_files_and_directories(root_dir: str) -> dict[str, list]:
|
||||
"""Gets file names and directory names. Checks that goose has correctly typed the file and directory names and that
|
||||
the files actually exist (to avoid downstream file read errors).
|
||||
|
||||
@@ -61,7 +60,7 @@ def get_files_and_directories(root_dir: str) -> Dict[str, list]:
|
||||
return {"files": files, "directories": dirs}
|
||||
|
||||
|
||||
def goose_picks_files(root: str, exchange: Exchange, max_workers: int = 4) -> List[str]:
|
||||
def goose_picks_files(root: str, exchange: Exchange, max_workers: int = 4) -> list[str]:
|
||||
"""Lets goose pick files in a BFS manner"""
|
||||
queue = deque([root])
|
||||
|
||||
@@ -80,7 +79,7 @@ def goose_picks_files(root: str, exchange: Exchange, max_workers: int = 4) -> Li
|
||||
return all_files
|
||||
|
||||
|
||||
def process_directory(current_dir: str, exchange: Exchange) -> Tuple[List[str], List[str]]:
|
||||
def process_directory(current_dir: str, exchange: Exchange) -> tuple[list[str], list[str]]:
|
||||
"""Allows goose to pick files and subdirectories contained in a given directory (current_dir). Get the list of file
|
||||
and directory names in the current folder, then ask Goose to pick which ones to keep.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import List, Optional
|
||||
from typing import Optional
|
||||
|
||||
from goose.toolkit import Toolkit
|
||||
from goose.toolkit.base import tool
|
||||
@@ -11,7 +11,7 @@ class SummarizeProject(Toolkit):
|
||||
def get_project_summary(
|
||||
self,
|
||||
project_dir_path: Optional[str] = os.getcwd(),
|
||||
extensions: Optional[List[str]] = None,
|
||||
extensions: Optional[list[str]] = None,
|
||||
summary_instructions_prompt: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""Generates or retrieves a project summary based on specified file extensions.
|
||||
@@ -19,7 +19,7 @@ class SummarizeProject(Toolkit):
|
||||
Args:
|
||||
project_dir_path (Optional[Path]): Path to the project directory. Defaults to the current working directory
|
||||
if None
|
||||
extensions (Optional[List[str]]): Specific file extensions to summarize.
|
||||
extensions (Optional[list[str]]): Specific file extensions to summarize.
|
||||
summary_instructions_prompt (Optional[str]): Instructions to give to the LLM about how to summarize each file. E.g.
|
||||
"Summarize the file in two sentences.". The default instruction is "Please summarize this file."
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List, Optional
|
||||
from typing import Optional
|
||||
|
||||
from goose.toolkit import Toolkit
|
||||
from goose.toolkit.base import tool
|
||||
@@ -10,7 +10,7 @@ class SummarizeRepo(Toolkit):
|
||||
def summarize_repo(
|
||||
self,
|
||||
repo_url: str,
|
||||
specified_extensions: Optional[List[str]] = None,
|
||||
specified_extensions: Optional[list[str]] = None,
|
||||
summary_instructions_prompt: Optional[str] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
@@ -19,7 +19,7 @@ class SummarizeRepo(Toolkit):
|
||||
|
||||
Args:
|
||||
repo_url (str): The URL of the repository to summarize.
|
||||
specified_extensions (Optional[List[str]]): List of file extensions to summarize, e.g., ["tf", "md"]. If
|
||||
specified_extensions (Optional[list[str]]): list of file extensions to summarize, e.g., ["tf", "md"]. If
|
||||
this list is empty, then all files in the repo are summarized
|
||||
summary_instructions_prompt (Optional[str]): Instructions to give to the LLM about how to summarize each file. E.g.
|
||||
"Summarize the file in two sentences.". The default instruction is "Please summarize this file."
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
import subprocess
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from typing import Optional
|
||||
|
||||
from exchange import Exchange
|
||||
from exchange.providers.utils import InitialMessageTooLargeError
|
||||
@@ -15,7 +15,7 @@ CLONED_REPOS_FOLDER = ".goose/cloned_repos"
|
||||
|
||||
|
||||
# TODO: move git stuff
|
||||
def run_git_command(command: List[str]) -> subprocess.CompletedProcess[str]:
|
||||
def run_git_command(command: list[str]) -> subprocess.CompletedProcess[str]:
|
||||
result = subprocess.run(["git"] + command, capture_output=True, text=True, check=False)
|
||||
|
||||
if result.returncode != 0:
|
||||
@@ -28,7 +28,7 @@ def clone_repo(repo_url: str, target_directory: str) -> None:
|
||||
run_git_command(["clone", repo_url, target_directory])
|
||||
|
||||
|
||||
def load_summary_file_if_exists(project_name: str) -> Optional[Dict]:
|
||||
def load_summary_file_if_exists(project_name: str) -> Optional[dict]:
|
||||
"""Checks if a summary file exists at '.goose/summaries/projectname-summary.json. Returns contents of the file if
|
||||
it exists, otherwise returns None
|
||||
|
||||
@@ -36,7 +36,7 @@ def load_summary_file_if_exists(project_name: str) -> Optional[Dict]:
|
||||
project_name (str): name of the project or repo
|
||||
|
||||
Returns:
|
||||
Optional[Dict]: File contents, else None
|
||||
Optional[dict]: File contents, else None
|
||||
"""
|
||||
summary_file_path = f"{SUMMARIES_FOLDER}/{project_name}-summary.json"
|
||||
if Path(summary_file_path).exists():
|
||||
@@ -44,7 +44,7 @@ def load_summary_file_if_exists(project_name: str) -> Optional[Dict]:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def summarize_file(filepath: str, exchange: Exchange, prompt: Optional[str] = None) -> Tuple[str, str]:
|
||||
def summarize_file(filepath: str, exchange: Exchange, prompt: Optional[str] = None) -> tuple[str, str]:
|
||||
"""Summarizes a single file
|
||||
|
||||
Args:
|
||||
@@ -74,15 +74,15 @@ def summarize_file(filepath: str, exchange: Exchange, prompt: Optional[str] = No
|
||||
def summarize_repo(
|
||||
repo_url: str,
|
||||
exchange: Exchange,
|
||||
extensions: List[str],
|
||||
extensions: list[str],
|
||||
summary_instructions_prompt: Optional[str] = None,
|
||||
) -> Dict[str, str]:
|
||||
) -> dict[str, str]:
|
||||
"""Clones (if needed) and summarizes a repo
|
||||
|
||||
Args:
|
||||
repo_url (str): Repository url
|
||||
exchange (Exchange): Exchange for summarizing the repo.
|
||||
extensions (List[str]): List of file-types to summarize.
|
||||
extensions (list[str]): list of file-types to summarize.
|
||||
summary_instructions_prompt (Optional[str]): Optional parameter to customize summarization results. Defaults to
|
||||
"Please summarize this file"
|
||||
"""
|
||||
@@ -110,15 +110,15 @@ def summarize_repo(
|
||||
|
||||
|
||||
def summarize_directory(
|
||||
directory: str, exchange: Exchange, extensions: List[str], summary_instructions_prompt: Optional[str] = None
|
||||
) -> Dict[str, str]:
|
||||
directory: str, exchange: Exchange, extensions: list[str], summary_instructions_prompt: Optional[str] = None
|
||||
) -> dict[str, str]:
|
||||
"""Summarize files in a given directory based on extensions. Will also recursively find files in subdirectories and
|
||||
summarize them.
|
||||
|
||||
Args:
|
||||
directory (str): path to the top-level directory to summarize
|
||||
exchange (Exchange): Exchange to use to summarize
|
||||
extensions (List[str]): List of file-type extensions to summarize (and ignore all other extensions).
|
||||
extensions (list[str]): list of file-type extensions to summarize (and ignore all other extensions).
|
||||
summary_instructions_prompt (Optional[str]): Optional instructions to give to the exchange regarding summarization.
|
||||
|
||||
Returns:
|
||||
@@ -158,19 +158,19 @@ def summarize_directory(
|
||||
|
||||
|
||||
def summarize_files_concurrent(
|
||||
exchange: Exchange, file_list: List[str], project_name: str, summary_instructions_prompt: Optional[str] = None
|
||||
) -> Dict[str, str]:
|
||||
exchange: Exchange, file_list: list[str], project_name: str, summary_instructions_prompt: Optional[str] = None
|
||||
) -> dict[str, str]:
|
||||
"""Takes in a list of files and summarizes them. Exchange does not keep history of the summarized files.
|
||||
|
||||
Args:
|
||||
exchange (Exchange): Underlying exchange
|
||||
file_list (List[str]): List of paths to files to summarize
|
||||
file_list (list[str]): list of paths to files to summarize
|
||||
project_name (str): Used to save the summary of the files to .goose/summaries/<project_name>-summary.json
|
||||
summary_instructions_prompt (Optional[str]): Summary instructions for the LLM. Defaults to "Please summarize
|
||||
this file."
|
||||
|
||||
Returns:
|
||||
file_summaries (Dict[str, str]): Keys are file paths and values are the summaries returned by the Exchange
|
||||
file_summaries (dict[str, str]): Keys are file paths and values are the summaries returned by the Exchange
|
||||
"""
|
||||
summary_file = load_summary_file_if_exists(project_name)
|
||||
if summary_file:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict
|
||||
from typing import Optional
|
||||
|
||||
from pygments.lexers import get_lexer_for_filename
|
||||
from pygments.util import ClassNotFound
|
||||
@@ -67,7 +67,7 @@ def find_last_task_group_index(input_str: str) -> int:
|
||||
return last_group_start_index
|
||||
|
||||
|
||||
def parse_plan(input_plan_str: str) -> Dict:
|
||||
def parse_plan(input_plan_str: str) -> dict:
|
||||
last_group_start_index = find_last_task_group_index(input_plan_str)
|
||||
if last_group_start_index == -1:
|
||||
return {"kickoff_message": input_plan_str, "tasks": []}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import random
|
||||
import string
|
||||
from importlib.metadata import entry_points
|
||||
from typing import Any, Callable, Dict, List, Type, TypeVar
|
||||
from typing import TypeVar, Callable
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@@ -31,10 +31,10 @@ def load_plugins(group: str) -> dict:
|
||||
return plugins
|
||||
|
||||
|
||||
def ensure(cls: Type[T]) -> Callable[[Any], T]:
|
||||
def ensure(cls: type[T]) -> Callable[[any], T]:
|
||||
"""Convert dictionary to a class instance"""
|
||||
|
||||
def converter(val: Any) -> T: # noqa: ANN401
|
||||
def converter(val: any) -> T: # noqa: ANN401
|
||||
if isinstance(val, cls):
|
||||
return val
|
||||
elif isinstance(val, dict):
|
||||
@@ -47,10 +47,10 @@ def ensure(cls: Type[T]) -> Callable[[Any], T]:
|
||||
return converter
|
||||
|
||||
|
||||
def ensure_list(cls: Type[T]) -> Callable[[List[Dict[str, Any]]], Type[T]]:
|
||||
def ensure_list(cls: type[T]) -> Callable[[list[dict[str, any]]], type[T]]:
|
||||
"""Convert a list of dictionaries to class instances"""
|
||||
|
||||
def converter(val: List[Dict[str, Any]]) -> List[T]:
|
||||
def converter(val: list[dict[str, any]]) -> list[T]:
|
||||
output = []
|
||||
for entry in val:
|
||||
output.append(ensure(cls)(entry))
|
||||
|
||||
@@ -2,7 +2,7 @@ import glob
|
||||
import os
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def create_extensions_list(project_root: str, max_n: int) -> list:
|
||||
@@ -11,7 +11,7 @@ def create_extensions_list(project_root: str, max_n: int) -> list:
|
||||
project_root (str): Root of the project to analyze
|
||||
max_n (int): The number of file extensions to return
|
||||
Returns:
|
||||
extensions (List[str]): A list of the top N file extensions
|
||||
extensions (list[str]): A list of the top N file extensions
|
||||
"""
|
||||
if max_n == 0:
|
||||
raise (ValueError("Number of file extensions must be greater than 0"))
|
||||
@@ -31,14 +31,14 @@ def create_extensions_list(project_root: str, max_n: int) -> list:
|
||||
return extensions
|
||||
|
||||
|
||||
def create_language_weighting(files_in_directory: List[str]) -> Dict[str, float]:
|
||||
def create_language_weighting(files_in_directory: list[str]) -> dict[str, float]:
|
||||
"""Calculate language weighting by file size to match GitHub's methodology.
|
||||
|
||||
Args:
|
||||
files_in_directory (List[str]): Paths to files in the project directory
|
||||
files_in_directory (list[str]): Paths to files in the project directory
|
||||
|
||||
Returns:
|
||||
Dict[str, float]: A dictionary with languages as keys and their percentage of the total codebase as values
|
||||
dict[str, float]: A dictionary with languages as keys and their percentage of the total codebase as values
|
||||
"""
|
||||
|
||||
# Initialize counters for sizes
|
||||
@@ -59,7 +59,7 @@ def create_language_weighting(files_in_directory: List[str]) -> Dict[str, float]
|
||||
return dict(sorted(language_percentages.items(), key=lambda item: item[1], reverse=True))
|
||||
|
||||
|
||||
def list_files_with_extension(dir_path: str, extension: Optional[str] = "") -> List[str]:
|
||||
def list_files_with_extension(dir_path: str, extension: Optional[str] = "") -> list[str]:
|
||||
"""List all files in a directory with a given extension. Set extension to '' to return all files.
|
||||
|
||||
Args:
|
||||
@@ -67,7 +67,7 @@ def list_files_with_extension(dir_path: str, extension: Optional[str] = "") -> L
|
||||
extension (Optional[str]): extension to lookup. Defaults to '' which will return all files.
|
||||
|
||||
Returns:
|
||||
files (List[str]): List of file paths
|
||||
files (list[str]): list of file paths
|
||||
"""
|
||||
# add a leading '.' to extension if needed
|
||||
if extension and not extension.startswith("."):
|
||||
@@ -77,15 +77,15 @@ def list_files_with_extension(dir_path: str, extension: Optional[str] = "") -> L
|
||||
return files
|
||||
|
||||
|
||||
def create_file_list(dir_path: str, extensions: List[str]) -> List[str]:
|
||||
def create_file_list(dir_path: str, extensions: list[str]) -> list[str]:
|
||||
"""Creates a list of files with certain extensions
|
||||
|
||||
Args:
|
||||
dir_path (str): Directory to list files of. Will include files recursively in sub-directories.
|
||||
extensions (List[str]): List of file extensions to select for. If empty list, return all files
|
||||
extensions (list[str]): list of file extensions to select for. If empty list, return all files
|
||||
|
||||
Returns:
|
||||
final_file_list (List[str]): List of file paths with specified extensions.
|
||||
final_file_list (list[str]): list of file paths with specified extensions.
|
||||
"""
|
||||
# if extensions is empty list, return all files
|
||||
if not extensions:
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterator, List
|
||||
from typing import Iterator
|
||||
|
||||
from exchange import Message
|
||||
|
||||
@@ -17,12 +17,12 @@ def is_empty_session(path: Path) -> bool:
|
||||
return path.is_file() and path.stat().st_size == 0
|
||||
|
||||
|
||||
def write_to_file(file_path: Path, messages: List[Message]) -> None:
|
||||
def write_to_file(file_path: Path, messages: list[Message]) -> None:
|
||||
with open(file_path, "w") as f:
|
||||
_write_messages_to_file(f, messages)
|
||||
|
||||
|
||||
def read_or_create_file(file_path: Path) -> List[Message]:
|
||||
def read_or_create_file(file_path: Path) -> list[Message]:
|
||||
if file_path.exists():
|
||||
return read_from_file(file_path)
|
||||
with open(file_path, "w"):
|
||||
@@ -30,7 +30,7 @@ def read_or_create_file(file_path: Path) -> List[Message]:
|
||||
return []
|
||||
|
||||
|
||||
def read_from_file(file_path: Path) -> List[Message]:
|
||||
def read_from_file(file_path: Path) -> list[Message]:
|
||||
try:
|
||||
with open(file_path, "r") as f:
|
||||
messages = [json.loads(m) for m in list(f) if m.strip()]
|
||||
@@ -40,7 +40,7 @@ def read_from_file(file_path: Path) -> List[Message]:
|
||||
return [Message(**m) for m in messages]
|
||||
|
||||
|
||||
def list_sorted_session_files(session_files_directory: Path) -> Dict[str, Path]:
|
||||
def list_sorted_session_files(session_files_directory: Path) -> dict[str, Path]:
|
||||
logs = list_session_files(session_files_directory)
|
||||
return {log.stem: log for log in sorted(logs, key=lambda x: x.stat().st_mtime, reverse=True)}
|
||||
|
||||
@@ -55,7 +55,7 @@ def session_file_exists(session_files_directory: Path) -> bool:
|
||||
return any(list_session_files(session_files_directory))
|
||||
|
||||
|
||||
def save_latest_session(file_path: Path, messages: List[Message]) -> None:
|
||||
def save_latest_session(file_path: Path, messages: list[Message]) -> None:
|
||||
with tempfile.NamedTemporaryFile("w", delete=False) as temp_file:
|
||||
_write_messages_to_file(temp_file, messages)
|
||||
temp_file_path = temp_file.name
|
||||
@@ -63,7 +63,7 @@ def save_latest_session(file_path: Path, messages: List[Message]) -> None:
|
||||
os.replace(temp_file_path, file_path)
|
||||
|
||||
|
||||
def _write_messages_to_file(file: any, messages: List[Message]) -> None:
|
||||
def _write_messages_to_file(file: any, messages: list[Message]) -> None:
|
||||
for m in messages:
|
||||
json.dump(m.to_dict(), file)
|
||||
file.write("\n")
|
||||
|
||||
Reference in New Issue
Block a user