Skip to content

Commit

Permalink
Merge branch 'main' into enhancements/observability
Browse files Browse the repository at this point in the history
  • Loading branch information
bekossy committed May 15, 2024
2 parents 0210178 + 4f4fc88 commit 8556703
Show file tree
Hide file tree
Showing 127 changed files with 755 additions and 543 deletions.
9 changes: 9 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,15 @@
"contributions": [
"code"
]
},
{
"login": "youcefs21",
"name": "Youcef Boumar",
"avatar_url": "https://avatars.githubusercontent.com/u/34604972?v=4",
"profile": "https://github.com/youcefs21",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7,
Expand Down
35 changes: 35 additions & 0 deletions .github/images/we-are-hiring.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<div align="center" style="margin: 30px">
<div>
<a href="https://agentaai.notion.site/Careers-at-agenta-fb8a76d4d9044e27bd3a32678818dbc8/">
<img src="https://github.com/Agenta-AI/agenta/raw/main/.github/images/we-are-hiring.svg" alt="We are hiring! Join our team!" width="350" height="60" alt="We are hiring! Join our team!" width="350" height="60">
</a>
</div>
<a href="https://agenta.ai/">
<div align="center" >
<picture >
Expand Down Expand Up @@ -148,6 +153,11 @@ To disable anonymized telemetry, follow these steps:

After making this change, restart Agenta Compose.

# ⭐️ Join Our Team
- [Founding Lead Software Engineer Backend](https://agentaai.notion.site/Founding-Lead-Software-Engineer-Backend-d70bfefed6d543778bc4aa38b543a678)
- [Founding Product Engineer Frontend](https://agentaai.notion.site/Founding-Product-Engineer-Frontend-b6d26a3e9b254be6b6c2bfffbf0b53c5)
- [Founding Product Designer](https://agentaai.notion.site/Founding-Product-Designer-96b1e760ff0241fd96632578d533a778)

# Contributing

We warmly welcome contributions to Agenta. Feel free to submit issues, fork the repository, and send pull requests.
Expand All @@ -159,7 +169,7 @@ Check out our [Contributing Guide](https://docs.agenta.ai/contributing/getting-s
## Contributors ✨

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-43-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-44-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
Expand Down Expand Up @@ -225,6 +235,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vishalvanpariya"><img src="https://avatars.githubusercontent.com/u/27823328?v=4?s=100" width="100px;" alt="Vishal Vanpariya"/><br /><sub><b>Vishal Vanpariya</b></sub></a><br /><a href="https://github.com/Agenta-AI/agenta/commits?author=vishalvanpariya" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/youcefs21"><img src="https://avatars.githubusercontent.com/u/34604972?v=4?s=100" width="100px;" alt="Youcef Boumar"/><br /><sub><b>Youcef Boumar</b></sub></a><br /><a href="https://github.com/Agenta-AI/agenta/commits?author=youcefs21" title="Documentation">📖</a></td>
</tr>
</tbody>
</table>
Expand Down
15 changes: 15 additions & 0 deletions agenta-backend/agenta_backend/routers/variants_router.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import inspect
import logging
from typing import Any, Optional, Union, List

Expand All @@ -24,11 +25,13 @@
Image_ as Image,
AppVariantResponse_ as AppVariantResponse,
)
from agenta_backend.cloud.services import logs_manager
else:
from agenta_backend.models.api.api_models import (
Image,
AppVariantResponse,
)
from agenta_backend.services import logs_manager

from agenta_backend.models.api.api_models import (
URI,
Expand Down Expand Up @@ -312,6 +315,18 @@ async def start_variant(
return url


@router.get("/{variant_id}/logs/", operation_id="retrieve_variant_logs")
async def retrieve_variant_logs(variant_id: str, request: Request):
try:
app_variant = await db_manager.fetch_app_variant_by_id(variant_id)
deployment = await db_manager.get_deployment_by_appid(str(app_variant.app.id))
logs_result = await logs_manager.retrieve_logs(deployment.container_id)
return logs_result
except Exception as exc:
logger.exception(f"An error occurred: {str(exc)}")
raise HTTPException(500, {"message": str(exc)})


@router.get(
"/{variant_id}/",
operation_id="get_variant",
Expand Down
24 changes: 15 additions & 9 deletions agenta-backend/agenta_backend/services/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -994,17 +994,15 @@ async def check_is_last_variant_for_image(db_app_variant: AppVariantDB) -> bool:
true if it's the last variant, false otherwise
"""

query_expression = {"base.id": db_app_variant.base.id}
query = AppVariantDB.find(AppVariantDB.base.id == ObjectId(db_app_variant.base.id))

if isCloudEE():
query_expression.update(
{
"organization.id": db_app_variant.organization.id,
"workspace.id": db_app_variant.workspace.id,
}
query = query.find(
AppVariantDB.organization.id == db_app_variant.organization.id,
AppVariantDB.workspace.id == db_app_variant.workspace.id,
)

count_variants = await AppVariantDB.find(query_expression).count()
count_variants = await query.count()
return count_variants == 1


Expand All @@ -1017,7 +1015,10 @@ async def remove_deployment(deployment_db: DeploymentDB):
logger.debug("Removing deployment")
assert deployment_db is not None, "deployment_db is missing"

await deployment_db.delete()
deployment = await DeploymentDB.find_one(
DeploymentDB.id == ObjectId(deployment_db.id)
)
await deployment.delete()


async def remove_app_variant_from_db(app_variant_db: AppVariantDB):
Expand All @@ -1041,7 +1042,10 @@ async def remove_app_variant_from_db(app_variant_db: AppVariantDB):
for app_variant_revision in app_variant_revisions:
await app_variant_revision.delete()

await app_variant_db.delete()
app_variant = await AppVariantDB.find_one(
AppVariantDB.id == ObjectId(app_variant_db.id)
)
await app_variant.delete()


async def deploy_to_environment(
Expand Down Expand Up @@ -1376,6 +1380,8 @@ async def remove_image(image: ImageDB):
"""
if image is None:
raise ValueError("Image is None")

image = await ImageDB.find_one(ImageDB.id == ObjectId(image.id))
await image.delete()


Expand Down
68 changes: 38 additions & 30 deletions agenta-backend/agenta_backend/services/llm_apps_service.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import json
import logging
import asyncio
import traceback
import aiohttp
from typing import Any, Dict, List


from agenta_backend.models.db_models import InvokationResult, Result, Error
from agenta_backend.utils import common

# Set logger
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -96,37 +98,40 @@ async def invoke_app(
)

except aiohttp.ClientResponseError as e:
# Parse error details from the API response
error_message = "Error in invoking the LLM App:"
try:
error_message = e.message
except ValueError:
# Fallback if the error response is not JSON or doesn't have the expected structure
logger.error(f"Failed to parse error response: {e}")

logger.error(f"Error occurred during request: {error_message}")
return InvokationResult(
result=Result(
type="error",
error=Error(
message=f"{e.code}: {error_message}",
stacktrace=str(e),
),
)
)

error_message = f"HTTP error {e.status}: {e.message}"
stacktrace = "".join(traceback.format_exception_only(type(e), e))
logger.error(f"HTTP error occurred during request: {error_message}")
common.capture_exception_in_sentry(e)
except aiohttp.ServerTimeoutError as e:
error_message = "Request timed out"
stacktrace = "".join(traceback.format_exception_only(type(e), e))
logger.error(error_message)
common.capture_exception_in_sentry(e)
except aiohttp.ClientConnectionError as e:
error_message = f"Connection error: {str(e)}"
stacktrace = "".join(traceback.format_exception_only(type(e), e))
logger.error(error_message)
common.capture_exception_in_sentry(e)
except json.JSONDecodeError as e:
error_message = "Failed to decode JSON from response"
stacktrace = "".join(traceback.format_exception_only(type(e), e))
logger.error(error_message)
common.capture_exception_in_sentry(e)
except Exception as e:
# Catch-all for any other unexpected errors
logger.error(f"Unexpected error: {e}")
return InvokationResult(
result=Result(
type="error",
error=Error(
message="Unexpected error while invoking the LLM App",
stacktrace=str(e),
),
)
error_message = f"Unexpected error: {str(e)}"
stacktrace = "".join(traceback.format_exception_only(type(e), e))
logger.error(error_message)
common.capture_exception_in_sentry(e)

return InvokationResult(
result=Result(
type="error",
error=Error(
message=error_message,
stacktrace=stacktrace,
),
)
)


async def run_with_retry(
Expand Down Expand Up @@ -165,10 +170,13 @@ async def run_with_retry(
retries += 1
except Exception as e:
last_exception = e
logger.info(f"Error processing datapoint: {input_data}")
logger.info(f"Error processing datapoint: {input_data}. {str(e)}")
logger.info("".join(traceback.format_exception_only(type(e), e)))
common.capture_exception_in_sentry(e)

# If max retries is reached or an exception that isn't in the second block,
# update & return the last exception
logging.info("Max retries reached")
exception_message = (
"Max retries reached"
if retries == max_retry_count
Expand Down
18 changes: 18 additions & 0 deletions agenta-backend/agenta_backend/services/logs_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import aiodocker


async def retrieve_logs(container_id: str) -> str:
"""
Retrieves and returns the last 10 lines of logs (both stdout and stderr)
for a specified Docker container.
Args:
container_id (str): The docker container identifier
Returns:
the last 10 lines of logs
"""

async with aiodocker.Docker() as client:
container = await client.containers.get(container_id)
logs = await container.log(stdout=True, stderr=True)
outputs = logs[::-1][:10]
return "".join(outputs)
6 changes: 6 additions & 0 deletions agenta-backend/agenta_backend/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from fastapi.types import DecoratedCallable
from fastapi import APIRouter as FastAPIRouter
from sentry_sdk import capture_exception

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
Expand Down Expand Up @@ -76,3 +77,8 @@ def isCloudDev():

def isOss():
return os.environ["FEATURE_FLAG"] == "oss"


def capture_exception_in_sentry(e: Exception):
if isCloudProd():
capture_exception(e)
Loading

0 comments on commit 8556703

Please sign in to comment.