feat: add profiling and structured logging (#5690)
* test dd build * dd agent in cluster * quick poc * refactor and add logging * remove tracing etc. * add changes to otel logging config * refactor to accept my feedback * finishing touches
This commit is contained in:
178
letta/log.py
178
letta/log.py
@@ -1,14 +1,136 @@
|
||||
import json
|
||||
import logging
|
||||
import traceback
|
||||
from datetime import datetime, timezone
|
||||
from logging.config import dictConfig
|
||||
from pathlib import Path
|
||||
from sys import stdout
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from letta.settings import settings
|
||||
from letta.settings import log_settings, settings, telemetry_settings
|
||||
|
||||
selected_log_level = logging.DEBUG if settings.debug else logging.INFO
|
||||
|
||||
|
||||
class JSONFormatter(logging.Formatter):
|
||||
"""
|
||||
Custom JSON formatter for structured logging with Datadog integration.
|
||||
|
||||
Outputs logs in JSON format with fields compatible with Datadog log ingestion.
|
||||
Automatically includes trace correlation fields when Datadog tracing is enabled.
|
||||
|
||||
Usage:
|
||||
Enable JSON logging by setting the environment variable:
|
||||
LETTA_LOGGING_JSON_LOGGING=true
|
||||
|
||||
Add custom structured fields to logs using the 'extra' parameter:
|
||||
logger.info("User action", extra={"user_id": "123", "action": "login"})
|
||||
|
||||
These fields will be automatically included in the JSON output and
|
||||
indexed by Datadog for filtering and analysis.
|
||||
|
||||
Output format:
|
||||
{
|
||||
"timestamp": "2025-10-23T18:34:24.931739+00:00",
|
||||
"level": "INFO",
|
||||
"logger": "Letta.module",
|
||||
"message": "Log message",
|
||||
"module": "module_name",
|
||||
"function": "function_name",
|
||||
"line": 123,
|
||||
"dd.trace_id": "1234567890", # Added when Datadog tracing is enabled
|
||||
"dd.span_id": "9876543210", # Added when Datadog tracing is enabled
|
||||
"custom_field": "custom_value" # Any extra fields you provide
|
||||
}
|
||||
"""
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
"""Format log record as JSON with Datadog-compatible fields."""
|
||||
# Base log structure
|
||||
log_data: dict[str, Any] = {
|
||||
"timestamp": datetime.fromtimestamp(record.created, tz=timezone.utc).isoformat(),
|
||||
"level": record.levelname,
|
||||
"logger": record.name,
|
||||
"message": record.getMessage(),
|
||||
"module": record.module,
|
||||
"function": record.funcName,
|
||||
"line": record.lineno,
|
||||
}
|
||||
|
||||
# Add Datadog trace correlation if available
|
||||
# ddtrace automatically injects these attributes when logging is patched
|
||||
if hasattr(record, "dd.trace_id"):
|
||||
log_data["dd.trace_id"] = getattr(record, "dd.trace_id")
|
||||
if hasattr(record, "dd.span_id"):
|
||||
log_data["dd.span_id"] = getattr(record, "dd.span_id")
|
||||
if hasattr(record, "dd.service"):
|
||||
log_data["dd.service"] = getattr(record, "dd.service")
|
||||
if hasattr(record, "dd.env"):
|
||||
log_data["dd.env"] = getattr(record, "dd.env")
|
||||
if hasattr(record, "dd.version"):
|
||||
log_data["dd.version"] = getattr(record, "dd.version")
|
||||
|
||||
# Add exception info if present
|
||||
if record.exc_info:
|
||||
log_data["exception"] = {
|
||||
"type": record.exc_info[0].__name__ if record.exc_info[0] else None,
|
||||
"message": str(record.exc_info[1]) if record.exc_info[1] else None,
|
||||
"stacktrace": "".join(traceback.format_exception(*record.exc_info)),
|
||||
}
|
||||
|
||||
# Add any extra fields from the log record
|
||||
# These are custom fields passed via logging.info("msg", extra={...})
|
||||
for key, value in record.__dict__.items():
|
||||
if key not in [
|
||||
"name",
|
||||
"msg",
|
||||
"args",
|
||||
"created",
|
||||
"filename",
|
||||
"funcName",
|
||||
"levelname",
|
||||
"levelno",
|
||||
"lineno",
|
||||
"module",
|
||||
"msecs",
|
||||
"message",
|
||||
"pathname",
|
||||
"process",
|
||||
"processName",
|
||||
"relativeCreated",
|
||||
"thread",
|
||||
"threadName",
|
||||
"exc_info",
|
||||
"exc_text",
|
||||
"stack_info",
|
||||
"dd_env",
|
||||
"dd_service",
|
||||
] and not key.startswith("dd."):
|
||||
log_data[key] = value
|
||||
|
||||
return json.dumps(log_data, default=str)
|
||||
|
||||
|
||||
class DatadogEnvFilter(logging.Filter):
|
||||
"""
|
||||
Logging filter that adds Datadog-specific attributes to log records.
|
||||
|
||||
This enables log-trace correlation by injecting environment and service metadata
|
||||
that Datadog can use to link logs with traces and other telemetry data.
|
||||
"""
|
||||
|
||||
def filter(self, record: logging.LogRecord) -> bool:
|
||||
"""Add Datadog attributes to log record if Datadog is enabled."""
|
||||
if telemetry_settings.enable_datadog:
|
||||
record.dd_env = telemetry_settings.datadog_env
|
||||
record.dd_service = "letta-server"
|
||||
else:
|
||||
# Provide defaults to prevent attribute errors if filter is applied incorrectly
|
||||
record.dd_env = ""
|
||||
record.dd_service = ""
|
||||
return True
|
||||
|
||||
|
||||
def _setup_logfile() -> "Path":
|
||||
"""ensure the logger filepath is in place
|
||||
|
||||
@@ -20,28 +142,65 @@ def _setup_logfile() -> "Path":
|
||||
return logfile
|
||||
|
||||
|
||||
# TODO: production logging should be much less invasive
|
||||
# Determine which formatter to use based on configuration
|
||||
def _get_console_formatter() -> str:
|
||||
"""Determine the appropriate console formatter based on settings."""
|
||||
if log_settings.json_logging:
|
||||
return "json"
|
||||
elif telemetry_settings.enable_datadog:
|
||||
return "datadog"
|
||||
else:
|
||||
return "no_datetime"
|
||||
|
||||
|
||||
def _get_file_formatter() -> str:
|
||||
"""Determine the appropriate file formatter based on settings."""
|
||||
if log_settings.json_logging:
|
||||
return "json"
|
||||
elif telemetry_settings.enable_datadog:
|
||||
return "datadog"
|
||||
else:
|
||||
return "standard"
|
||||
|
||||
|
||||
# Logging configuration with optional Datadog integration and JSON support
|
||||
DEVELOPMENT_LOGGING = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False, # Allow capturing from all loggers
|
||||
"formatters": {
|
||||
"standard": {"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"},
|
||||
"no_datetime": {"format": "%(name)s - %(levelname)s - %(message)s"},
|
||||
"datadog": {
|
||||
# Datadog-compatible format with key=value pairs for better parsing
|
||||
# ddtrace's log injection will add dd.trace_id, dd.span_id automatically when logging is patched
|
||||
"format": "%(asctime)s - %(name)s - %(levelname)s - [dd.env=%(dd_env)s dd.service=%(dd_service)s] - %(message)s"
|
||||
},
|
||||
"json": {
|
||||
# JSON formatter for structured logging with full Datadog integration
|
||||
"()": JSONFormatter,
|
||||
},
|
||||
},
|
||||
"filters": {
|
||||
"datadog_env": {
|
||||
"()": DatadogEnvFilter,
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"console": {
|
||||
"level": selected_log_level,
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": stdout,
|
||||
"formatter": "no_datetime",
|
||||
"formatter": _get_console_formatter(),
|
||||
"filters": ["datadog_env"] if telemetry_settings.enable_datadog and not log_settings.json_logging else [],
|
||||
},
|
||||
"file": {
|
||||
"level": "DEBUG",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"filename": _setup_logfile(),
|
||||
"maxBytes": 1024**2 * 10,
|
||||
"backupCount": 3,
|
||||
"formatter": "standard",
|
||||
"maxBytes": 1024**2 * 10, # 10 MB per file
|
||||
"backupCount": 3, # Keep 3 backup files
|
||||
"formatter": _get_file_formatter(),
|
||||
"filters": ["datadog_env"] if telemetry_settings.enable_datadog and not log_settings.json_logging else [],
|
||||
},
|
||||
},
|
||||
"root": { # Root logger handles all logs
|
||||
@@ -58,6 +217,11 @@ DEVELOPMENT_LOGGING = {
|
||||
"handlers": ["console"],
|
||||
"propagate": True,
|
||||
},
|
||||
# Reduce noise from ddtrace internal logging
|
||||
"ddtrace": {
|
||||
"level": "WARNING",
|
||||
"propagate": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,49 @@ def create_application() -> "FastAPI":
|
||||
},
|
||||
)
|
||||
|
||||
if telemetry_settings.enable_datadog:
|
||||
try:
|
||||
dd_env = settings.environment or "development"
|
||||
print(f"▶ Initializing Datadog profiling (env={dd_env})")
|
||||
|
||||
# Configure environment variables before importing ddtrace (must be set in environment before importing ddtrace)
|
||||
os.environ.setdefault("DD_ENV", dd_env)
|
||||
os.environ.setdefault("DD_SERVICE", telemetry_settings.datadog_service_name)
|
||||
os.environ.setdefault("DD_VERSION", letta_version)
|
||||
os.environ.setdefault("DD_AGENT_HOST", telemetry_settings.datadog_agent_host)
|
||||
os.environ.setdefault("DD_TRACE_AGENT_PORT", str(telemetry_settings.datadog_agent_port))
|
||||
os.environ.setdefault("DD_PROFILING_ENABLED", "true")
|
||||
os.environ.setdefault("DD_PROFILING_MEMORY_ENABLED", str(telemetry_settings.datadog_profiling_memory_enabled).lower())
|
||||
os.environ.setdefault("DD_PROFILING_HEAP_ENABLED", str(telemetry_settings.datadog_profiling_heap_enabled).lower())
|
||||
|
||||
from ddtrace.profiling import Profiler
|
||||
|
||||
# Initialize and start profiler
|
||||
profiler = Profiler(
|
||||
env=dd_env,
|
||||
service=telemetry_settings.datadog_service_name,
|
||||
version=letta_version,
|
||||
)
|
||||
profiler.start()
|
||||
|
||||
# Log Git metadata for source code integration
|
||||
git_info = ""
|
||||
if telemetry_settings.datadog_git_commit_sha:
|
||||
git_info = f", commit={telemetry_settings.datadog_git_commit_sha[:8]}"
|
||||
if telemetry_settings.datadog_git_repository_url:
|
||||
git_info += f", repo={telemetry_settings.datadog_git_repository_url}"
|
||||
|
||||
logger.info(
|
||||
f"Datadog profiling enabled: env={dd_env}, "
|
||||
f"service={telemetry_settings.datadog_service_name}, "
|
||||
f"agent={telemetry_settings.datadog_agent_host}:{telemetry_settings.datadog_agent_port}{git_info}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize Datadog profiling: {e}", exc_info=True)
|
||||
if SENTRY_ENABLED:
|
||||
sentry_sdk.capture_exception(e)
|
||||
# Don't fail application startup if Datadog initialization fails
|
||||
|
||||
debug_mode = "--debug" in sys.argv
|
||||
app = FastAPI(
|
||||
swagger_ui_parameters={"docExpansion": "none"},
|
||||
|
||||
@@ -379,15 +379,52 @@ class TestSettings(Settings):
|
||||
class LogSettings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_prefix="letta_logging_", extra="ignore")
|
||||
debug: bool | None = Field(False, description="Enable debugging for logging")
|
||||
json_logging: bool = Field(False, description="Enable json logging instead of text logging")
|
||||
json_logging: bool = Field(
|
||||
False,
|
||||
description="Enable structured JSON logging (recommended).",
|
||||
)
|
||||
log_level: str | None = Field("WARNING", description="Logging level")
|
||||
letta_log_path: Path | None = Field(Path.home() / ".letta" / "logs" / "Letta.log")
|
||||
verbose_telemetry_logging: bool = Field(False)
|
||||
|
||||
|
||||
class TelemetrySettings(BaseSettings):
|
||||
"""Configuration for telemetry and observability integrations."""
|
||||
|
||||
model_config = SettingsConfigDict(env_prefix="letta_telemetry_", extra="ignore")
|
||||
profiler: bool | None = Field(False, description="Enable use of the profiler.")
|
||||
|
||||
# Google Cloud Profiler
|
||||
profiler: bool | None = Field(False, description="Enable Google Cloud Profiler.")
|
||||
|
||||
# Datadog APM and Profiling
|
||||
enable_datadog: bool | None = Field(False, description="Enable Datadog profiling. Environment is pulled from settings.environment.")
|
||||
datadog_agent_host: str = Field(
|
||||
default="localhost",
|
||||
description="Datadog agent hostname or IP address. Use service name for Kubernetes (e.g., 'datadog-cluster-agent').",
|
||||
)
|
||||
datadog_agent_port: int = Field(default=8126, ge=1, le=65535, description="Datadog trace agent port (typically 8126 for traces).")
|
||||
datadog_service_name: str = Field(default="letta-server", description="Service name for Datadog profiling.")
|
||||
datadog_profiling_memory_enabled: bool = Field(default=True, description="Enable memory profiling in Datadog.")
|
||||
datadog_profiling_heap_enabled: bool = Field(default=True, description="Enable heap profiling in Datadog.")
|
||||
|
||||
# Datadog Source Code Integration (optional, tightly coupled with profiling)
|
||||
# These settings link profiling data and traces to specific Git commits,
|
||||
# enabling code navigation directly from Datadog UI to GitHub/GitLab.
|
||||
datadog_git_repository_url: str | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("DD_GIT_REPOSITORY_URL", "datadog_git_repository_url"),
|
||||
description="Git repository URL (e.g., 'https://github.com/org/repo'). Set at build time.",
|
||||
)
|
||||
datadog_git_commit_sha: str | None = Field(
|
||||
default=None,
|
||||
validation_alias=AliasChoices("DD_GIT_COMMIT_SHA", "datadog_git_commit_sha"),
|
||||
description="Git commit SHA for the deployed code. Set at build time with 'git rev-parse HEAD'.",
|
||||
)
|
||||
datadog_main_package: str = Field(
|
||||
default="letta",
|
||||
validation_alias=AliasChoices("DD_MAIN_PACKAGE", "datadog_main_package"),
|
||||
description="Primary Python package name for source code linking. Datadog uses this setting to determine which code is 'yours' vs. third-party dependencies.",
|
||||
)
|
||||
|
||||
|
||||
# singleton
|
||||
|
||||
@@ -8,15 +8,15 @@ receivers:
|
||||
filelog:
|
||||
include:
|
||||
- /root/.letta/logs/Letta.log
|
||||
multiline:
|
||||
line_start_pattern: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}
|
||||
operators:
|
||||
# Extract timestamp and other fields
|
||||
- type: regex_parser
|
||||
regex: '^(?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+.*'
|
||||
# Parse JSON logs
|
||||
- type: json_parser
|
||||
parse_from: body
|
||||
parse_to: attributes
|
||||
- type: time_parser
|
||||
parse_from: attributes.timestamp
|
||||
layout: '%Y-%m-%d %H:%M:%S,%L'
|
||||
layout_type: gotime
|
||||
layout: '2006-01-02T15:04:05.999999Z07:00'
|
||||
|
||||
processors:
|
||||
memory_limiter:
|
||||
|
||||
@@ -8,15 +8,15 @@ receivers:
|
||||
filelog:
|
||||
include:
|
||||
- /root/.letta/logs/Letta.log
|
||||
multiline:
|
||||
line_start_pattern: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}
|
||||
operators:
|
||||
# Extract timestamp and other fields
|
||||
- type: regex_parser
|
||||
regex: '^(?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\s+.*'
|
||||
# Parse JSON logs
|
||||
- type: json_parser
|
||||
parse_from: body
|
||||
parse_to: attributes
|
||||
- type: time_parser
|
||||
parse_from: attributes.timestamp
|
||||
layout: '%Y-%m-%d %H:%M:%S,%L'
|
||||
layout_type: gotime
|
||||
layout: '2006-01-02T15:04:05.999999Z07:00'
|
||||
|
||||
processors:
|
||||
memory_limiter:
|
||||
|
||||
@@ -89,7 +89,10 @@ pinecone = ["pinecone[asyncio]>=7.3.0"]
|
||||
sqlite = ["aiosqlite>=0.21.0", "sqlite-vec>=0.1.7a2"]
|
||||
|
||||
# ====== Server ======
|
||||
experimental = ["uvloop>=0.21.0", "granian[uvloop,reload]>=2.3.2", "google-cloud-profiler>=4.1.0"]
|
||||
experimental = [
|
||||
"uvloop>=0.21.0",
|
||||
"granian[uvloop,reload]>=2.3.2",
|
||||
]
|
||||
server = [
|
||||
"websockets",
|
||||
"fastapi>=0.115.6",
|
||||
@@ -144,6 +147,10 @@ desktop = [
|
||||
"magika>=0.6.2",
|
||||
#"pgserver>=0.1.4",
|
||||
]
|
||||
profiling = [
|
||||
"ddtrace>=2.18.2",
|
||||
"google-cloud-profiler>=4.1.0",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
|
||||
104
uv.lock
generated
104
uv.lock
generated
@@ -518,6 +518,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b", size = 358517, upload-time = "2024-10-18T12:32:54.066Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecode"
|
||||
version = "0.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/98/c4/4818b392104bd426171fc2ce9c79c8edb4019ba6505747626d0f7107766c/bytecode-0.17.0.tar.gz", hash = "sha256:0c37efa5bd158b1b873f530cceea2c645611d55bd2dc2a4758b09f185749b6fd", size = 105863, upload-time = "2025-09-03T19:55:45.703Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/80/379e685099841f8501a19fb58b496512ef432331fed38276c3938ab09d8e/bytecode-0.17.0-py3-none-any.whl", hash = "sha256:64fb10cde1db7ef5cc39bd414ecebd54ba3b40e1c4cf8121ca5e72f170916ff8", size = 43045, upload-time = "2025-09-03T19:55:43.879Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cachetools"
|
||||
version = "5.5.2"
|
||||
@@ -888,6 +897,55 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/87/22/f020c047ae1346613db9322638186468238bcfa8849b4668a22b97faad65/dateparser-1.2.2-py3-none-any.whl", hash = "sha256:5a5d7211a09013499867547023a2a0c91d5a27d15dd4dbcea676ea9fe66f2482", size = 315453, upload-time = "2025-06-26T09:29:21.412Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ddtrace"
|
||||
version = "3.16.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "bytecode" },
|
||||
{ name = "envier" },
|
||||
{ name = "legacy-cgi", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "wrapt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/35/028fe174ec1a1da8977d4900297f4493a77e93dee1af700f473e692d010e/ddtrace-3.16.2.tar.gz", hash = "sha256:cfef021790635b6dda949e89298b7fed3b5e686c55b46afe9483cebcc0f10a86", size = 7408082, upload-time = "2025-10-21T19:29:32.004Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/7f/55a8753b6ee574b34ee9c3ae48f6b35f4b04de3ef0e4044ad1adb6e7831b/ddtrace-3.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8d644051c265be9865e68274ebbc4a17934a78fc447bf7d6611ecbe49fbe4b7a", size = 6334301, upload-time = "2025-10-21T19:26:27.261Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/a9/a58ae59088f00e237068c4522bb23b12d93e03a9e76cf73f2a357c963533/ddtrace-3.16.2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:9a51665c563f2cc56ccc29f3404e68618bbfd70e60983de239ba8d2edc5ce7e8", size = 6679330, upload-time = "2025-10-21T19:26:28.867Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/48/df6dc3e2b7fff37ad813ddc5651a3e1f8240757b46f464d0e4b3ccf58a11/ddtrace-3.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:527d257f8b020d61f53686fa8791529d1a5b5c33719ed47b28110b8449f14257", size = 7402656, upload-time = "2025-10-21T19:26:30.865Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/d3/377f88a42b9df3bb12fe8c11dfc46548b996dec13abea23fbf0714994a32/ddtrace-3.16.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2eb5a196f74fa5fd8e62105a4faeb4b89e58ed2e00401b182888e407c8d23e94", size = 7668527, upload-time = "2025-10-21T19:26:32.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/01/8ee880b739afb614b2268c5e86cb039d509b3947aa6669ad861130fc62a0/ddtrace-3.16.2-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:59bb645bd5f58465df651e3ae9809bdc2fed339e9c7eae53a41b941d40497508", size = 5521123, upload-time = "2025-10-21T19:26:35.209Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/60/cd88ae82999fe8e532259289f37f5afa08e9fae2204464372cc08859bf60/ddtrace-3.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b2e752daab0206c3abd118621851cc39673f9ed5c2180264ffa4fd147b6351be", size = 8415337, upload-time = "2025-10-21T19:26:37.117Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/7d/5ec01e65bf3a5c022439292e65c23ce80cd0c4726daba8bc7cfa12252665/ddtrace-3.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f9cd3345d686369254e072f049974386f58ee583a24be99862c480d7347819e", size = 6609971, upload-time = "2025-10-21T19:26:39.462Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/1f/8df630beb55734d46f4340144c7350c0c820eb4fedc0d3c38f5a694b4eea/ddtrace-3.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ed11dfc53359e2c0d8aa377ceddd1409520dafc7d41c3e5e3432897160c2b23", size = 8744007, upload-time = "2025-10-21T19:26:41.421Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/eb/70f518a5da3d0b1ca5585e81f3af1ce5119cee9cb4289134ce76d4614ad0/ddtrace-3.16.2-cp311-cp311-win32.whl", hash = "sha256:5c64499f3c2cd906be1f01f880b631157c0a8d4f0b074164efead09c0bd22c6d", size = 5043118, upload-time = "2025-10-21T19:26:43.527Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/29/2a4b0cd621151063912f8919f03cc1f3cbf494097861de73d9c000d8f1b7/ddtrace-3.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:53110eca9026052c37751018e1a2d7ce6631fe54d456ebf92e575e6f75d14781", size = 5603897, upload-time = "2025-10-21T19:26:45.52Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/90/a2f44bdac307ed2f428ac16168d57d601586489e2e31cdb7b8360c5a1981/ddtrace-3.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:0246ccbdf2b4f393410cb798219737fff106161941c4aa9048ce7d812192806c", size = 5326912, upload-time = "2025-10-21T19:26:47.654Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/18/763b25401be47ede7b6118f0470ad081c051e8ed60e8beeed0c2b0f4c7ef/ddtrace-3.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4c3f770eee6085155c52f24e9d14e413977a3ea2eb0f0338e17bf5e87159a11c", size = 6335314, upload-time = "2025-10-21T19:26:50.051Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/3a/4be0d1ad80384b888c0959e0198a6413b5bcfd17da189289f27b487bfa26/ddtrace-3.16.2-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:296c820c6612fbf863534f638c10d811b31b7985cc30c8f20679d4d70249464d", size = 6684784, upload-time = "2025-10-21T19:26:53.557Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/6e/5bc4ec8404a65832dd5f045064f7af41a02183dbd3f7f7c3e13276d75874/ddtrace-3.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:867101dc679c6b77ce77524e434ebe87b22bbece04f10226960fbd38811f4022", size = 7382532, upload-time = "2025-10-21T19:26:55.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/e2/b0b220b76fb90a91c8a322a1511ff6f28f0e7c9f5174bd2492dd28392bfb/ddtrace-3.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:35dce94534d5a13914ca943f4dd718f76c941f50f99dcfab729b0b9ec3587e0a", size = 7656342, upload-time = "2025-10-21T19:26:57.636Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/ad/f9dbfd6be8fb032d087b3362558947bb39a0329a30b84ead30fcf2c9668e/ddtrace-3.16.2-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:975de343cf9c643a5d7b0006d36fe716cdf9957012faea66c1001c6195a964f8", size = 5504371, upload-time = "2025-10-21T19:27:00.054Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/e1/c7375cffa27f4558d2b3e5cba043a9770bce9373f0b9fd2c2441992e7dc9/ddtrace-3.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:053d9311c4db88f91b197209be945694afb360dc12153c9fc9eee676db1c2ea3", size = 8398772, upload-time = "2025-10-21T19:27:02.101Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/3a/3f6eccf9ddf65bc8dd6fef5c94d742df6cbe3a112dab53f60da4fa691420/ddtrace-3.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f3b94723d50ab235608c1e4d216c4ac22dfb9a21a253a488097648e456f1d82b", size = 6588990, upload-time = "2025-10-21T19:27:04.512Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/35/32bdb07845720a2b694495253fb341506deb6b745ed674b5281516824273/ddtrace-3.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b07c930bf83ed54996656faafbe065f96402d73231c7005b97f98cd0f002713a", size = 8731538, upload-time = "2025-10-21T19:27:07.007Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/ad/e6fe3e4316191fa54c1211e553e6ee20aa0f3c148096001c55e74b556c39/ddtrace-3.16.2-cp312-cp312-win32.whl", hash = "sha256:c778dfd7bf839ca94b815fcf1985b390060694806535bdd69641986b76915894", size = 5036303, upload-time = "2025-10-21T19:27:09.755Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/20/3fa392f338cfd22c1c8229e6b260c1ab67a01d6e4507cae3c4de7d720e5b/ddtrace-3.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:3a81183b1681ddc04062dbe990770b50b1062bceb5b1780f2526daa6ecd3a909", size = 5594871, upload-time = "2025-10-21T19:27:11.857Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/65/3d08e2e6ac26e8f016e6ced86c070d200380e7d37c73de7f22986c162be5/ddtrace-3.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:1b74d506e660244f7df29e2cda643f058e591da66ef8d2a71435c78eda3b47ce", size = 5313712, upload-time = "2025-10-21T19:27:14.084Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/2e/a7dde061252cd565f92d627b0c372db2747874bdbc17333f154b2be6bb18/ddtrace-3.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:74c7b6c2ef0043b902c6cd7eda3cad5a866d1251c83f14b8c49abb8e1e67a2b1", size = 6329879, upload-time = "2025-10-21T19:27:21.968Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/ba/d6e486dc27f9ba04be4ad90789dfbceb394ea5960219ed83aef5c7878634/ddtrace-3.16.2-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:adfe6373014b9f37a99d894986c6117b7fb0486d52b4990c2647f93e838c540a", size = 6679188, upload-time = "2025-10-21T19:27:24.339Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/d5/2090abf84fe9cfc941b3a903c638b8157d7a15d016348df6ce7cad733e1c/ddtrace-3.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:66e68846b9b617a1311d8b76c1c5d7bee552cb0af68dc2ccf9af91abc55a74af", size = 7377794, upload-time = "2025-10-21T19:27:26.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/88/07bccc2d9b22ec6114015468772a3451697fcc3c1a39bfb357bdbdfb43e2/ddtrace-3.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6822b1b9cd2f6ad3db4d76a05e22adad21878bcff6bd9ba7b7cd581c9136c00c", size = 7649664, upload-time = "2025-10-21T19:27:29.294Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/e7/433d8d2d5a9614a1adcadf54cf3c21afe151fa714208ff7fd40e3435496c/ddtrace-3.16.2-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:9f4f5adedcfb1f42a02ac7c7370887001ce71826141885da49bb2da39a440125", size = 5498780, upload-time = "2025-10-21T19:27:31.703Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/a1/1339416eeeb39dab87f750038460f922e40681b3ca0089d6c6a5139c00ff/ddtrace-3.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:070cf3f7571a2b8640a6663f476c157b110b3a88b1c7f7941615b746bc4c6c99", size = 8394692, upload-time = "2025-10-21T19:27:34.52Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/24/a380640e605daebfb7791bdcc92bef8d7474ad913807276f9f21117aa323/ddtrace-3.16.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:873a06e21bd00a20d4453cea30bf44e877b657d0cf911aabbf6c8945cfbb31b6", size = 6584925, upload-time = "2025-10-21T19:27:37.209Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/80/6126563c16d9a28cb03f4318bde899e402662e14e97351569640ff833608/ddtrace-3.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:af28ecad6a6379bb5e18979baeb3defe5dea101bc0608e5032a18aa4c38340b2", size = 8727833, upload-time = "2025-10-21T19:27:39.584Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/9c/1b0aa8e0984e3d4f58e7ee9e6a5b938ae45645847f7ae52583fbaff1314e/ddtrace-3.16.2-cp313-cp313-win32.whl", hash = "sha256:a42fc81e7bd6a80c297ee891ac8169a0d1efcdd6b7b0ea5478f3bc3deb1aa8af", size = 5033513, upload-time = "2025-10-21T19:27:44.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/66/dfb088db59b580a6e1ff0a180029ff90dab684b6a60abfe4a5dad0f8e19b/ddtrace-3.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:f61291e94d37ae1de5456e11e1f55a56eda6a622a0b4e6a1e59b481cc87e29ba", size = 5592118, upload-time = "2025-10-21T19:27:47.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/f4/164c40d8cd0392e86ea58194428fa1bd0fff7224ee01d5fa77abe4ae467c/ddtrace-3.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:c3dedde96f9906556c20c76ef0e7f8a2fc24db394b5a095ce6c6dab21facf20f", size = 5311416, upload-time = "2025-10-21T19:27:50.107Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debugpy"
|
||||
version = "1.8.16"
|
||||
@@ -1027,6 +1085,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/f1/135acbaffe4b2e63addecfc2a6c2ecf9ea3e5394aa2a9a829e3eb6f2098d/e2b_code_interpreter-2.0.0-py3-none-any.whl", hash = "sha256:273642d4dd78f09327fb1553fe4f7ddcf17892b78f98236e038d29985e42dca5", size = 12939, upload-time = "2025-08-22T10:16:55.698Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "envier"
|
||||
version = "0.6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/e7/4fe4d3f6e21213cea9bcddc36ba60e6ae4003035f9ce8055e6a9f0322ddb/envier-0.6.1.tar.gz", hash = "sha256:3309a01bb3d8850c9e7a31a5166d5a836846db2faecb79b9cb32654dd50ca9f9", size = 10063, upload-time = "2024-10-22T09:56:47.226Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/56/e9/30493b1cc967f7c07869de4b2ab3929151a58e6bb04495015554d24b61db/envier-0.6.1-py3-none-any.whl", hash = "sha256:73609040a76be48bbcb97074d9969666484aa0de706183a6e9ef773156a8a6a9", size = 10638, upload-time = "2024-10-22T09:56:45.968Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eval-type-backport"
|
||||
version = "0.2.2"
|
||||
@@ -1393,7 +1460,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "google-api-core"
|
||||
version = "2.25.1"
|
||||
version = "2.27.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "google-auth" },
|
||||
@@ -1402,14 +1469,14 @@ dependencies = [
|
||||
{ name = "protobuf" },
|
||||
{ name = "requests" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/dc/21/e9d043e88222317afdbdb567165fdbc3b0aad90064c7e0c9eb0ad9955ad8/google_api_core-2.25.1.tar.gz", hash = "sha256:d2aaa0b13c78c61cb3f4282c464c046e45fbd75755683c9c525e6e8f7ed0a5e8", size = 165443, upload-time = "2025-06-12T20:52:20.439Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/da/99/6c8b44ecc28026fd9441d7fcc5434ee1b3976c491f2f810b464c4702c975/google_api_core-2.27.0.tar.gz", hash = "sha256:d32e2f5dd0517e91037169e75bf0a9783b255aff1d11730517c0b2b29e9db06a", size = 168851, upload-time = "2025-10-22T23:54:14.195Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/4b/ead00905132820b623732b175d66354e9d3e69fcf2a5dcdab780664e7896/google_api_core-2.25.1-py3-none-any.whl", hash = "sha256:8a2a56c1fef82987a524371f99f3bd0143702fecc670c72e600c1cda6bf8dbb7", size = 160807, upload-time = "2025-06-12T20:52:19.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/93/ecf9f7caa99c71e969091e9a78789f11b2dea5c684917eab7c54a8d13560/google_api_core-2.27.0-py3-none-any.whl", hash = "sha256:779a380db4e21a4ee3d717cf8efbf324e53900bf37e1ffb273e5348a9916dd42", size = 167110, upload-time = "2025-10-22T23:54:12.805Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-api-python-client"
|
||||
version = "2.179.0"
|
||||
version = "2.185.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "google-api-core" },
|
||||
@@ -1418,9 +1485,9 @@ dependencies = [
|
||||
{ name = "httplib2" },
|
||||
{ name = "uritemplate" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/73/ed/6e7865324252ea0a9f7c8171a3a00439a1e8447a5dc08e6d6c483777bb38/google_api_python_client-2.179.0.tar.gz", hash = "sha256:76a774a49dd58af52e74ce7114db387e58f0aaf6760c9cf9201ab6d731d8bd8d", size = 13397672, upload-time = "2025-08-13T18:45:28.838Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/5a/6f9b49d67ea91376305fdb8bbf2877c746d756e45fd8fb7d2e32d6dad19b/google_api_python_client-2.185.0.tar.gz", hash = "sha256:aa1b338e4bb0f141c2df26743f6b46b11f38705aacd775b61971cbc51da089c3", size = 13885609, upload-time = "2025-10-17T15:00:35.623Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/d4/2568d5d907582cc145f3ffede43879746fd4b331308088a0fc57f7ecdbca/google_api_python_client-2.179.0-py3-none-any.whl", hash = "sha256:79ab5039d70c59dab874fd18333fca90fb469be51c96113cb133e5fc1f0b2a79", size = 13955142, upload-time = "2025-08-13T18:45:25.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/28/be3b17bd6a190c8c2ec9e4fb65d43e6ecd7b7a1bb19ccc1d9ab4f687a58c/google_api_python_client-2.185.0-py3-none-any.whl", hash = "sha256:00fe173a4b346d2397fbe0d37ac15368170dfbed91a0395a66ef2558e22b93fc", size = 14453595, upload-time = "2025-10-17T15:00:33.176Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1771,14 +1838,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "httplib2"
|
||||
version = "0.22.0"
|
||||
version = "0.31.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyparsing" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/ad/2371116b22d616c194aa25ec410c9c6c37f23599dcd590502b74db197584/httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81", size = 351116, upload-time = "2023-03-21T22:29:37.214Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/52/77/6653db69c1f7ecfe5e3f9726fdadc981794656fcd7d98c4209fecfea9993/httplib2-0.31.0.tar.gz", hash = "sha256:ac7ab497c50975147d4f7b1ade44becc7df2f8954d42b38b3d69c515f531135c", size = 250759, upload-time = "2025-09-11T12:16:03.403Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/6c/d2fbdaaa5959339d53ba38e94c123e4e84b8fbc4b84beb0e70d7c1608486/httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc", size = 96854, upload-time = "2023-03-21T22:29:35.683Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/a2/0d269db0f6163be503775dc8b6a6fa15820cc9fdc866f6ba608d86b721f2/httplib2-0.31.0-py3-none-any.whl", hash = "sha256:b9cd78abea9b4e43a7714c6e0f8b6b8561a6fc1e95d5dbd367f5bf0ef35f5d24", size = 91148, upload-time = "2025-09-11T12:16:01.803Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2308,6 +2375,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/73/91a506e17bb1bc6d20c2c04cf7b459dc58951bfbfe7f97f2c952646b4500/langsmith-0.4.18-py3-none-any.whl", hash = "sha256:ad63154f503678356aadf5b999f40393b4bbd332aee2d04cde3e431c61f2e1c2", size = 376444, upload-time = "2025-08-26T17:00:03.564Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "legacy-cgi"
|
||||
version = "2.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a6/ed/300cabc9693209d5a03e2ebc5eb5c4171b51607c08ed84a2b71c9015e0f3/legacy_cgi-2.6.3.tar.gz", hash = "sha256:4c119d6cb8e9d8b6ad7cc0ddad880552c62df4029622835d06dfd18f438a8154", size = 24401, upload-time = "2025-03-27T00:48:56.957Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/33/68c6c38193684537757e0d50a7ccb4f4656e5c2f7cd2be737a9d4a1bff71/legacy_cgi-2.6.3-py3-none-any.whl", hash = "sha256:6df2ea5ae14c71ef6f097f8b6372b44f6685283dc018535a75c924564183cdab", size = 19851, upload-time = "2025-03-27T00:48:55.366Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "letta"
|
||||
version = "0.12.1"
|
||||
@@ -2413,7 +2489,6 @@ dev = [
|
||||
{ name = "pytest-order" },
|
||||
]
|
||||
experimental = [
|
||||
{ name = "google-cloud-profiler" },
|
||||
{ name = "granian", extra = ["reload", "uvloop"] },
|
||||
{ name = "uvloop" },
|
||||
]
|
||||
@@ -2438,6 +2513,10 @@ postgres = [
|
||||
{ name = "psycopg2" },
|
||||
{ name = "psycopg2-binary" },
|
||||
]
|
||||
profiling = [
|
||||
{ name = "ddtrace" },
|
||||
{ name = "google-cloud-profiler" },
|
||||
]
|
||||
redis = [
|
||||
{ name = "redis" },
|
||||
]
|
||||
@@ -2468,6 +2547,7 @@ requires-dist = [
|
||||
{ name = "certifi", specifier = ">=2025.6.15" },
|
||||
{ name = "colorama", specifier = ">=0.4.6" },
|
||||
{ name = "datamodel-code-generator", extras = ["http"], specifier = ">=0.25.0" },
|
||||
{ name = "ddtrace", marker = "extra == 'profiling'", specifier = ">=2.18.2" },
|
||||
{ name = "demjson3", specifier = ">=3.0.6" },
|
||||
{ name = "docker", marker = "extra == 'desktop'", specifier = ">=7.1.0" },
|
||||
{ name = "docker", marker = "extra == 'external-tools'", specifier = ">=7.1.0" },
|
||||
@@ -2478,7 +2558,7 @@ requires-dist = [
|
||||
{ name = "faker", specifier = ">=36.1.0" },
|
||||
{ name = "fastapi", marker = "extra == 'desktop'", specifier = ">=0.115.6" },
|
||||
{ name = "fastapi", marker = "extra == 'server'", specifier = ">=0.115.6" },
|
||||
{ name = "google-cloud-profiler", marker = "extra == 'experimental'", specifier = ">=4.1.0" },
|
||||
{ name = "google-cloud-profiler", marker = "extra == 'profiling'", specifier = ">=4.1.0" },
|
||||
{ name = "google-genai", specifier = ">=1.15.0" },
|
||||
{ name = "granian", extras = ["uvloop", "reload"], marker = "extra == 'experimental'", specifier = ">=2.3.2" },
|
||||
{ name = "grpcio", specifier = ">=1.68.1" },
|
||||
@@ -2564,7 +2644,7 @@ requires-dist = [
|
||||
{ name = "wikipedia", marker = "extra == 'desktop'", specifier = ">=1.4.0" },
|
||||
{ name = "wikipedia", marker = "extra == 'external-tools'", specifier = ">=1.4.0" },
|
||||
]
|
||||
provides-extras = ["postgres", "redis", "pinecone", "sqlite", "experimental", "server", "bedrock", "dev", "cloud-tool-sandbox", "modal", "external-tools", "desktop"]
|
||||
provides-extras = ["postgres", "redis", "pinecone", "sqlite", "experimental", "server", "bedrock", "dev", "cloud-tool-sandbox", "modal", "external-tools", "desktop", "profiling"]
|
||||
|
||||
[[package]]
|
||||
name = "letta-client"
|
||||
|
||||
Reference in New Issue
Block a user