Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@

## Highlights

* Concurrent editing. Continue editing while the assistant runs, without any
* Concurrent edits. Continue editing while the assistant runs, without any
risks of interference.


## Ideas

* Add a compatibility OpenAI bot version which does not use threads, so that it
can be used with tools only. Gemini only supports the latter.
* Customizable prompt templates
* Extensible bot API
6 changes: 2 additions & 4 deletions src/git_draft/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,13 @@ def main() -> None:
)
command = getattr(opts, "command", "generate")
if command == "generate":
if not config.bots:
raise ValueError("No bots configured")

bot_config = None
if opts.bot:
bot_configs = [c for c in config.bots if c.name == opts.bot]
if len(bot_configs) != 1:
raise ValueError(f"Found {len(bot_configs)} matching bots")
bot_config = bot_configs[0]
else:
elif config.bots:
bot_config = config.bots[0]
bot = load_bot(bot_config)

Expand Down
51 changes: 36 additions & 15 deletions src/git_draft/bots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"""

import importlib
import os
import sys

from ..common import BotConfig
from ..common import BotConfig, reindent
from .common import Action, Bot, Goal, Operation, OperationHook, Toolbox

__all__ = [
Expand All @@ -19,20 +20,11 @@
]


def load_bot(config: BotConfig) -> Bot:
"""Load and return a Bot instance using the provided configuration.
def load_bot(config: BotConfig | None) -> Bot:
"""Load and return a Bot instance using the provided configuration"""
if not config:
return _default_bot()

If a pythonpath is specified in the config and not already present in
sys.path, it is added. The function expects the config.factory in the
format 'module:symbol' or 'symbol'. If only 'symbol' is provided, the
current module is used.

Args:
config: BotConfig object containing bot configuration details.

Raises:
NotImplementedError: If the specified factory cannot be found.
"""
if config.pythonpath and config.pythonpath not in sys.path:
sys.path.insert(0, config.pythonpath)

Expand All @@ -44,7 +36,36 @@ def load_bot(config: BotConfig) -> Bot:

factory = getattr(module, symbol, None)
if not factory:
raise NotImplementedError(f"Unknown bot factory: {factory}")
raise NotImplementedError(f"Unknown bot factory: {config.factory}")

kwargs = config.config or {}
return factory(**kwargs)


def _default_bot() -> Bot:
if not os.environ.get("OPENAI_API_KEY"):
raise RuntimeError(
reindent(
"""
The default bot implementation requires an OpenAI API key.
Please specify one via the `$OPENAI_API_KEY` environment
variable or enable a different bot in your configuration.
"""
)
)

try:
from .openai import threads_bot

except ImportError:
raise RuntimeError(
reindent(
"""
The default bot implementation requires the `openai` Python
package. Please install it or specify a different bot in
your configuration.
"""
)
)
else:
return threads_bot()
Loading