Skip to content

Commit

Permalink
Merge branch 'dev' into feat/single-input-validation-lock
Browse files Browse the repository at this point in the history
  • Loading branch information
aarushik93 authored Dec 3, 2024
2 parents 4b91a38 + 3bca279 commit 8d41f2d
Show file tree
Hide file tree
Showing 18 changed files with 305 additions and 17 deletions.
24 changes: 21 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ updates:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: "dev"
commit-message:
prefix: "chore(libs/deps)"
prefix-development: "chore(libs/deps-dev)"
groups:
production-dependencies:
dependency-type: "production"
Expand All @@ -26,6 +29,9 @@ updates:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: "dev"
commit-message:
prefix: "chore(backend/deps)"
prefix-development: "chore(backend/deps-dev)"
groups:
production-dependencies:
dependency-type: "production"
Expand All @@ -38,14 +44,16 @@ updates:
- "minor"
- "patch"


# frontend (Next.js project)
- package-ecosystem: "npm"
directory: "autogpt_platform/frontend"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: "dev"
commit-message:
prefix: "chore(frontend/deps)"
prefix-development: "chore(frontend/deps-dev)"
groups:
production-dependencies:
dependency-type: "production"
Expand All @@ -58,14 +66,17 @@ updates:
- "minor"
- "patch"


# infra (Terraform)
- package-ecosystem: "terraform"
directory: "autogpt_platform/infra"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
target-branch: "dev"
commit-message:
prefix: "chore(infra/deps)"
prefix-development: "chore(infra/deps-dev)"

groups:
production-dependencies:
dependency-type: "production"
Expand All @@ -78,14 +89,16 @@ updates:
- "minor"
- "patch"


