From 70cb1ec5d876ca0d6cbdd5be98824ec6ccc20590 Mon Sep 17 00:00:00 2001 From: Yolanda Robla Date: Fri, 10 Jan 2025 11:23:48 +0100 Subject: [PATCH 1/4] feat: add support for aider Aider offers two types of integrations: - compatible OPENAI API - local ollama Add support for those 2 integrations, and correct all different nuances that we are getting with this new engine Closes: #440 --- .gitignore | 1 + src/codegate/pipeline/base.py | 8 +++++--- .../pipeline/codegate_context_retriever/codegate.py | 1 - src/codegate/pipeline/output.py | 2 ++ src/codegate/pipeline/secrets/secrets.py | 13 +++++++++---- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 689157b4..4cc79a6a 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ sqlite_data/vectordb.db # certificate directory *certs/ +.aider* diff --git a/src/codegate/pipeline/base.py b/src/codegate/pipeline/base.py index 9ac86d96..59c73981 100644 --- a/src/codegate/pipeline/base.py +++ b/src/codegate/pipeline/base.py @@ -253,9 +253,11 @@ def get_latest_user_messages(request: ChatCompletionRequest) -> str: for message in reversed(request.get("messages", [])): if message["role"] == "user": - latest_user_messages += "\n" + message["content"] - else: - break + # if found we can stop here, if not we continue until we find it + message_str = message.get("content", "") + if message_str: + latest_user_messages += "\n" + str(message_str) + break return latest_user_messages diff --git a/src/codegate/pipeline/codegate_context_retriever/codegate.py b/src/codegate/pipeline/codegate_context_retriever/codegate.py index d5b33faf..b163a215 100644 --- a/src/codegate/pipeline/codegate_context_retriever/codegate.py +++ b/src/codegate/pipeline/codegate_context_retriever/codegate.py @@ -59,7 +59,6 @@ async def process( """ Use RAG DB to add context to the user request """ - # Get the latest user messages user_messages = self.get_latest_user_messages(request) diff --git a/src/codegate/pipeline/output.py b/src/codegate/pipeline/output.py index 43525db6..89c31c59 100644 --- a/src/codegate/pipeline/output.py +++ b/src/codegate/pipeline/output.py @@ -27,6 +27,8 @@ class OutputPipelineContext: snippets: List[CodeSnippet] = field(default_factory=list) # Store all content that has been processed by the pipeline processed_content: List[str] = field(default_factory=list) + # partial buffer to store prefixes + prefix_buffer: str = "" class OutputPipelineStep(ABC): diff --git a/src/codegate/pipeline/secrets/secrets.py b/src/codegate/pipeline/secrets/secrets.py index 0845c0f6..33ab8503 100644 --- a/src/codegate/pipeline/secrets/secrets.py +++ b/src/codegate/pipeline/secrets/secrets.py @@ -280,7 +280,7 @@ async def process( if "content" in message and message["content"]: # Protect the text protected_string, redacted_count = self._redact_text( - message["content"], secrets_manager, session_id, context + str(message["content"]), secrets_manager, session_id, context ) new_request["messages"][i]["content"] = protected_string @@ -389,12 +389,17 @@ async def process_chunk( return [chunk] # If we have a partial marker at the end, keep buffering - if self.marker_start in buffered_content or self._is_partial_marker_prefix( - buffered_content - ): + if self.marker_start in buffered_content: + context.prefix_buffer = "" + return [] + + if self._is_partial_marker_prefix(buffered_content): + context.prefix_buffer += buffered_content return [] # No markers or partial markers, let pipeline handle the chunk normally + chunk.choices[0].delta.content = context.prefix_buffer + chunk.choices[0].delta.content + context.prefix_buffer = "" return [chunk] From 59b693d98f74cd9a2d9124ba48e38741c9205eed Mon Sep 17 00:00:00 2001 From: Yolanda Robla Date: Fri, 10 Jan 2025 11:35:10 +0100 Subject: [PATCH 2/4] add readme --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 56361880..d06ae282 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,16 @@ With Continue, you can choose from several leading AI model providers: 🔮 Many more on the way! +- **[Aider](https://aider.chat) + +With Aider, you can choose from two leading AI model providers: + +- 💻 Local LLMs with [Ollama](https://ollama.com/) and + [llama.cpp](https://github.com/ggerganov/llama.cpp) (run AI completely + offline!) +- 🧠 [OpenAI API](https://openai.com/api/) + + ### Privacy first Unlike E.T., your code never phones home! 🛸 CodeGate is designed with privacy @@ -83,6 +93,8 @@ Check out the quickstart guides to get up and running quickly! - [Quickstart guide for GitHub Copilot with VS Code](https://docs.codegate.ai/quickstart) - [Quickstart guide for Continue with VS Code and Ollama](https://docs.codegate.ai/quickstart-continue) +- [Quickstart guide for Aider with Open AI and Ollama](https://docs.codegate.ai/quickstart-aider) + ## 🎯 Usage From e1f797b939aa5189ab877348b1552d1bdd93abea Mon Sep 17 00:00:00 2001 From: Yolanda Robla Date: Fri, 10 Jan 2025 13:51:45 +0100 Subject: [PATCH 3/4] add missing endpoints --- src/codegate/providers/ollama/provider.py | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/codegate/providers/ollama/provider.py b/src/codegate/providers/ollama/provider.py index dc64baec..f8e901d4 100644 --- a/src/codegate/providers/ollama/provider.py +++ b/src/codegate/providers/ollama/provider.py @@ -45,6 +45,32 @@ def _setup_routes(self): """ Sets up Ollama API routes. """ + @self.router.get(f"/{self.provider_route_name}/api/tags") + async def get_tags(request: Request): + """ + Special route for /api/tags that responds outside of the pipeline + Tags are used to get the list of models + https://github.com/ollama/ollama/blob/main/docs/api.md#list-local-models + """ + async with httpx.AsyncClient() as client: + response = await client.get(f"{self.base_url}/api/tags") + return response.json() + + @self.router.post(f"/{self.provider_route_name}/api/show") + async def show_model(request: Request): + """ + route for /api/show that responds outside of the pipeline + /api/show displays model is used to get the model information + https://github.com/ollama/ollama/blob/main/docs/api.md#show-model-information + """ + body = await request.body() + async with httpx.AsyncClient() as client: + response = await client.post( + f"{self.base_url}/api/show", + content=body, + headers={"Content-Type": "application/json"}, + ) + return response.json() # Native Ollama API routes @self.router.post(f"/{self.provider_route_name}/api/chat") From a22ea5ff1b57fcb99d6366c506a35797450cd106 Mon Sep 17 00:00:00 2001 From: Yolanda Robla Date: Fri, 10 Jan 2025 16:33:15 +0100 Subject: [PATCH 4/4] modifications from review --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index d06ae282..a0ace02b 100644 --- a/README.md +++ b/README.md @@ -71,9 +71,7 @@ With Continue, you can choose from several leading AI model providers: With Aider, you can choose from two leading AI model providers: -- 💻 Local LLMs with [Ollama](https://ollama.com/) and - [llama.cpp](https://github.com/ggerganov/llama.cpp) (run AI completely - offline!) +- 💻 Local LLMs with [Ollama](https://ollama.com/) - 🧠 [OpenAI API](https://openai.com/api/) @@ -93,7 +91,6 @@ Check out the quickstart guides to get up and running quickly! - [Quickstart guide for GitHub Copilot with VS Code](https://docs.codegate.ai/quickstart) - [Quickstart guide for Continue with VS Code and Ollama](https://docs.codegate.ai/quickstart-continue) -- [Quickstart guide for Aider with Open AI and Ollama](https://docs.codegate.ai/quickstart-aider) ## 🎯 Usage