Co-authored-by: Ethan Knox <ethan.m.knox@gmail.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1016,3 +1016,4 @@ pgdata/
|
||||
## pytest mirrors
|
||||
memgpt/.pytest_cache/
|
||||
memgpy/pytest.ini
|
||||
**/**/pytest_cache
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# The builder image, used to build the virtual environment
|
||||
FROM python:3.12-bookworm as builder
|
||||
FROM python:3.12.2-bookworm as builder
|
||||
ARG MEMGPT_ENVIRONMENT=PRODUCTION
|
||||
ENV MEMGPT_ENVIRONMENT=${MEMGPT_ENVIRONMENT}
|
||||
RUN pip install poetry==1.8.2
|
||||
@@ -16,13 +16,13 @@ RUN poetry lock --no-update
|
||||
RUN if [ "$MEMGPT_ENVIRONMENT" = "DEVELOPMENT" ] ; then \
|
||||
poetry install --no-root -E "postgres server dev autogen" ; \
|
||||
else \
|
||||
poetry install --without dev --without local --no-root -E "postgres server" && \
|
||||
poetry install --no-root -E "postgres server" && \
|
||||
rm -rf $POETRY_CACHE_DIR ; \
|
||||
fi
|
||||
|
||||
|
||||
# The runtime image, used to just run the code provided its virtual environment
|
||||
FROM python:3.12-slim-bookworm as runtime
|
||||
FROM python:3.12.2-slim-bookworm as runtime
|
||||
ARG MEMGPT_ENVIRONMENT=PRODUCTION
|
||||
ENV MEMGPT_ENVIRONMENT=${MEMGPT_ENVIRONMENT}
|
||||
ENV VIRTUAL_ENV=/app/.venv \
|
||||
|
||||
@@ -22,6 +22,7 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: runtime
|
||||
depends_on:
|
||||
- memgpt_db
|
||||
ports:
|
||||
|
||||
@@ -14,6 +14,8 @@ services:
|
||||
- .env
|
||||
environment:
|
||||
- MEMGPT_SERVER_PASS=test_server_token
|
||||
- WATCHFILES_FORCE_POLLING=true
|
||||
|
||||
volumes:
|
||||
- ./memgpt:/memgpt
|
||||
- ~/.memgpt/credentials:/root/.memgpt/credentials
|
||||
|
||||
@@ -19,7 +19,7 @@ from memgpt.config import MemGPTConfig
|
||||
from memgpt.constants import CLI_WARNING_PREFIX, MEMGPT_DIR
|
||||
from memgpt.credentials import MemGPTCredentials
|
||||
from memgpt.data_types import EmbeddingConfig, LLMConfig, User
|
||||
from memgpt.log import logger
|
||||
from memgpt.log import get_logger
|
||||
from memgpt.metadata import MetadataStore
|
||||
from memgpt.migrate import migrate_all_agents, migrate_all_sources
|
||||
from memgpt.server.constants import WS_DEFAULT_PORT
|
||||
@@ -30,6 +30,8 @@ from memgpt.streaming_interface import (
|
||||
)
|
||||
from memgpt.utils import open_folder_in_explorer, printd
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def migrate(
|
||||
debug: Annotated[bool, typer.Option(help="Print extra tracebacks for failed migrations")] = False,
|
||||
|
||||
@@ -9,7 +9,9 @@ import memgpt
|
||||
import memgpt.utils as utils
|
||||
from memgpt.constants import DEFAULT_HUMAN, DEFAULT_PERSONA, DEFAULT_PRESET, MEMGPT_DIR
|
||||
from memgpt.data_types import AgentState, EmbeddingConfig, LLMConfig
|
||||
from memgpt.log import logger
|
||||
from memgpt.log import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
# helper functions for writing to configs
|
||||
|
||||
@@ -21,17 +21,6 @@ DEFAULT_PERSONA = "sam_pov"
|
||||
DEFAULT_HUMAN = "basic"
|
||||
DEFAULT_PRESET = "memgpt_chat"
|
||||
|
||||
# Used to isolate MemGPT logger instance from Dependant Libraries logging
|
||||
LOGGER_NAME = "MemGPT"
|
||||
LOGGER_DEFAULT_LEVEL = CRITICAL
|
||||
# Where to store the logs
|
||||
LOGGER_DIR = os.path.join(MEMGPT_DIR, "logs")
|
||||
# filename of the log
|
||||
LOGGER_FILENAME = "MemGPT.log"
|
||||
# Number of log files to rotate
|
||||
LOGGER_FILE_BACKUP_COUNT = 3
|
||||
# Max Log file size in bytes
|
||||
LOGGER_MAX_FILE_SIZE = 10485760
|
||||
# LOGGER_LOG_LEVEL is use to convert Text to Logging level value for logging mostly for Cli input to setting level
|
||||
LOGGER_LOG_LEVELS = {"CRITICAL": CRITICAL, "ERROR": ERROR, "WARN": WARN, "WARNING": WARNING, "INFO": INFO, "DEBUG": DEBUG, "NOTSET": NOTSET}
|
||||
|
||||
|
||||
@@ -1,43 +1,77 @@
|
||||
import logging
|
||||
import os
|
||||
import os.path
|
||||
from logging.config import dictConfig
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
from sys import stdout
|
||||
from typing import Optional
|
||||
|
||||
from memgpt.constants import (
|
||||
LOGGER_DEFAULT_LEVEL,
|
||||
LOGGER_DIR,
|
||||
LOGGER_FILE_BACKUP_COUNT,
|
||||
LOGGER_FILENAME,
|
||||
LOGGER_MAX_FILE_SIZE,
|
||||
LOGGER_NAME,
|
||||
)
|
||||
from memgpt.settings import settings
|
||||
|
||||
# Checking if log directory exists
|
||||
if not os.path.exists(LOGGER_DIR):
|
||||
os.makedirs(LOGGER_DIR, exist_ok=True)
|
||||
selected_log_level = logging.DEBUG if settings.debug else logging.INFO
|
||||
|
||||
# Create logger for MemGPT
|
||||
logger = logging.getLogger(LOGGER_NAME)
|
||||
logger.setLevel(LOGGER_DEFAULT_LEVEL)
|
||||
|
||||
# create console handler and set level to debug
|
||||
console_handler = logging.StreamHandler()
|
||||
def _setup_logfile() -> "Path":
|
||||
"""ensure the logger filepath is in place
|
||||
|
||||
# create rotatating file handler
|
||||
file_handler = RotatingFileHandler(
|
||||
os.path.join(LOGGER_DIR, LOGGER_FILENAME), maxBytes=LOGGER_MAX_FILE_SIZE, backupCount=LOGGER_FILE_BACKUP_COUNT
|
||||
)
|
||||
Returns: the logfile Path
|
||||
"""
|
||||
logfile = Path(settings.memgpt_dir / "logs" / "MemGPT.log")
|
||||
logfile.parent.mkdir(parents=True, exist_ok=True)
|
||||
logfile.touch(exist_ok=True)
|
||||
return logfile
|
||||
|
||||
# create formatters
|
||||
console_formatter = logging.Formatter("%(name)s - %(levelname)s - %(message)s") # not datetime
|
||||
file_formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
|
||||
# add formatter to console handler
|
||||
console_handler.setFormatter(console_formatter)
|
||||
# TODO: production logging should be much less invasive
|
||||
DEVELOPMENT_LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": True,
|
||||
"formatters": {
|
||||
"standard": {"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"},
|
||||
"no_datetime": {
|
||||
"format": "%(name)s - %(levelname)s - %(message)s",
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"level": selected_log_level,
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": stdout,
|
||||
"formatter": "no_datetime",
|
||||
},
|
||||
"file": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": _setup_logfile(),
|
||||
"maxBytes": 1024**2 * 10,
|
||||
"backupCount": 3,
|
||||
"formatter": "standard",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"MemGPT": {
|
||||
"level": logging.DEBUG if settings.debug else logging.INFO,
|
||||
"handlers": [
|
||||
"console",
|
||||
"file",
|
||||
],
|
||||
"propagate": False,
|
||||
},
|
||||
"uvicorn": {
|
||||
"level": "INFO",
|
||||
"handlers": ["console"],
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# add formatter for file handler
|
||||
file_handler.setFormatter(file_formatter)
|
||||
|
||||
# add ch to logger
|
||||
logger.addHandler(console_handler)
|
||||
logger.addHandler(file_handler)
|
||||
def get_logger(name: Optional[str] = None) -> "logging.Logger":
|
||||
"""returns the project logger, scoped to a child name if provided
|
||||
Args:
|
||||
name: will define a child logger
|
||||
"""
|
||||
dictConfig(DEVELOPMENT_LOGGING)
|
||||
parent_logger = logging.getLogger("MemGPT")
|
||||
if name:
|
||||
return parent_logger.getChild(name)
|
||||
return parent_logger
|
||||
|
||||
@@ -418,7 +418,7 @@ class MetadataStore:
|
||||
"""Get the user associated with a given API key"""
|
||||
token = self.get_api_key(api_key=api_key)
|
||||
if token is None:
|
||||
raise ValueError(f"Token {api_key} does not exist")
|
||||
raise ValueError(f"Provided token does not exist")
|
||||
else:
|
||||
return self.get_user(user_id=token.user_id)
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@ from uuid import UUID
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from memgpt.log import get_logger
|
||||
from memgpt.server.rest_api.interface import QueuingInterface
|
||||
from memgpt.server.server import SyncServer
|
||||
|
||||
logger = get_logger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@@ -18,6 +20,7 @@ class AuthRequest(BaseModel):
|
||||
|
||||
|
||||
def setup_auth_router(server: SyncServer, interface: QueuingInterface, password: str) -> APIRouter:
|
||||
|
||||
@router.post("/auth", tags=["auth"], response_model=AuthResponse)
|
||||
def authenticate_user(request: AuthRequest) -> AuthResponse:
|
||||
"""
|
||||
@@ -26,16 +29,10 @@ def setup_auth_router(server: SyncServer, interface: QueuingInterface, password:
|
||||
Currently, this is a placeholder that simply returns a UUID placeholder
|
||||
"""
|
||||
interface.clear()
|
||||
try:
|
||||
if request.password != password:
|
||||
# raise HTTPException(status_code=400, detail="Incorrect credentials")
|
||||
response = server.api_key_to_user(api_key=request.password)
|
||||
else:
|
||||
response = server.authenticate_user()
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"{e}")
|
||||
if request.password != password:
|
||||
response = server.api_key_to_user(api_key=request.password)
|
||||
else:
|
||||
response = server.authenticate_user()
|
||||
return AuthResponse(uuid=response)
|
||||
|
||||
return router
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
import warnings
|
||||
from abc import abstractmethod
|
||||
@@ -37,6 +36,7 @@ from memgpt.data_types import (
|
||||
# TODO use custom interface
|
||||
from memgpt.interface import AgentInterface # abstract
|
||||
from memgpt.interface import CLIInterface # for printing to terminal
|
||||
from memgpt.log import get_logger
|
||||
from memgpt.metadata import MetadataStore
|
||||
from memgpt.models.pydantic_models import (
|
||||
DocumentModel,
|
||||
@@ -47,7 +47,7 @@ from memgpt.models.pydantic_models import (
|
||||
ToolModel,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class Server(object):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
echo "Starting MEMGPT server..."
|
||||
if [ "$MEMGPT_ENVIRONMENT" = "DEVELOPMENT" ] ; then
|
||||
echo "Starting in development mode!"
|
||||
uvicorn memgpt.server.rest_api.server:app --reload --reload-dir /memgpt --host 0.0.0.0 --port 8083
|
||||
else
|
||||
uvicorn memgpt.server.rest_api.server:app --host 0.0.0.0 --port 8083
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_prefix="memgpt_")
|
||||
|
||||
memgpt_dir: Optional[Path] = Field(Path.home() / ".memgpt", env="MEMGPT_DIR")
|
||||
debug: Optional[bool] = False
|
||||
server_pass: Optional[str] = None
|
||||
pg_db: Optional[str] = None
|
||||
pg_user: Optional[str] = None
|
||||
|
||||
@@ -29,7 +29,6 @@ test_server_token = "test_server_token"
|
||||
|
||||
|
||||
def _reset_config():
|
||||
|
||||
# Use os.getenv with a fallback to os.environ.get
|
||||
db_url = settings.memgpt_pg_uri
|
||||
|
||||
@@ -51,14 +50,12 @@ def _reset_config():
|
||||
config.archival_storage_type = "postgres"
|
||||
config.recall_storage_type = "postgres"
|
||||
config.metadata_storage_type = "postgres"
|
||||
|
||||
config.save()
|
||||
credentials.save()
|
||||
print("_reset_config :: ", config.config_path)
|
||||
|
||||
|
||||
def run_server():
|
||||
|
||||
load_dotenv()
|
||||
|
||||
_reset_config()
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import logging
|
||||
|
||||
from memgpt.constants import LOGGER_LOG_LEVELS
|
||||
from memgpt.log import logger
|
||||
|
||||
|
||||
def test_log_debug():
|
||||
# test setting logging level
|
||||
assert logging.DEBUG == LOGGER_LOG_LEVELS["DEBUG"]
|
||||
logger.setLevel(LOGGER_LOG_LEVELS["DEBUG"])
|
||||
assert logger.isEnabledFor(logging.DEBUG)
|
||||
|
||||
# Assert that the message was logged
|
||||
assert logger.hasHandlers()
|
||||
logger.debug("This is a Debug message")
|
||||
assert 1 == 1
|
||||
Reference in New Issue
Block a user