From 1cd5162ccd00863d419f9a80baec02eda3db3c19 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 19 Feb 2025 14:37:24 +0100 Subject: [PATCH 1/2] Fix copilot secret unredaction The copilot provider always sends `cleanup_sensitive` set to `False` as it manages the context itself. On streams where `finish_stream` was set to `False` as well, we would have yielded the rest of the context buffer though which would break secret unredaction. To reproduce, ask Copilot to make a simple modification in a file containing secrets so that it's forced to print the secrets back to you. --- src/codegate/pipeline/output.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/codegate/pipeline/output.py b/src/codegate/pipeline/output.py index 4f0706c2..b7ce419b 100644 --- a/src/codegate/pipeline/output.py +++ b/src/codegate/pipeline/output.py @@ -169,8 +169,9 @@ async def process_stream( finally: # NOTE: Don't use await in finally block, it will break the stream # Don't flush the buffer if we assume we'll call the pipeline again - if cleanup_sensitive is False and finish_stream: - self._record_to_db() + if cleanup_sensitive is False: + if finish_stream: + self._record_to_db() return # TODO figure out what's the logic here. From 26ac21453c46c5b8bb46b2397c96933c20ca74cb Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 19 Feb 2025 13:55:42 +0100 Subject: [PATCH 2/2] Port recent copilot change to the new chunk API --- src/codegate/providers/copilot/provider.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/codegate/providers/copilot/provider.py b/src/codegate/providers/copilot/provider.py index b1b944ed..e5787efc 100644 --- a/src/codegate/providers/copilot/provider.py +++ b/src/codegate/providers/copilot/provider.py @@ -871,16 +871,15 @@ async def stream_iterator(): while not self.stream_queue.empty(): incoming_record = await self.stream_queue.get() for choice in incoming_record.choices: - if choice.finish_reason and \ - choice.finish_reason in ["stop", "length", "content_filter", "tool_calls"]: + if choice.finish_reason and choice.finish_reason is not None: self.finish_stream = True yield incoming_record # needs to be set as the flag gets reset on finish_data finish_stream_flag = any( - choice.get("finish_reason") == "stop" + choice.finish_reason is not None for record in list(self.stream_queue._queue) - for choice in record.get("content", {}).get("choices", []) + for choice in record.choices ) async for record in self.output_pipeline_instance.process_stream( stream_iterator(),