diff --git a/Dockerfile.allinone b/Dockerfile.allinone index a51e31814..6bcf78459 100644 --- a/Dockerfile.allinone +++ b/Dockerfile.allinone @@ -216,10 +216,6 @@ RUN pip install --no-cache-dir playwright \ && playwright install chromium \ && rm -rf /root/.cache/ms-playwright/ffmpeg* -# Install Microsandbox (optional secure code execution for deep agent). -# Requires --device /dev/kvm at runtime. Enable via MICROSANDBOX_ENABLED=TRUE. -RUN curl -sSL https://get.microsandbox.dev | sh || true - # Copy backend source COPY surfsense_backend/ ./ @@ -264,10 +260,9 @@ ENV NEXT_PUBLIC_FASTAPI_BACKEND_URL=http://localhost:8000 ENV NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE=LOCAL ENV NEXT_PUBLIC_ETL_SERVICE=DOCLING -# Microsandbox (optional - requires --device /dev/kvm and --privileged at runtime) -ENV MICROSANDBOX_ENABLED=FALSE -ENV MICROSANDBOX_SERVER_URL=http://localhost:5555 -# MICROSANDBOX_API_KEY is intentionally unset; set at runtime for production. +# Daytona Sandbox (cloud code execution — no local server needed) +ENV DAYTONA_SANDBOX_ENABLED=FALSE +# DAYTONA_API_KEY, DAYTONA_API_URL, DAYTONA_TARGET: set at runtime for production. # Electric SQL configuration (ELECTRIC_DATABASE_URL is built dynamically by entrypoint from these values) ENV ELECTRIC_DB_USER=electric @@ -283,8 +278,8 @@ ENV NEXT_PUBLIC_ELECTRIC_AUTH_MODE=insecure # Data volume VOLUME ["/data"] -# Expose ports (Frontend: 3000, Backend: 8000, Electric: 5133, Microsandbox: 5555) -EXPOSE 3000 8000 5133 5555 +# Expose ports (Frontend: 3000, Backend: 8000, Electric: 5133) +EXPOSE 3000 8000 5133 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \ diff --git a/docker-compose.yml b/docker-compose.yml index 942a3de09..50abb8548 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -65,14 +65,14 @@ services: - ELECTRIC_DB_PASSWORD=${ELECTRIC_DB_PASSWORD:-electric_password} - AUTH_TYPE=${AUTH_TYPE:-LOCAL} - NEXT_FRONTEND_URL=${NEXT_FRONTEND_URL:-http://localhost:3000} - # Microsandbox – uncomment when microsandbox service is enabled - # - MICROSANDBOX_ENABLED=TRUE - # - MICROSANDBOX_SERVER_URL=http://microsandbox:5555 - # - MICROSANDBOX_API_KEY=${MICROSANDBOX_API_KEY:-} + # Daytona Sandbox – uncomment and set credentials to enable cloud code execution + # - DAYTONA_SANDBOX_ENABLED=TRUE + # - DAYTONA_API_KEY=${DAYTONA_API_KEY:-} + # - DAYTONA_API_URL=${DAYTONA_API_URL:-https://app.daytona.io/api} + # - DAYTONA_TARGET=${DAYTONA_TARGET:-us} depends_on: - db - redis - # - microsandbox # Run these services separately in production # celery_worker: @@ -129,43 +129,6 @@ services: # - redis # - celery_worker - # ============================================================ - # Microsandbox (optional - secure code execution for deep agent) - # ============================================================ - # Requires a Linux host with KVM support (/dev/kvm). - # To enable: - # 1. Uncomment this service - # 2. Set MICROSANDBOX_ENABLED=TRUE in surfsense_backend/.env - # 3. Run with: docker compose up -d - # The first sandbox creation will pull the OCI image (e.g. microsandbox/python), - # so the initial run takes a bit longer. - # - microsandbox: - image: ubuntu:22.04 - ports: - - "${MICROSANDBOX_PORT:-5555}:5555" - volumes: - - microsandbox_data:/root/.microsandbox - privileged: true - devices: - - /dev/kvm:/dev/kvm - entrypoint: ["/bin/bash", "-c"] - command: - - | - set -e - export PATH="$$HOME/.local/bin:$$PATH" - if ! command -v msb &>/dev/null; then - apt-get update && apt-get install -y --no-install-recommends curl ca-certificates libdigest-sha-perl - curl -sSL https://get.microsandbox.dev | sh - fi - exec msb server start --dev --host 0.0.0.0 - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5555/health"] - interval: 10s - timeout: 5s - retries: 5 - electric: image: electricsql/electric:latest ports: @@ -207,4 +170,3 @@ volumes: pgadmin_data: redis_data: shared_temp: - microsandbox_data: diff --git a/scripts/docker/entrypoint-allinone.sh b/scripts/docker/entrypoint-allinone.sh index 9ca653979..7c232a079 100644 --- a/scripts/docker/entrypoint-allinone.sh +++ b/scripts/docker/entrypoint-allinone.sh @@ -42,17 +42,6 @@ if [ -z "$STT_SERVICE" ]; then echo "✅ Using default STT_SERVICE: local/base" fi -# ================================================ -# Microsandbox (optional secure sandbox server) -# ================================================ -if [ "${MICROSANDBOX_ENABLED:-FALSE}" = "TRUE" ]; then - export MICROSANDBOX_AUTOSTART=true - echo "✅ Microsandbox enabled (requires --device /dev/kvm)" -else - export MICROSANDBOX_AUTOSTART=false - echo "ℹ️ Microsandbox disabled (set MICROSANDBOX_ENABLED=TRUE to enable)" -fi - # ================================================ # Set Electric SQL configuration # ================================================ @@ -243,7 +232,7 @@ echo " Auth Type: ${NEXT_PUBLIC_FASTAPI_BACKEND_AUTH_TYPE}" echo " ETL Service: ${NEXT_PUBLIC_ETL_SERVICE}" echo " TTS Service: ${TTS_SERVICE}" echo " STT Service: ${STT_SERVICE}" -echo " Microsandbox: ${MICROSANDBOX_ENABLED:-FALSE}" +echo " Daytona Sandbox: ${DAYTONA_SANDBOX_ENABLED:-FALSE}" echo "===========================================" echo "" diff --git a/scripts/docker/supervisor-allinone.conf b/scripts/docker/supervisor-allinone.conf index 2a0c4fe81..1a21fcc04 100644 --- a/scripts/docker/supervisor-allinone.conf +++ b/scripts/docker/supervisor-allinone.conf @@ -114,23 +114,8 @@ stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 environment=NODE_ENV="production",PORT="3000",HOSTNAME="0.0.0.0" -# Microsandbox (secure code execution sandbox server) -# Autostart is controlled by the entrypoint based on MICROSANDBOX_ENABLED env var. -# Requires --device /dev/kvm and --privileged when running the container. -[program:microsandbox] -command=msb server start --dev --host 0.0.0.0 -autostart=%(ENV_MICROSANDBOX_AUTOSTART)s -autorestart=true -priority=25 -startsecs=5 -startretries=3 -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 - # Process Groups [group:surfsense] -programs=postgresql,redis,electric,backend,celery-worker,celery-beat,frontend,microsandbox +programs=postgresql,redis,electric,backend,celery-worker,celery-beat,frontend priority=999 diff --git a/surfsense_backend/app/agents/new_chat/chat_deepagent.py b/surfsense_backend/app/agents/new_chat/chat_deepagent.py index dbb1d4b4a..5fcb8236d 100644 --- a/surfsense_backend/app/agents/new_chat/chat_deepagent.py +++ b/surfsense_backend/app/agents/new_chat/chat_deepagent.py @@ -169,7 +169,7 @@ async def create_surfsense_deep_agent( These are always added regardless of enabled/disabled settings. firecrawl_api_key: Optional Firecrawl API key for premium web scraping. Falls back to Chromium/Trafilatura if not provided. - sandbox_backend: Optional sandbox backend (e.g. MicrosandboxBackend) for + sandbox_backend: Optional sandbox backend (e.g. DaytonaSandbox) for secure code execution. When provided, the agent gets an isolated ``execute`` tool for running shell commands. diff --git a/surfsense_backend/app/agents/new_chat/sandbox.py b/surfsense_backend/app/agents/new_chat/sandbox.py index 84ba9fac1..959ec6949 100644 --- a/surfsense_backend/app/agents/new_chat/sandbox.py +++ b/surfsense_backend/app/agents/new_chat/sandbox.py @@ -1,130 +1,89 @@ """ -Microsandbox provider for SurfSense deep agent. +Daytona sandbox provider for SurfSense deep agent. Manages the lifecycle of sandboxed code execution environments. -Each conversation thread gets its own isolated sandbox instance. +Each conversation thread gets its own isolated sandbox instance +via the Daytona cloud API, identified by labels. """ from __future__ import annotations +import asyncio import logging import os +from daytona import CreateSandboxFromSnapshotParams, Daytona, DaytonaConfig +from langchain_daytona import DaytonaSandbox + logger = logging.getLogger(__name__) -# --------------------------------------------------------------------------- -# Compatibility shim -# --------------------------------------------------------------------------- -# deepagents-microsandbox imports SandboxInfo, SandboxListResponse, and -# SandboxProvider from deepagents.backends.sandbox. These types were added -# in a fork and have not yet landed in the official deepagents package. -# We inject minimal stubs so the import succeeds without patching the venv. -# --------------------------------------------------------------------------- - -def _ensure_sandbox_provider_types() -> None: - """Inject missing SandboxProvider / SandboxInfo types if absent.""" - import importlib - sandbox_mod = importlib.import_module("deepagents.backends.sandbox") - - if hasattr(sandbox_mod, "SandboxProvider"): - return # Already present – nothing to do. - - from abc import ABC, abstractmethod - from dataclasses import dataclass, field - from typing import Any, Generic, TypeVar - - _M = TypeVar("_M") - - @dataclass - class SandboxInfo(Generic[_M]): - sandbox_id: str - metadata: _M = field(default_factory=dict) # type: ignore[assignment] - - @dataclass - class SandboxListResponse(Generic[_M]): - items: list[SandboxInfo[_M]] = field(default_factory=list) - cursor: str | None = None - - class SandboxProvider(ABC, Generic[_M]): - @abstractmethod - def list(self, *, cursor: str | None = None, **kwargs: Any) -> SandboxListResponse[_M]: ... - - @abstractmethod - async def alist(self, *, cursor: str | None = None, **kwargs: Any) -> SandboxListResponse[_M]: ... - - @abstractmethod - def get_or_create(self, *, sandbox_id: str | None = None, **kwargs: Any) -> Any: ... - - @abstractmethod - async def aget_or_create(self, *, sandbox_id: str | None = None, **kwargs: Any) -> Any: ... - - @abstractmethod - def delete(self, *, sandbox_id: str, **kwargs: Any) -> None: ... - - @abstractmethod - async def adelete(self, *, sandbox_id: str, **kwargs: Any) -> None: ... - - sandbox_mod.SandboxInfo = SandboxInfo # type: ignore[attr-defined] - sandbox_mod.SandboxListResponse = SandboxListResponse # type: ignore[attr-defined] - sandbox_mod.SandboxProvider = SandboxProvider # type: ignore[attr-defined] - - -_ensure_sandbox_provider_types() - -from deepagents_microsandbox import MicrosandboxBackend, MicrosandboxProvider # noqa: E402 - -_provider: MicrosandboxProvider | None = None +_daytona_client: Daytona | None = None +THREAD_LABEL_KEY = "surfsense_thread" def is_sandbox_enabled() -> bool: - return os.environ.get("MICROSANDBOX_ENABLED", "FALSE").upper() == "TRUE" + return os.environ.get("DAYTONA_SANDBOX_ENABLED", "FALSE").upper() == "TRUE" -def _get_provider() -> MicrosandboxProvider: - global _provider - if _provider is None: - server_url = os.environ.get( - "MICROSANDBOX_SERVER_URL", "http://127.0.0.1:5555" +def _get_client() -> Daytona: + global _daytona_client + if _daytona_client is None: + config = DaytonaConfig( + api_key=os.environ.get("DAYTONA_API_KEY", ""), + api_url=os.environ.get("DAYTONA_API_URL", "https://app.daytona.io/api"), + target=os.environ.get("DAYTONA_TARGET", "us"), ) - api_key = os.environ.get("MICROSANDBOX_API_KEY") - _provider = MicrosandboxProvider( - server_url=server_url, - api_key=api_key, - namespace="surfsense", + _daytona_client = Daytona(config) + return _daytona_client + + +def _find_or_create(thread_id: str) -> DaytonaSandbox: + """Find an existing sandbox for *thread_id*, or create a new one.""" + client = _get_client() + labels = {THREAD_LABEL_KEY: thread_id} + + try: + sandbox = client.find_one(labels=labels) + logger.info("Reusing existing sandbox: %s", sandbox.id) + except Exception: + sandbox = client.create( + CreateSandboxFromSnapshotParams(language="python", labels=labels) ) - return _provider + logger.info("Created new sandbox: %s", sandbox.id) + + return DaytonaSandbox(sandbox=sandbox) -async def get_or_create_sandbox(thread_id: int | str) -> MicrosandboxBackend: +async def get_or_create_sandbox(thread_id: int | str) -> DaytonaSandbox: """Get or create a sandbox for a conversation thread. - Uses the thread_id as the sandbox name so the same sandbox persists + Uses the thread_id as a label so the same sandbox persists across multiple messages within the same conversation. Args: thread_id: The conversation thread identifier. Returns: - MicrosandboxBackend connected to the sandbox. + DaytonaSandbox connected to the sandbox. """ - provider = _get_provider() - sandbox_name = f"thread-{thread_id}" - sandbox = await provider.aget_or_create( - sandbox_id=sandbox_name, - timeout=120, - memory=512, - cpus=1.0, - ) - logger.info("Sandbox ready: %s", sandbox.id) - return sandbox + return await asyncio.to_thread(_find_or_create, str(thread_id)) async def delete_sandbox(thread_id: int | str) -> None: """Delete the sandbox for a conversation thread.""" - provider = _get_provider() - sandbox_name = f"thread-{thread_id}" - try: - await provider.adelete(sandbox_id=sandbox_name) - logger.info("Sandbox deleted: surfsense/%s", sandbox_name) - except Exception: - logger.warning("Failed to delete sandbox surfsense/%s", sandbox_name, exc_info=True) + + def _delete() -> None: + client = _get_client() + labels = {THREAD_LABEL_KEY: str(thread_id)} + try: + sandbox = client.find_one(labels=labels) + client.delete(sandbox) + logger.info("Sandbox deleted: %s", sandbox.id) + except Exception: + logger.warning( + "Failed to delete sandbox for thread %s", + thread_id, + exc_info=True, + ) + + await asyncio.to_thread(_delete) diff --git a/surfsense_backend/pyproject.toml b/surfsense_backend/pyproject.toml index f9359c9b5..1319f4519 100644 --- a/surfsense_backend/pyproject.toml +++ b/surfsense_backend/pyproject.toml @@ -66,8 +66,7 @@ dependencies = [ "pypandoc_binary>=1.16.2", "typst>=0.14.0", "deepagents>=0.4.3", - "deepagents-microsandbox>=1.0.1", - "microsandbox>=0.1.8", + "langchain-daytona>=0.0.2", ] [dependency-groups] diff --git a/surfsense_backend/uv.lock b/surfsense_backend/uv.lock index ef3d0fbe0..c6ee66d89 100644 --- a/surfsense_backend/uv.lock +++ b/surfsense_backend/uv.lock @@ -49,11 +49,11 @@ wheels = [ [[package]] name = "aiofiles" -version = "25.1.0" +version = "24.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668 }, + { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896 }, ] [[package]] @@ -111,6 +111,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/1d/18ef37549901db94717d4389eb7be807acbfbdeab48a73ff2993fc909118/aiohttp-3.10.11-cp313-cp313-win_amd64.whl", hash = "sha256:4996ff1345704ffdd6d75fb06ed175938c133425af616142e7187f28dc75f14e", size = 378073 }, ] +[[package]] +name = "aiohttp-retry" +version = "2.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981 }, +] + [[package]] name = "aiolimiter" version = "1.2.1" @@ -1240,6 +1252,98 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/22/f020c047ae1346613db9322638186468238bcfa8849b4668a22b97faad65/dateparser-1.2.2-py3-none-any.whl", hash = "sha256:5a5d7211a09013499867547023a2a0c91d5a27d15dd4dbcea676ea9fe66f2482", size = 315453 }, ] +[[package]] +name = "daytona" +version = "0.145.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles" }, + { name = "daytona-api-client" }, + { name = "daytona-api-client-async" }, + { name = "daytona-toolbox-api-client" }, + { name = "daytona-toolbox-api-client-async" }, + { name = "deprecated" }, + { name = "environs" }, + { name = "httpx" }, + { name = "multipart" }, + { name = "obstore" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, + { name = "opentelemetry-instrumentation-aiohttp-client" }, + { name = "opentelemetry-sdk" }, + { name = "pydantic" }, + { name = "toml" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/ff/d0c4d6295c7da4e32fa7ea7d4b319f9c9ac22023448dfb45ce160bd1d807/daytona-0.145.0.tar.gz", hash = "sha256:717ba4b59732839eec6c8d97b7069520129f7ebaea32d643e99a049dfcf69671", size = 125342 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/5b/66f790ef3188718f2e42abb562af212454c278120c0407880542ad5689d3/daytona-0.145.0-py3-none-any.whl", hash = "sha256:2f0ed0384ea6b662fb3c8dacd21c6bb91f0c138161f654034a4d8666030e8118", size = 155401 }, +] + +[[package]] +name = "daytona-api-client" +version = "0.145.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d0/f4/2a75eb88a32d0da2a53be703daf7f02a1a5fe3332844ac84712701109880/daytona_api_client-0.145.0.tar.gz", hash = "sha256:40e6be54c5fe23cb9884629b1ac948d6528262d635f540990e51c50830b04526", size = 140299 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/18/47cc59737237a34f6a6d2df361251f7512b8a199ed995c8c1f3d543efd18/daytona_api_client-0.145.0-py3-none-any.whl", hash = "sha256:578e2c7e6af72a2c36a8de55f9c6539ba192faf1e1e1037906b05350cb369f0e", size = 393463 }, +] + +[[package]] +name = "daytona-api-client-async" +version = "0.145.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiohttp-retry" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/98/fcd1c3f23843c3c7b5bdd6a6d56289e6c6f14d5a1026878f3a45cdd6712f/daytona_api_client_async-0.145.0.tar.gz", hash = "sha256:bb78da16e445e0d5eed59368737290abfe9073e04a19885fcc71e32bd452eb69", size = 140342 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/98/4d97c5b27b14464dcfecdffe41e9f6f9df8fc020f020021814be81942090/daytona_api_client_async-0.145.0-py3-none-any.whl", hash = "sha256:2b3a98588f89ecb2d948d705f1ed847fd5d69abb1185e2b75461ee0b75ee25f9", size = 396425 }, +] + +[[package]] +name = "daytona-toolbox-api-client" +version = "0.145.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/12/4d565376366376d7e767e69d87a0bd82593ca41c5168a0acbebcde48155d/daytona_toolbox_api_client-0.145.0.tar.gz", hash = "sha256:a1cb9f1a4ed699fee8cd0cb11d6d452d238d3c1ccf04c8452b4b77db7c223622", size = 64785 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/74/865219b984d78d3b4df8cf4806d2d29426c7b9c24d9f82b5b55766905621/daytona_toolbox_api_client-0.145.0-py3-none-any.whl", hash = "sha256:d1418a207ff46a1fb48bd511d28a93336f0a2b6b2c1a7c8d0b218f4c08f8b2b3", size = 174400 }, +] + +[[package]] +name = "daytona-toolbox-api-client-async" +version = "0.145.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "aiohttp-retry" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/ab/63acd0e6fb0e2d8f4c9e3d9f94782f15ae2fa6d91dac6e165f949fb92ce7/daytona_toolbox_api_client_async-0.145.0.tar.gz", hash = "sha256:070876471653e4f54af0a5e6c2d56d10b298ce4c24d62c635e57b80713501ee2", size = 61835 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/ca/48fcdc463376bd0f317c6dfb28511d0f49d241dfa95c012ca3a27912d8fa/daytona_toolbox_api_client_async-0.145.0-py3-none-any.whl", hash = "sha256:fa2b0ab87f4a4f9e243a5c2906bdf6829a56c6c30f474dcb9f28adfcfa29d263", size = 175774 }, +] + [[package]] name = "deepagents" version = "0.4.3" @@ -1256,19 +1360,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/58/f8/c076a841b68cc13d89c395cc97965b37751ed008691a304119efa0f5717e/deepagents-0.4.3-py3-none-any.whl", hash = "sha256:298d19c5c0b4c6fc6a74b68049a7bfea0ba481aece7201ab21e7172b71ee61b9", size = 94882 }, ] -[[package]] -name = "deepagents-microsandbox" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deepagents" }, - { name = "microsandbox" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8d/d5/77562772b7bf868478e5e3badb4f66e60171c6b740be4cf9fd5ffa0c37e5/deepagents_microsandbox-1.0.1.tar.gz", hash = "sha256:b9471f251597fc56b9b2bc5f41a478cd6b87db2641a1e91210978b4abeeb1600", size = 140696 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/e5/7fc618dfa08d60a954bf3b13cb9c765ecb37cd3ad8c2174171dcbff8b00b/deepagents_microsandbox-1.0.1-py3-none-any.whl", hash = "sha256:8173ce8dbdf290a0fb5bf83f204814b587470ba9b93fcdad8980ca85e46604b1", size = 9736 }, -] - [[package]] name = "defusedxml" version = "0.7.1" @@ -1602,6 +1693,19 @@ wheels = [ { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl", hash = "sha256:1932429db727d4bff3deed6b34cfc05df17794f4a52eeb26cf8928f7c1a0fb85" }, ] +[[package]] +name = "environs" +version = "14.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "marshmallow" }, + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/75/06801d5beeb398ed3903167af9376bb81c4ac41c44a53d45193065ebb1a8/environs-14.5.0.tar.gz", hash = "sha256:f7b8f6fcf3301bc674bc9c03e39b5986d116126ffb96764efd34c339ed9464ee", size = 35426 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/f3/6961beb9a1e77d01dee1dd48f00fb3064429c8abcfa26aa863eb7cb2b6dd/environs-14.5.0-py3-none-any.whl", hash = "sha256:1abd3e3a5721fb09797438d6c902bc2f35d4580dfaffe68b8ee588b67b504e13", size = 17202 }, +] + [[package]] name = "espeakng-loader" version = "0.2.4" @@ -3052,6 +3156,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/71/41/fe6ae9065b866b1397adbfc98db5e1648e8dcd78126b8e1266fcbe2d6395/langchain_core-1.2.14-py3-none-any.whl", hash = "sha256:b349ca28c057ac1f9b5280ea091bddb057db24d0f1c3c89bbb590713e1715838", size = 501411 }, ] +[[package]] +name = "langchain-daytona" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "daytona" }, + { name = "deepagents" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/f1/0440d3bf4c49ca7e07dd42a5756bc73500b4a41e49ba49c15b9c8f927eb0/langchain_daytona-0.0.2.tar.gz", hash = "sha256:0a849a4a27776434c9c29d40d3c2161f6e6354bcd30e11014c72023dc94107f5", size = 188358 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/92/1d3af3134e79bb0f19b9c12bdf987b0e786084b948584c51b9328cd3cf2a/langchain_daytona-0.0.2-py3-none-any.whl", hash = "sha256:cc3cf13cc7c2558f22cc255ffed3be6726e860756e15232799524b7ec0f92091", size = 4065 }, +] + [[package]] name = "langchain-google-genai" version = "4.2.1" @@ -3711,20 +3828,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] -[[package]] -name = "microsandbox" -version = "0.1.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "frozenlist" }, - { name = "python-dotenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bf/ad/200f7d89d9ae6f6066ee71e2dff3b3becece1858e8d795f8cc8a66c94516/microsandbox-0.1.8.tar.gz", hash = "sha256:38eac3310f05a238fc49c27cd9c6064a767ccb6f8a53c118b7ecfccb5df58b7a", size = 8949 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/89/2d6653e4c6bfa535da59d84d7c8bcc1678b35299ed43c1d11fb1c07a2179/microsandbox-0.1.8-py3-none-any.whl", hash = "sha256:b4503f6efd0f58e1acbac782399d3020cc704031279637fe5c60bdb5da267cd8", size = 12112 }, -] - [[package]] name = "misaki" version = "0.9.4" @@ -4021,6 +4124,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/d8/45e8fc9892a7386d074941429e033adb4640e59ff0780d96a8cf46fe788e/multidict-6.5.0-py3-none-any.whl", hash = "sha256:5634b35f225977605385f56153bd95a7133faffc0ffe12ad26e10517537e8dfc", size = 12181 }, ] +[[package]] +name = "multipart" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/c9/c6f5ab81bae667d4fe42a58df29f4c2db6ad8377cfd0e9baa729e4fa3ebb/multipart-1.3.0.tar.gz", hash = "sha256:a46bd6b0eb4c1ba865beb88ddd886012a3da709b6e7b86084fc37e99087e5cf1", size = 38816 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/d6/d547a7004b81fa0b2aafa143b09196f6635e4105cd9d2c641fa8a4051c05/multipart-1.3.0-py3-none-any.whl", hash = "sha256:439bf4b00fd7cb2dbff08ae13f49f4f49798931ecd8d496372c63537fa19f304", size = 14938 }, +] + [[package]] name = "multiprocess" version = "0.70.16" @@ -4387,6 +4499,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/3d/760b1456010ed11ce87c0109007f0166078dfdada7597f0091ae76eb7305/oauthlib-3.3.0-py3-none-any.whl", hash = "sha256:a2b3a0a2a4ec2feb4b9110f56674a39b2cc2f23e14713f4ed20441dfba14e934", size = 165155 }, ] +[[package]] +name = "obstore" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/8c/9ec984edd0f3b72226adfaa19b1c61b15823b35b52f311ca4af36d009d15/obstore-0.8.2.tar.gz", hash = "sha256:a467bc4e97169e2ba749981b4fd0936015428d9b8f3fb83a5528536b1b6f377f", size = 168852 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/dc/60fefbb5736e69eab56657bca04ca64dc07fdeccb3814164a31b62ad066b/obstore-0.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bb70ce297a47392b1d9a3e310f18d59cd5ebbb9453428210fef02ed60e4d75d1", size = 3612955 }, + { url = "https://files.pythonhosted.org/packages/d2/8b/844e8f382e5a12b8a3796a05d76a03e12c7aedc13d6900419e39207d7868/obstore-0.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1619bf618428abf1f607e0b219b2e230a966dcf697b717deccfa0983dd91f646", size = 3346564 }, + { url = "https://files.pythonhosted.org/packages/89/73/8537f99e09a38a54a6a15ede907aa25d4da089f767a808f0b2edd9c03cec/obstore-0.8.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a4605c3ed7c9515aeb4c619b5f7f2c9986ed4a79fe6045e536b5e59b804b1476", size = 3460809 }, + { url = "https://files.pythonhosted.org/packages/b4/99/7714dec721e43f521d6325a82303a002cddad089437640f92542b84e9cc8/obstore-0.8.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce42670417876dd8668cbb8659e860e9725e5f26bbc86449fd259970e2dd9d18", size = 3692081 }, + { url = "https://files.pythonhosted.org/packages/ec/bd/4ac4175fe95a24c220a96021c25c432bcc0c0212f618be0737184eebbaad/obstore-0.8.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a3e893b2a06585f651c541c1972fe1e3bf999ae2a5fda052ee55eb7e6516f5", size = 3957466 }, + { url = "https://files.pythonhosted.org/packages/4e/04/caa288fb735484fc5cb019bdf3d896eaccfae0ac4622e520d05692c46790/obstore-0.8.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08462b32f95a9948ed56ed63e88406e2e5a4cae1fde198f9682e0fb8487100ed", size = 3951293 }, + { url = "https://files.pythonhosted.org/packages/44/2f/d380239da2d6a1fda82e17df5dae600a404e8a93a065784518ff8325d5f6/obstore-0.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a0bf7763292a8fc47d01cd66e6f19002c5c6ad4b3ed4e6b2729f5e190fa8a0d", size = 3766199 }, + { url = "https://files.pythonhosted.org/packages/28/41/d391be069d3da82969b54266948b2582aeca5dd735abeda4d63dba36e07b/obstore-0.8.2-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:bcd47f8126cb192cbe86942b8f73b1c45a651ce7e14c9a82c5641dfbf8be7603", size = 3529678 }, + { url = "https://files.pythonhosted.org/packages/b9/4c/4862fdd1a3abde459ee8eea699b1797df638a460af235b18ca82c8fffb72/obstore-0.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:57eda9fd8c757c3b4fe36cf3918d7e589cc1286591295cc10b34122fa36dd3fd", size = 3698079 }, + { url = "https://files.pythonhosted.org/packages/68/ca/014e747bc53b570059c27e3565b2316fbe5c107d4134551f4cd3e24aa667/obstore-0.8.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ea44442aad8992166baa69f5069750979e4c5d9ffce772e61565945eea5774b9", size = 3687154 }, + { url = "https://files.pythonhosted.org/packages/6f/89/6db5f8edd93028e5b8bfbeee15e6bd3e56f72106107d31cb208b57659de4/obstore-0.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:41496a3ab8527402db4142aaaf0d42df9d7d354b13ba10d9c33e0e48dd49dd96", size = 3773444 }, + { url = "https://files.pythonhosted.org/packages/26/e5/c9e2cc540689c873beb61246e1615d6e38301e6a34dec424f5a5c63c1afd/obstore-0.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43da209803f052df96c7c3cbec512d310982efd2407e4a435632841a51143170", size = 3939315 }, + { url = "https://files.pythonhosted.org/packages/4d/c9/bb53280ca50103c1ffda373cdc9b0f835431060039c2897cbc87ddd92e42/obstore-0.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:1836f5dcd49f9f2950c75889ab5c51fb290d3ea93cdc39a514541e0be3af016e", size = 3978234 }, + { url = "https://files.pythonhosted.org/packages/f0/5d/8c3316cc958d386d5e6ab03e9db9ddc27f8e2141cee4a6777ae5b92f3aac/obstore-0.8.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:212f033e53fe6e53d64957923c5c88949a400e9027f7038c705ec2e9038be563", size = 3612027 }, + { url = "https://files.pythonhosted.org/packages/ea/4d/699359774ce6330130536d008bfc32827fab0c25a00238d015a5974a3d1d/obstore-0.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bee21fa4ba148d08fa90e47a96df11161661ed31e09c056a373cb2154b0f2852", size = 3344686 }, + { url = "https://files.pythonhosted.org/packages/82/37/55437341f10512906e02fd9fa69a8a95ad3f2f6a916d3233fda01763d110/obstore-0.8.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4c66594b59832ff1ced4c72575d9beb8b5f9b4e404ac1150a42bfb226617fd50", size = 3459860 }, + { url = "https://files.pythonhosted.org/packages/7a/51/4245a616c94ee4851965e33f7a563ab4090cc81f52cc73227ff9ceca2e46/obstore-0.8.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:089f33af5c2fe132d00214a0c1f40601b28f23a38e24ef9f79fb0576f2730b74", size = 3691648 }, + { url = "https://files.pythonhosted.org/packages/4e/f1/4e2fb24171e3ca3641a4653f006be826e7e17634b11688a5190553b00b83/obstore-0.8.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d87f658dfd340d5d9ea2d86a7c90d44da77a0db9e00c034367dca335735110cf", size = 3956867 }, + { url = "https://files.pythonhosted.org/packages/42/f5/b703115361c798c9c1744e1e700d5908d904a8c2e2bd38bec759c9ffb469/obstore-0.8.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e2e4fa92828c4fbc2d487f3da2d3588701a1b67d9f6ca3c97cc2afc912e9c63", size = 3950599 }, + { url = "https://files.pythonhosted.org/packages/53/20/08c6dc0f20c1394e2324b9344838e4e7af770cdcb52c30757a475f50daeb/obstore-0.8.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab440e89c5c37a8ec230857dd65147d4b923e0cada33297135d05e0f937d696a", size = 3765865 }, + { url = "https://files.pythonhosted.org/packages/77/20/77907765e29b2eba6bd8821872284d91170d7084f670855b2dfcb249ea14/obstore-0.8.2-cp313-cp313-manylinux_2_24_aarch64.whl", hash = "sha256:b9beed107c5c9cd995d4a73263861fcfbc414d58773ed65c14f80eb18258a932", size = 3529807 }, + { url = "https://files.pythonhosted.org/packages/a5/f5/f629d39cc30d050f52b1bf927e4d65c1cc7d7ffbb8a635cd546b5c5219a0/obstore-0.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b75b4e7746292c785e31edcd5aadc8b758238372a19d4c5e394db5c305d7d175", size = 3693629 }, + { url = "https://files.pythonhosted.org/packages/30/ff/106763fd10f2a1cb47f2ef1162293c78ad52f4e73223d8d43fc6b755445d/obstore-0.8.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f33e6c366869d05ab0b7f12efe63269e631c5450d95d6b4ba4c5faf63f69de70", size = 3686176 }, + { url = "https://files.pythonhosted.org/packages/ce/0c/d2ccb6f32feeca906d5a7c4255340df5262af8838441ca06c9e4e37b67d5/obstore-0.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:12c885a9ce5ceb09d13cc186586c0c10b62597eff21b985f6ce8ff9dab963ad3", size = 3773081 }, + { url = "https://files.pythonhosted.org/packages/fa/79/40d1cc504cefc89c9b3dd8874287f3fddc7d963a8748d6dffc5880222013/obstore-0.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4accc883b93349a81c9931e15dd318cc703b02bbef2805d964724c73d006d00e", size = 3938589 }, + { url = "https://files.pythonhosted.org/packages/14/dd/916c6777222db3271e9fb3cf9a97ed92b3a9b3e465bdeec96de9ab809d53/obstore-0.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:ec850adf9980e5788a826ccfd5819989724e2a2f712bfa3258e85966c8d9981e", size = 3977768 }, + { url = "https://files.pythonhosted.org/packages/f1/61/66f8dc98bbf5613bbfe5bf21747b4c8091442977f4bd897945895ab7325c/obstore-0.8.2-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:1431e40e9bb4773a261e51b192ea6489d0799b9d4d7dbdf175cdf813eb8c0503", size = 3623364 }, + { url = "https://files.pythonhosted.org/packages/1a/66/6d527b3027e42f625c8fc816ac7d19b0d6228f95bfe7666e4d6b081d2348/obstore-0.8.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ddb39d4da303f50b959da000aa42734f6da7ac0cc0be2d5a7838b62c97055bb9", size = 3347764 }, + { url = "https://files.pythonhosted.org/packages/0d/79/c00103302b620192ea447a948921ad3fed031ce3d19e989f038e1183f607/obstore-0.8.2-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e01f4e13783db453e17e005a4a3ceff09c41c262e44649ba169d253098c775e8", size = 3460981 }, + { url = "https://files.pythonhosted.org/packages/3d/d9/bfe4ed4b1aebc45b56644dd5b943cf8e1673505cccb352e66878a457e807/obstore-0.8.2-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df0fc2d0bc17caff9b538564ddc26d7616f7e8b7c65b1a3c90b5048a8ad2e797", size = 3692711 }, + { url = "https://files.pythonhosted.org/packages/13/47/cd6c2cbb18e1f40c77e7957a4a03d2d83f1859a2e876a408f1ece81cad4c/obstore-0.8.2-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e439d06c99a140348f046c9f598ee349cc2dcd9105c15540a4b231f9cc48bbae", size = 3958362 }, + { url = "https://files.pythonhosted.org/packages/3d/ea/5ee82bf23abd71c7d6a3f2d008197ae8f8f569d41314c26a8f75318245be/obstore-0.8.2-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e37d9046669fcc59522d0faf1d105fcbfd09c84cccaaa1e809227d8e030f32c", size = 3957082 }, + { url = "https://files.pythonhosted.org/packages/cb/ee/46650405e50fdaa8d95f30375491f9c91fac9517980e8a28a4a6af66927f/obstore-0.8.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2646fdcc4bbe92dc2bb5bcdff15574da1211f5806c002b66d514cee2a23c7cb8", size = 3775539 }, + { url = "https://files.pythonhosted.org/packages/35/d6/348a7ebebe2ca3d94dfc75344ea19675ae45472823e372c1852844078307/obstore-0.8.2-cp314-cp314-manylinux_2_24_aarch64.whl", hash = "sha256:e31a7d37675056d93dfc244605089dee67f5bba30f37c88436623c8c5ad9ba9d", size = 3535048 }, + { url = "https://files.pythonhosted.org/packages/41/07/b7a16cc0da91a4b902d47880ad24016abfe7880c63f7cdafda45d89a2f91/obstore-0.8.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:656313dd8170dde0f0cd471433283337a63912e8e790a121f7cc7639c83e3816", size = 3699035 }, + { url = "https://files.pythonhosted.org/packages/7f/74/3269a3a58347e0b019742d888612c4b765293c9c75efa44e144b1e884c0d/obstore-0.8.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:329038c9645d6d1741e77fe1a53e28a14b1a5c1461cfe4086082ad39ebabf981", size = 3687307 }, + { url = "https://files.pythonhosted.org/packages/01/f9/4fd4819ad6a49d2f462a45be453561f4caebded0dc40112deeffc34b89b1/obstore-0.8.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1e4df99b369790c97c752d126b286dc86484ea49bff5782843a265221406566f", size = 3776076 }, + { url = "https://files.pythonhosted.org/packages/14/dd/7c4f958fa0b9fc4778fb3d232e38b37db8c6b260f641022fbba48b049d7e/obstore-0.8.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9e1c65c65e20cc990414a8a9af88209b1bbc0dd9521b5f6b0293c60e19439bb7", size = 3947445 }, +] + [[package]] name = "olefile" version = "0.47" @@ -4566,6 +4727,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/a3/cc9b66575bd6597b98b886a2067eea2693408d2d5f39dad9ab7fc264f5f3/opentelemetry_exporter_otlp_proto_grpc-1.39.1-py3-none-any.whl", hash = "sha256:fa1c136a05c7e9b4c09f739469cbdb927ea20b34088ab1d959a849b5cc589c18", size = 19766 }, ] +[[package]] +name = "opentelemetry-exporter-otlp-proto-http" +version = "1.39.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/04/2a08fa9c0214ae38880df01e8bfae12b067ec0793446578575e5080d6545/opentelemetry_exporter_otlp_proto_http-1.39.1.tar.gz", hash = "sha256:31bdab9745c709ce90a49a0624c2bd445d31a28ba34275951a6a362d16a0b9cb", size = 17288 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl", hash = "sha256:d9f5207183dd752a412c4cd564ca8875ececba13be6e9c6c370ffb752fd59985", size = 19641 }, +] + +[[package]] +name = "opentelemetry-instrumentation" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "packaging" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/0f/7e6b713ac117c1f5e4e3300748af699b9902a2e5e34c9cf443dde25a01fa/opentelemetry_instrumentation-0.60b1.tar.gz", hash = "sha256:57ddc7974c6eb35865af0426d1a17132b88b2ed8586897fee187fd5b8944bd6a", size = 31706 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl", hash = "sha256:04480db952b48fb1ed0073f822f0ee26012b7be7c3eac1a3793122737c78632d", size = 33096 }, +] + +[[package]] +name = "opentelemetry-instrumentation-aiohttp-client" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-http" }, + { name = "wrapt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/79/95be90c555fd7efde79dcba36ea5c668815aa2d0a4250b63687e0f91c74a/opentelemetry_instrumentation_aiohttp_client-0.60b1.tar.gz", hash = "sha256:d0e7d5aa057791ca4d9090b0d3c9982f253c1a24b6bc78a734fc18d8dd97927b", size = 15907 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/f4/1a1ec632c86269750ae833c8fbdd4c8d15316eb1c21e3544e34791c805ee/opentelemetry_instrumentation_aiohttp_client-0.60b1-py3-none-any.whl", hash = "sha256:34c5097256a30b16c5a2a88a409ed82b92972a494c43212c85632d204a78c2a1", size = 12694 }, +] + [[package]] name = "opentelemetry-proto" version = "1.39.1" @@ -4606,6 +4816,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982 }, ] +[[package]] +name = "opentelemetry-util-http" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/fc/c47bb04a1d8a941a4061307e1eddfa331ed4d0ab13d8a9781e6db256940a/opentelemetry_util_http-0.60b1.tar.gz", hash = "sha256:0d97152ca8c8a41ced7172d29d3622a219317f74ae6bb3027cfbdcf22c3cc0d6", size = 11053 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl", hash = "sha256:66381ba28550c91bee14dcba8979ace443444af1ed609226634596b4b0faf199", size = 8947 }, +] + [[package]] name = "orjson" version = "3.10.18" @@ -6867,7 +7086,6 @@ dependencies = [ { name = "composio" }, { name = "datasets" }, { name = "deepagents" }, - { name = "deepagents-microsandbox" }, { name = "discord-py" }, { name = "docling" }, { name = "elasticsearch" }, @@ -6885,6 +7103,7 @@ dependencies = [ { name = "kokoro" }, { name = "langchain" }, { name = "langchain-community" }, + { name = "langchain-daytona" }, { name = "langchain-litellm" }, { name = "langchain-unstructured" }, { name = "langgraph" }, @@ -6895,7 +7114,6 @@ dependencies = [ { name = "markdown" }, { name = "markdownify" }, { name = "mcp" }, - { name = "microsandbox" }, { name = "notion-client" }, { name = "numpy" }, { name = "pgvector" }, @@ -6940,7 +7158,6 @@ requires-dist = [ { name = "composio", specifier = ">=0.10.9" }, { name = "datasets", specifier = ">=2.21.0" }, { name = "deepagents", specifier = ">=0.4.3" }, - { name = "deepagents-microsandbox", specifier = ">=1.0.1" }, { name = "discord-py", specifier = ">=2.5.2" }, { name = "docling", specifier = ">=2.15.0" }, { name = "elasticsearch", specifier = ">=9.1.1" }, @@ -6958,6 +7175,7 @@ requires-dist = [ { name = "kokoro", specifier = ">=0.9.4" }, { name = "langchain", specifier = ">=1.2.6" }, { name = "langchain-community", specifier = ">=0.3.31" }, + { name = "langchain-daytona", specifier = ">=0.0.2" }, { name = "langchain-litellm", specifier = ">=0.3.5" }, { name = "langchain-unstructured", specifier = ">=1.0.1" }, { name = "langgraph", specifier = ">=1.0.5" }, @@ -6968,7 +7186,6 @@ requires-dist = [ { name = "markdown", specifier = ">=3.7" }, { name = "markdownify", specifier = ">=0.14.1" }, { name = "mcp", specifier = ">=1.25.0" }, - { name = "microsandbox", specifier = ">=0.1.8" }, { name = "notion-client", specifier = ">=2.3.0" }, { name = "numpy", specifier = ">=1.24.0" }, { name = "pgvector", specifier = ">=0.3.6" }, @@ -7176,6 +7393,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/b6/072a8e053ae600dcc2ac0da81a23548e3b523301a442a6ca900e92ac35be/tokenizers-0.21.1-cp39-abi3-win_amd64.whl", hash = "sha256:0f0dcbcc9f6e13e675a66d7a5f2f225a736745ce484c1a4e07476a89ccdad382", size = 2435481 }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, +] + [[package]] name = "torch" version = "2.7.1" diff --git a/surfsense_web/components/tool-ui/sandbox-execute.tsx b/surfsense_web/components/tool-ui/sandbox-execute.tsx index 0dd853218..4cb3ba63c 100644 --- a/surfsense_web/components/tool-ui/sandbox-execute.tsx +++ b/surfsense_web/components/tool-ui/sandbox-execute.tsx @@ -148,7 +148,8 @@ function ExecuteResult({ parsed: ParsedOutput; }) { const [open, setOpen] = useState(false); - const hasOutput = parsed.output.trim().length > 0; + const isLongCommand = command.length > 80 || command.includes("\n"); + const hasContent = parsed.output.trim().length > 0 || isLongCommand; const exitBadge = useMemo(() => { if (parsed.exitCode === null) return null; @@ -180,13 +181,13 @@ function ExecuteResult({ open && "rounded-b-none border-b-0", parsed.isError && "border-destructive/20" )} - disabled={!hasOutput} + disabled={!hasContent} > @@ -199,15 +200,34 @@ function ExecuteResult({
-
-							{parsed.output}
-						
+ {isLongCommand && ( +
+

+ Command +

+
+									{command}
+								
+
+ )} + {parsed.output.trim().length > 0 && ( +
+ {isLongCommand && ( +

+ Output +

+ )} +
+									{parsed.output}
+								
+
+ )} {parsed.truncated && ( -

+

Output was truncated due to size limits

)}