Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Commit e16a97e

Browse files
authored
Merge branch 'main' into redacting
2 parents 00b0103 + 619fc3d commit e16a97e

File tree

13 files changed

+291
-71
lines changed

13 files changed

+291
-71
lines changed

.github/workflows/image-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Checkout
2424
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
2525
- name: Set up Docker Buildx
26-
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
26+
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3
2727
- name: Download artifact
2828
id: download-artifact
2929
uses: dawidd6/action-download-artifact@20319c5641d495c8a52e688b7dc5fada6c3a9fbc # v8

.github/workflows/image-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ jobs:
2222
- name: Checkout
2323
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
2424
- name: Set up QEMU for cross-platform builds
25-
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3
25+
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3
2626
- name: Set up Docker Buildx
27-
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3
27+
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3
2828
- name: Compute version number
2929
id: version-string
3030
run: |

api/openapi.json

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,14 +1145,7 @@
11451145
"default": ""
11461146
},
11471147
"auth_type": {
1148-
"anyOf": [
1149-
{
1150-
"$ref": "#/components/schemas/ProviderAuthType"
1151-
},
1152-
{
1153-
"type": "null"
1154-
}
1155-
],
1148+
"$ref": "#/components/schemas/ProviderAuthType",
11561149
"default": "none"
11571150
},
11581151
"api_key": {
@@ -1175,6 +1168,74 @@
11751168
"title": "AddProviderEndpointRequest",
11761169
"description": "Represents a request to add a provider endpoint."
11771170
},
1171+
"Alert": {
1172+
"properties": {
1173+
"id": {
1174+
"type": "string",
1175+
"title": "Id"
1176+
},
1177+
"prompt_id": {
1178+
"type": "string",
1179+
"title": "Prompt Id"
1180+
},
1181+
"code_snippet": {
1182+
"anyOf": [
1183+
{
1184+
"$ref": "#/components/schemas/CodeSnippet"
1185+
},
1186+
{
1187+
"type": "null"
1188+
}
1189+
]
1190+
},
1191+
"trigger_string": {
1192+
"anyOf": [
1193+
{
1194+
"type": "string"
1195+
},
1196+
{
1197+
"type": "object"
1198+
},
1199+
{
1200+
"type": "null"
1201+
}
1202+
],
1203+
"title": "Trigger String"
1204+
},
1205+
"trigger_type": {
1206+
"type": "string",
1207+
"title": "Trigger Type"
1208+
},
1209+
"trigger_category": {
1210+
"anyOf": [
1211+
{
1212+
"type": "string"
1213+
},
1214+
{
1215+
"type": "null"
1216+
}
1217+
],
1218+
"title": "Trigger Category"
1219+
},
1220+
"timestamp": {
1221+
"type": "string",
1222+
"format": "date-time",
1223+
"title": "Timestamp"
1224+
}
1225+
},
1226+
"type": "object",
1227+
"required": [
1228+
"id",
1229+
"prompt_id",
1230+
"code_snippet",
1231+
"trigger_string",
1232+
"trigger_type",
1233+
"trigger_category",
1234+
"timestamp"
1235+
],
1236+
"title": "Alert",
1237+
"description": "Represents an alert."
1238+
},
11781239
"AlertConversation": {
11791240
"properties": {
11801241
"conversation": {
@@ -1389,6 +1450,14 @@
13891450
"type": "null"
13901451
}
13911452
]
1453+
},
1454+
"alerts": {
1455+
"items": {
1456+
"$ref": "#/components/schemas/Alert"
1457+
},
1458+
"type": "array",
1459+
"title": "Alerts",
1460+
"default": []
13921461
}
13931462
},
13941463
"type": "object",
@@ -1593,14 +1662,7 @@
15931662
"default": ""
15941663
},
15951664
"auth_type": {
1596-
"anyOf": [
1597-
{
1598-
"$ref": "#/components/schemas/ProviderAuthType"
1599-
},
1600-
{
1601-
"type": "null"
1602-
}
1603-
],
1665+
"$ref": "#/components/schemas/ProviderAuthType",
16041666
"default": "none"
16051667
}
16061668
},
@@ -1621,7 +1683,7 @@
16211683
"ollama",
16221684
"lm_studio",
16231685
"llamacpp",
1624-
"openai"
1686+
"openrouter"
16251687
],
16261688
"title": "ProviderType",
16271689
"description": "Represents the different types of providers we support."

