Skip to content
Open
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
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source_env .env
18 changes: 9 additions & 9 deletions app/api/agentops/api/routes/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ async def create_session(request: Request, supabase: AsyncSupabaseClient):
except ExpiredJWTError:
logger.warning("Expired JWT")
return JSONResponse({"path": request.url.path, "message": "Expired Token"}, status_code=401)
except InvalidAPIKeyError as e:
except InvalidAPIKeyError:
# This is a user error (invalid API key format), not a system error
# Log as warning to avoid Sentry alerts
try:
Expand All @@ -93,7 +93,7 @@ async def create_session(request: Request, supabase: AsyncSupabaseClient):
)
except Exception:
logger.warning(f"{request.url.path}: Invalid API key format")

return JSONResponse(
{
"path": request.url.path,
Expand Down Expand Up @@ -151,8 +151,8 @@ async def v2_reauthorize_jwt(request: Request, supabase: AsyncSupabaseClient):
token = generate_jwt(data["session_id"], jwt_secret)
logger.info(colored(f"Completed request for session: {data['session_id']}", "yellow"))
return JSONResponse({"status": "Success", "jwt": token})
except InvalidAPIKeyError as e:

except InvalidAPIKeyError:
# This is a user error (invalid API key format), not a system error
# Log as warning to avoid Sentry alerts
try:
Expand All @@ -162,7 +162,7 @@ async def v2_reauthorize_jwt(request: Request, supabase: AsyncSupabaseClient):
)
except Exception:
logger.warning(f"{request.url.path}: Invalid API key format")

return JSONResponse(
{
"path": request.url.path,
Expand Down Expand Up @@ -252,7 +252,7 @@ async def v2_create_session(request: Request, supabase: AsyncSupabaseClient):
except ExpiredJWTError:
logger.warning("Expired JWT")
return JSONResponse({"path": str(request.url.path), "message": "Expired Token"}, status_code=401)
except InvalidAPIKeyError as e:
except InvalidAPIKeyError:
# This is a user error (invalid API key format), not a system error
# Log as warning to avoid Sentry alerts
try:
Expand All @@ -262,7 +262,7 @@ async def v2_create_session(request: Request, supabase: AsyncSupabaseClient):
)
except Exception:
logger.warning(f"{request.url.path}: Invalid API key format")

return JSONResponse(
{
"path": request.url.path,
Expand Down Expand Up @@ -784,7 +784,7 @@ async def v2_get_session_stats(session_id: str, request: Request, supabase: Asyn

return JSONResponse(stats)

except InvalidAPIKeyError as e:
except InvalidAPIKeyError:
# This is a user error (invalid API key format), not a system error
# Log as warning to avoid Sentry alerts
logger.warning(f"{request.url.path}: Invalid API key format for session {session_id}")
Expand Down Expand Up @@ -837,7 +837,7 @@ async def v2_export_session(session_id: str, request: Request, supabase: AsyncSu

return JSONResponse(export_data)

except InvalidAPIKeyError as e:
except InvalidAPIKeyError:
# This is a user error (invalid API key format), not a system error
# Log as warning to avoid Sentry alerts
logger.warning(f"{request.url.path}: Invalid API key format for session {session_id}")
Expand Down
2 changes: 1 addition & 1 deletion app/api/agentops/auth/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,4 @@

router = APIRouter(route_class=AuthenticatedRoute)
register_routes(router, route_config, prefix="/auth")
app.include_router(router)
app.include_router(router)
20 changes: 10 additions & 10 deletions app/api/agentops/deploy/views/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ async def __call__(
"Authorization": f"Bearer {project.github_oath_access_token}",
"Accept": "application/vnd.github+json",
}

all_repos = []
page = 1
per_page = 100 # Maximum allowed by GitHub API

try:
while True:
params = {
Expand All @@ -93,15 +93,15 @@ async def __call__(
"sort": "created", # Sort by creation date
"direction": "desc" # Most recent first
}

resp = requests.get("https://api.github.com/user/repos", headers=headers, params=params)
resp.raise_for_status()
repos = resp.json()

# If no repos returned, we've reached the end
if not repos:
break

# Add repos from this page
all_repos.extend([
{
Expand All @@ -114,14 +114,14 @@ async def __call__(
}
for repo in repos
])

# If we got fewer repos than per_page, we've reached the end
if len(repos) < per_page:
break

page += 1

return all_repos

except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to fetch repos from GitHub: {str(e)}")
raise HTTPException(status_code=500, detail=f"Failed to fetch repos from GitHub: {str(e)}")
2 changes: 1 addition & 1 deletion app/api/agentops/public/agent/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# these are the public views for interacting with hosted agents
# these are the public views for interacting with hosted agents
9 changes: 4 additions & 5 deletions app/api/agentops/public/agent/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
from fastapi import Request, HTTPException, Depends
from agentops.common.route_config import BaseView
from agentops.common.orm import Session, get_orm_session
from agentops.api.auth import JWTPayload, verify_jwt
from agentops.opsboard.models import BaseProjectModel, ProjectModel, SparseProjectModel
from agentops.opsboard.models import ProjectModel
from agentops.deploy.models import HostingProjectModel


Expand Down Expand Up @@ -35,7 +34,7 @@ async def create(cls, request: Request) -> "BaseAgentAPIView":
# we use a constructor to allow us to execute async methods on creation
instance = await super().create(request=request)
return instance


class AuthenticatedByKeyAgentAPIView(BaseAgentAPIView, ABC):
"""
Expand All @@ -59,12 +58,12 @@ async def get_project(self, orm: Session = Depends(get_orm_session)) -> ProjectM
self._validate_api_key(api_key)
project = ProjectModel.get_by_api_key(orm, api_key)
return project

async def get_hosted_project(self, orm: Session = Depends(get_orm_session)) -> HostingProjectModel:
"""Get hosted project for authenticated use cases via API key."""
# For API key auth, hosted project is the same as regular project
api_key = getattr(self.request.state, 'api_key', None)
self._validate_api_key(api_key)
project = ProjectModel.get_by_api_key(orm, api_key)
hosted_project = HostingProjectModel.get_by_id(orm, project.id)
return hosted_project
return hosted_project
20 changes: 10 additions & 10 deletions app/api/agentops/public/agent/job.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pydantic
from fastapi import Depends, HTTPException
from fastapi import Depends
from agentops.common.orm import Session, get_orm_session
from .base import AuthenticatedByKeyAgentAPIView, BaseResponse
from jockey.backend.models.job import Job
Expand All @@ -21,7 +21,7 @@ class JobResponse(BaseResponse):
@classmethod
def validate_uuid(cls, v):
return str(v)

@pydantic.field_validator("job", mode="before")
@classmethod
def to_string(cls, v) -> str:
Expand All @@ -37,25 +37,25 @@ class KickoffRunView(AuthenticatedByKeyAgentAPIView):
async def __call__(self, body: JobRequest, orm: Session = Depends(get_orm_session)) -> JobResponse:
job = await self.start_run(body=body, orm=orm)
return JobResponse.model_validate(job)

async def start_run(self, body: JobRequest, orm: Session) -> Job:
project = await self.get_project(orm=orm)
run_request = RunJobRequest(inputs=body.inputs, callback_url=body.callback_url)

initiate_run_view = InitiateRunView()
initiate_run_view.request = self.request
deployment_response = await initiate_run_view.__call__(
project_id=str(project.id),
body=run_request,
orm=orm
)

job = Job(
name=f"agent-job-{deployment_response.job_id}",
image_url="",
namespace="",
)

return JobResponse(
id=deployment_response.job_id,
agent_id=project.id,
Expand All @@ -73,13 +73,13 @@ class JobStatusView(AuthenticatedByKeyAgentAPIView):
async def __call__(self, orm: Session = Depends(get_orm_session)) -> JobResponse:
job = await self.get_job(orm=orm)
return JobResponse.model_validate(job)

async def get_job(self, orm: Session) -> Job:
"""Get job details - implement based on your requirements."""
# This is a placeholder implementation
# You'll need to implement this based on how you want to retrieve job information
raise NotImplementedError("get_job method not implemented")


class JobHistoryView(AuthenticatedByKeyAgentAPIView):
__name__ = "Get Project"
Expand All @@ -92,9 +92,9 @@ class JobHistoryView(AuthenticatedByKeyAgentAPIView):
async def __call__(self, orm: Session = Depends(get_orm_session)) -> JobResponse:
project = await self.get_project(orm=orm)
return JobResponse.model_validate(project)

async def get_project(self, orm: Session) -> Job:
"""Get project details - implement based on your requirements."""
# This is a placeholder implementation
# You'll need to implement this based on how you want to retrieve project information
raise NotImplementedError("get_project method not implemented")
raise NotImplementedError("get_project method not implemented")
8 changes: 4 additions & 4 deletions app/api/tests/auth/test_public_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

# Mark to skip rate limit tests when Redis is not available
redis_required = pytest.mark.skipif(
not (REDIS_HOST and REDIS_PORT),
not (REDIS_HOST and REDIS_PORT),
reason="Rate limit tests require Redis (REDIS_HOST and REDIS_PORT env vars)"
)

Expand Down Expand Up @@ -211,7 +211,7 @@ async def __call__(self):

# Create an instance and test validation
view_instance = TestView(mock_request)

# The wrapped __call__ method should validate the request
with patch('agentops.auth.views._validate_request') as mock_validate:
import asyncio
Expand All @@ -220,10 +220,10 @@ async def __call__(self):
mock_validate.assert_called_once_with(mock_request)


@patch("agentops.auth.views.API_URL", "https://api.agentops.ai")
@patch("agentops.auth.views.API_URL", "https://api.agentops.ai")
def test_public_route_decorator_invalid_class():
"""Test that the public_route decorator raises TypeError for non-BaseView classes."""

# Should raise TypeError when decorating a non-BaseView class
with pytest.raises(TypeError, match="must inherit from BaseView"):
@public_route
Expand Down
Loading
Loading