Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions libs/code/deepagents_code/server_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,14 @@

if TYPE_CHECKING:
from collections.abc import Awaitable, Callable, Mapping
from contextlib import AbstractContextManager

from deepagents.backends.composite import CompositeBackend

EnvironmentContext = Callable[
[Mapping[str, str] | None], AbstractContextManager[None]
]

from deepagents_code.config import CredentialsSnapshot
from deepagents_code.extensions.registry import ExtensionRegistry
from deepagents_code.offload_middleware import OffloadOperation
Expand Down Expand Up @@ -257,12 +262,6 @@ async def _make_graphs(
offload operation bound to that backend.
"""
config = config_override or ServerConfig.from_env()
from deepagents_code.config import (
Credentials,
_preview_dotenv_environ,
use_environment,
)

workspace_path = (
project_context_override.user_cwd
if project_context_override is not None
Expand All @@ -278,15 +277,25 @@ async def _make_graphs(
# rejects when invoked directly from the server loop (see issue #5043),
# for the same reason as the offload in `_make_graphs_in_environment`.
def _resolve_workspace_environment() -> tuple[
Mapping[str, str], CredentialsSnapshot
Mapping[str, str], CredentialsSnapshot, EnvironmentContext
]:
from deepagents_code.config import (
Credentials,
_preview_dotenv_environ,
use_environment,
)

environ = MappingProxyType(_preview_dotenv_environ(start_path=workspace_path))
return environ, Credentials.snapshot_from_environment(
start_path=workspace_path,
environ=environ,
return (
environ,
Credentials.snapshot_from_environment(
start_path=workspace_path,
environ=environ,
),
use_environment,
)

workspace_env, workspace_credentials = await asyncio.to_thread(
workspace_env, workspace_credentials, use_environment = await asyncio.to_thread(
_resolve_workspace_environment
)

Expand Down
47 changes: 46 additions & 1 deletion libs/code/tests/unit_tests/test_server_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@

import importlib
import os
import subprocess
import sys
from types import ModuleType, SimpleNamespace
from typing import Any
from typing import TYPE_CHECKING, Any
from unittest.mock import AsyncMock, MagicMock, Mock, patch

import pytest

from deepagents_code._env_vars import SERVER_ENV_PREFIX
from deepagents_code._server_config import ServerConfig

if TYPE_CHECKING:
from pathlib import Path


@pytest.fixture(autouse=True)
def _disable_extensions(monkeypatch: pytest.MonkeyPatch) -> None:
Expand Down Expand Up @@ -84,6 +88,47 @@ async def build() -> object:
assert calls == 1
assert results == [graph_obj, graph_obj, graph_obj]

def test_config_bootstrap_runs_off_the_blockbuster_loop(
self, tmp_path: Path
) -> None:
"""Profile validation must not block the server event loop."""
profile = tmp_path / "profile"
profile.mkdir()
env = os.environ.copy()
env["DEEPAGENTS_HOME"] = str(profile)
env.pop("DEEPAGENTS_HOME_IS_DEFAULT", None)
code = """
import asyncio
from unittest.mock import AsyncMock, patch
from blockbuster import blockbuster_ctx
from deepagents_code._server_config import ServerConfig
import deepagents_code.server_graph as module

async def main():
runtime = module.ServerRuntime(object(), object(), object())
with patch.object(
module,
"_make_graphs_in_environment",
new=AsyncMock(return_value=runtime),
):
with blockbuster_ctx():
assert await module._make_graphs(
config_override=ServerConfig(no_mcp=True)
) is runtime

asyncio.run(main())
"""

process = subprocess.run(
[sys.executable, "-c", code],
env=env,
check=False,
capture_output=True,
text=True,
)

assert process.returncode == 0, process.stderr

def test_criteria_context_tools_use_identity_allowlist_in_tool_order(self) -> None:
"""Criteria tools should be known context objects in main-tool order."""
module = _import_fresh_server_graph()
Expand Down
Loading