# market (Poetry project)
- package-ecosystem: "pip"
directory: "autogpt_platform/market"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: "dev"
commit-message:
prefix: "chore(market/deps)"
prefix-development: "chore(market/deps-dev)"
groups:
production-dependencies:
dependency-type: "production"
Expand Down Expand Up @@ -146,6 +159,9 @@ updates:
interval: "weekly"
open-pull-requests-limit: 1
target-branch: "dev"
commit-message:
prefix: "chore(platform/deps)"
prefix-development: "chore(platform/deps-dev)"
groups:
production-dependencies:
dependency-type: "production"
Expand All @@ -166,6 +182,8 @@ updates:
interval: "weekly"
open-pull-requests-limit: 1
target-branch: "dev"
commit-message:
prefix: "chore(docs/deps)"
groups:
production-dependencies:
dependency-type: "production"
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ We take the security of our project seriously. If you believe you have found a s
Instead, please report them via:
- [GitHub Security Advisory](https://github.com/Significant-Gravitas/AutoGPT/security/advisories/new)
- [Huntr.dev](https://huntr.com/repos/significant-gravitas/autogpt) - where you may be eligible for a bounty
<!--- [Huntr.dev](https://huntr.com/repos/significant-gravitas/autogpt) - where you may be eligible for a bounty-->

### Reporting Process
1. **Submit Report**: Use one of the above channels to submit your report
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def feature_flag(
"""

def decorator(
func: Callable[P, Union[T, Awaitable[T]]]
func: Callable[P, Union[T, Awaitable[T]]],
) -> Callable[P, Union[T, Awaitable[T]]]:
@wraps(func)
async def async_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import pytest
from autogpt_libs.feature_flag.client import feature_flag, mock_flag_variation
from ldclient import LDClient

from autogpt_libs.feature_flag.client import feature_flag, mock_flag_variation


@pytest.fixture
def ld_client(mocker):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Settings(BaseSettings):
launch_darkly_sdk_key: str = Field(
default="",
description="The Launch Darkly SDK key",
validation_alias="LAUNCH_DARKLY_SDK_KEY"
validation_alias="LAUNCH_DARKLY_SDK_KEY",
)

model_config = SettingsConfigDict(case_sensitive=True, extra="ignore")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@


class LoggingConfig(BaseSettings):

level: str = Field(
default="INFO",
description="Logging level",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
),
("", ""),
("hello", "hello"),
("hello\x1B[31m world", "hello world"),
("\x1B[36mHello,\x1B[32m World!", "Hello, World!"),
("hello\x1b[31m world", "hello world"),
("\x1b[36mHello,\x1b[32m World!", "Hello, World!"),
(
"\x1B[1m\x1B[31mError:\x1B[0m\x1B[31m file not found",
"\x1b[1m\x1b[31mError:\x1b[0m\x1b[31m file not found",
"Error: file not found",
),
],
Expand Down
Empty file.
31 changes: 31 additions & 0 deletions autogpt_platform/autogpt_libs/autogpt_libs/rate_limit/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict


class RateLimitSettings(BaseSettings):
redis_host: str = Field(
default="redis://localhost:6379",
description="Redis host",
validation_alias="REDIS_HOST",
)

redis_port: str = Field(
default="6379", description="Redis port", validation_alias="REDIS_PORT"
)

redis_password: str = Field(
default="password",
description="Redis password",
validation_alias="REDIS_PASSWORD",
)

requests_per_minute: int = Field(
default=60,
description="Maximum number of requests allowed per minute per API key",
validation_alias="RATE_LIMIT_REQUESTS_PER_MINUTE",
)

model_config = SettingsConfigDict(case_sensitive=True, extra="ignore")


RATE_LIMIT_SETTINGS = RateLimitSettings()
51 changes: 51 additions & 0 deletions autogpt_platform/autogpt_libs/autogpt_libs/rate_limit/limiter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import time
from typing import Tuple

from redis import Redis

from .config import RATE_LIMIT_SETTINGS


class RateLimiter:
def __init__(
self,
redis_host: str = RATE_LIMIT_SETTINGS.redis_host,
redis_port: str = RATE_LIMIT_SETTINGS.redis_port,
redis_password: str = RATE_LIMIT_SETTINGS.redis_password,
requests_per_minute: int = RATE_LIMIT_SETTINGS.requests_per_minute,
):
self.redis = Redis(
host=redis_host,
port=redis_port,
password=redis_password,
decode_responses=True,
)
self.window = 60
self.max_requests = requests_per_minute

async def check_rate_limit(self, api_key_id: str) -> Tuple[bool, int, int]:
"""
Check if request is within rate limits.
Args:
api_key_id: The API key identifier to check
Returns:
Tuple of (is_allowed, remaining_requests, reset_time)
"""
now = time.time()
window_start = now - self.window
key = f"ratelimit:{api_key_id}:1min"

pipe = self.redis.pipeline()
pipe.zremrangebyscore(key, 0, window_start)
pipe.zadd(key, {str(now): now})
pipe.zcount(key, window_start, now)
pipe.expire(key, self.window)

_, _, request_count, _ = pipe.execute()

remaining = max(0, self.max_requests - request_count)
reset_time = int(now + self.window)

return request_count <= self.max_requests, remaining, reset_time
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from fastapi import HTTPException, Request
from starlette.middleware.base import RequestResponseEndpoint

from .limiter import RateLimiter


async def rate_limit_middleware(request: Request, call_next: RequestResponseEndpoint):
"""FastAPI middleware for rate limiting API requests."""
limiter = RateLimiter()

if not request.url.path.startswith("/api"):
return await call_next(request)

api_key = request.headers.get("Authorization")
if not api_key:
return await call_next(request)

api_key = api_key.replace("Bearer ", "")

is_allowed, remaining, reset_time = await limiter.check_rate_limit(api_key)

if not is_allowed:
raise HTTPException(
status_code=429, detail="Rate limit exceeded. Please try again later."
)

response = await call_next(request)
response.headers["X-RateLimit-Limit"] = str(limiter.max_requests)
response.headers["X-RateLimit-Remaining"] = str(remaining)
response.headers["X-RateLimit-Reset"] = str(reset_time)

return response
Empty file.
59 changes: 59 additions & 0 deletions autogpt_platform/backend/backend/blocks/jina/fact_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from urllib.parse import quote

import requests

from backend.blocks.jina._auth import (
JinaCredentials,
JinaCredentialsField,
JinaCredentialsInput,
)
from backend.data.block import Block, BlockCategory, BlockOutput, BlockSchema
from backend.data.model import SchemaField


class FactCheckerBlock(Block):
class Input(BlockSchema):
statement: str = SchemaField(
description="The statement to check for factuality"
)
credentials: JinaCredentialsInput = JinaCredentialsField()

class Output(BlockSchema):
factuality: float = SchemaField(
description="The factuality score of the statement"
)
result: bool = SchemaField(description="The result of the factuality check")
reason: str = SchemaField(description="The reason for the factuality result")
error: str = SchemaField(description="Error message if the check fails")

def __init__(self):
super().__init__(
id="d38b6c5e-9968-4271-8423-6cfe60d6e7e6",
description="This block checks the factuality of a given statement using Jina AI's Grounding API.",
categories={BlockCategory.SEARCH},
input_schema=FactCheckerBlock.Input,
output_schema=FactCheckerBlock.Output,
)

def run(
self, input_data: Input, *, credentials: JinaCredentials, **kwargs
) -> BlockOutput:
encoded_statement = quote(input_data.statement)
url = f"https://g.jina.ai/{encoded_statement}"

headers = {
"Accept": "application/json",
"Authorization": f"Bearer {credentials.api_key.get_secret_value()}",
}

response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()

if "data" in data:
data = data["data"]
yield "factuality", data["factuality"]
yield "result", data["result"]
yield "reason", data["reason"]
else:
raise RuntimeError(f"Expected 'data' key not found in response: {data}")
9 changes: 5 additions & 4 deletions autogpt_platform/backend/linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import subprocess

directory = os.path.dirname(os.path.realpath(__file__))
target_dirs = ["../backend", "../autogpt_libs"]


def run(*command: str) -> None:
Expand All @@ -11,17 +12,17 @@ def run(*command: str) -> None:

def lint():
try:
run("ruff", "check", ".", "--exit-zero")
run("ruff", "check", *target_dirs, "--exit-zero")
run("isort", "--diff", "--check", "--profile", "black", ".")
run("black", "--diff", "--check", ".")
run("pyright")
run("pyright", *target_dirs)
except subprocess.CalledProcessError as e:
print("Lint failed, try running `poetry run format` to fix the issues: ", e)
raise e


def format():
run("ruff", "check", "--fix", ".")
run("ruff", "check", "--fix", *target_dirs)
run("isort", "--profile", "black", ".")
run("black", ".")
run("pyright", ".")
run("pyright", *target_dirs)
3 changes: 2 additions & 1 deletion autogpt_platform/frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ NEXT_PUBLIC_AUTH_CALLBACK_URL=http://localhost:8006/auth/callback
NEXT_PUBLIC_AGPT_SERVER_URL=http://localhost:8006/api
NEXT_PUBLIC_AGPT_WS_SERVER_URL=ws://localhost:8001/ws
NEXT_PUBLIC_AGPT_MARKETPLACE_URL=http://localhost:8015/api/v1/market
NEXT_PUBLIC_APP_ENV=dev

## Supabase credentials

Expand All @@ -15,4 +16,4 @@ AUTH_CALLBACK_URL=http://localhost:3000/auth/callback
GA_MEASUREMENT_ID=G-FH2XK2W4GN

# When running locally, set NEXT_PUBLIC_BEHAVE_AS=CLOUD to use the a locally hosted marketplace (as is typical in development, and the cloud deployment), otherwise set it to LOCAL to have the marketplace open in a new tab
NEXT_PUBLIC_BEHAVE_AS=LOCAL
NEXT_PUBLIC_BEHAVE_AS=LOCAL
10 changes: 9 additions & 1 deletion autogpt_platform/frontend/src/components/nav/MarketPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ interface MarketPopupProps extends ButtonHTMLAttributes<HTMLButtonElement> {

export default function MarketPopup({
className = "",
marketplaceUrl = "http://platform.agpt.co/marketplace",
marketplaceUrl = (() => {
if (process.env.NEXT_PUBLIC_APP_ENV === "prod") {
return "https://production-marketplace-url.com";
} else if (process.env.NEXT_PUBLIC_APP_ENV === "dev") {
return "https://dev-builder.agpt.co/marketplace";
} else {
return "http://localhost:3000/marketplace";
}
})(),
children,
...props
}: MarketPopupProps) {
Expand Down
Loading

0 comments on commit 8d41f2d

Please sign in to comment.