poetry.lock

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ PyYAML = "==6.0.2"
1212
fastapi = "==0.115.8"
1313
uvicorn = "==0.34.0"
1414
structlog = "==25.1.0"
15-
litellm = "==1.60.4"
15+
litellm = "==1.60.5"
1616
llama_cpp_python = "==0.3.5"
1717
cryptography = "==44.0.0"
1818
sqlalchemy = "==2.0.37"
@@ -37,11 +37,11 @@ legacy-cgi = "==2.6.2"
3737
pytest = "==8.3.4"
3838
pytest-cov = "==6.0.0"
3939
black = "==25.1.0"
40-
ruff = "==0.9.4"
40+
ruff = "==0.9.5"
4141
bandit = "==1.8.2"
4242
build = "==1.2.2.post1"
4343
wheel = "==0.45.1"
44-
litellm = "==1.60.4"
44+
litellm = "==1.60.5"
4545
pytest-asyncio = "==0.25.3"
4646
llama_cpp_python = "==0.3.5"
4747
scikit-learn = "==1.6.1"

src/codegate/api/v1.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ async def add_provider_endpoint(
123123
status_code=400,
124124
detail=str(e),
125125
)
126+
except provendcrud.ProviderModelsNotFoundError:
127+
raise HTTPException(status_code=401, detail="Provider models could not be found")
128+
except provendcrud.ProviderInvalidAuthConfigError:
129+
raise HTTPException(status_code=400, detail="Invalid auth configuration")
126130
except ValidationError as e:
127131
# TODO: This should be more specific
128132
raise HTTPException(
@@ -151,6 +155,10 @@ async def configure_auth_material(
151155
await pcrud.configure_auth_material(provider_id, request)
152156
except provendcrud.ProviderNotFoundError:
153157
raise HTTPException(status_code=404, detail="Provider endpoint not found")
158+
except provendcrud.ProviderModelsNotFoundError:
159+
raise HTTPException(status_code=401, detail="Provider models could not be found")
160+
except provendcrud.ProviderInvalidAuthConfigError:
161+
raise HTTPException(status_code=400, detail="Invalid auth configuration")
154162
except Exception:
155163
raise HTTPException(status_code=500, detail="Internal server error")
156164

@@ -405,8 +413,12 @@ async def get_workspace_messages(workspace_name: str) -> List[v1_models.Conversa
405413
raise HTTPException(status_code=500, detail="Internal server error")
406414

407415
try:
408-
prompts_outputs = await dbreader.get_prompts_with_output(ws.id)
409-
conversations, _ = await v1_processing.parse_messages_in_conversations(prompts_outputs)
416+
prompts_with_output_alerts_usage = (
417+
await dbreader.get_prompts_with_output_alerts_usage_by_workspace_id(ws.id)
418+
)
419+
conversations, _ = await v1_processing.parse_messages_in_conversations(
420+
prompts_with_output_alerts_usage
421+
)
410422
return conversations
411423
except Exception:
412424
logger.exception("Error while getting messages")

src/codegate/api/v1_models.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,32 @@ def add_model_token_usage(self, model_token_usage: TokenUsageByModel) -> None:
147147
self.token_usage += model_token_usage.token_usage
148148

149149

150+
class Alert(pydantic.BaseModel):
151+
"""
152+
Represents an alert.
153+
"""
154+
155+
@staticmethod
156+
def from_db_model(db_model: db_models.Alert) -> "Alert":
157+
return Alert(
158+
id=db_model.id,
159+
prompt_id=db_model.prompt_id,
160+
code_snippet=db_model.code_snippet,
161+
trigger_string=db_model.trigger_string,
162+
trigger_type=db_model.trigger_type,
163+
trigger_category=db_model.trigger_category,
164+
timestamp=db_model.timestamp,
165+
)
166+
167+
id: str
168+
prompt_id: str
169+
code_snippet: Optional[CodeSnippet]
170+
trigger_string: Optional[Union[str, dict]]
171+
trigger_type: str
172+
trigger_category: Optional[str]
173+
timestamp: datetime.datetime
174+
175+
150176
class PartialQuestionAnswer(pydantic.BaseModel):
151177
"""
152178
Represents a partial conversation.
@@ -155,6 +181,7 @@ class PartialQuestionAnswer(pydantic.BaseModel):
155181
partial_questions: PartialQuestions
156182
answer: Optional[ChatMessage]
157183
model_token_usage: TokenUsageByModel
184+
alerts: List[Alert] = []
158185

159186

160187
class Conversation(pydantic.BaseModel):
@@ -168,6 +195,7 @@ class Conversation(pydantic.BaseModel):
168195
chat_id: str
169196
conversation_timestamp: datetime.datetime
170197
token_usage_agg: Optional[TokenUsageAggregate]
198+
alerts: List[Alert] = []
171199

172200

173201
class AlertConversation(pydantic.BaseModel):
@@ -210,7 +238,7 @@ class ProviderEndpoint(pydantic.BaseModel):
210238
description: str = ""
211239
provider_type: db_models.ProviderType
212240
endpoint: str = "" # Some providers have defaults we can leverage
213-
auth_type: Optional[ProviderAuthType] = ProviderAuthType.none
241+
auth_type: ProviderAuthType = ProviderAuthType.none
214242

215243
@staticmethod
216244
def from_db_model(db_model: db_models.ProviderEndpoint) -> "ProviderEndpoint":

src/codegate/api/v1_processing.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import requests
99
import structlog
1010

11+
from codegate.api import v1_models
1112
from codegate.api.v1_models import (
1213
AlertConversation,
1314
ChatMessage,
@@ -200,10 +201,15 @@ async def _get_partial_question_answer(
200201
model=model, token_usage=token_usage, provider_type=provider
201202
)
202203

204+
alerts: List[v1_models.Alert] = [
205+
v1_models.Alert.from_db_model(db_alert) for db_alert in row.alerts
206+
]
207+
203208
return PartialQuestionAnswer(
204209
partial_questions=request_message,
205210
answer=output_message,
206211
model_token_usage=model_token_usage,
212+
alerts=alerts,
207213
)
208214

209215

@@ -367,6 +373,7 @@ async def match_conversations(
367373
for group in grouped_partial_questions:
368374
questions_answers: List[QuestionAnswer] = []
369375
token_usage_agg = TokenUsageAggregate(tokens_by_model={}, token_usage=TokenUsage())
376+
alerts: List[v1_models.Alert] = []
370377
first_partial_qa = None
371378
for partial_question in sorted(group, key=lambda x: x.timestamp):
372379
# Partial questions don't contain the answer, so we need to find the corresponding
@@ -385,6 +392,7 @@ async def match_conversations(
385392
qa = _get_question_answer_from_partial(selected_partial_qa)
386393
qa.question.message = parse_question_answer(qa.question.message)
387394
questions_answers.append(qa)
395+
alerts.extend(selected_partial_qa.alerts)
388396
token_usage_agg.add_model_token_usage(selected_partial_qa.model_token_usage)
389397

390398
# only add conversation if we have some answers
@@ -398,6 +406,7 @@ async def match_conversations(
398406
chat_id=first_partial_qa.partial_questions.message_id,
399407
conversation_timestamp=first_partial_qa.partial_questions.timestamp,
400408
token_usage_agg=token_usage_agg,
409+
alerts=alerts,
401410
)
402411
for qa in questions_answers:
403412
map_q_id_to_conversation[qa.question.message_id] = conversation

0 commit comments

Comments
 (0)