Skip to content
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Empty file removed dimos/__init__.py
Empty file.
8 changes: 3 additions & 5 deletions dimos/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from dataclasses import dataclass
import json
from queue import Empty, Queue
from threading import Event, RLock, Thread
Expand All @@ -31,14 +30,13 @@
from dimos.core.module import Module, ModuleConfig, SkillInfo
from dimos.core.rpc_client import RpcCall, RPCClient
from dimos.core.stream import In, Out
from dimos.protocol.rpc import RPCSpec
from dimos.protocol.rpc.spec import RPCSpec
from dimos.spec.utils import Spec

if TYPE_CHECKING:
from langchain_core.language_models import BaseChatModel


@dataclass
class AgentConfig(ModuleConfig):
system_prompt: str | None = SYSTEM_PROMPT
model: str = "gpt-4o"
Expand All @@ -58,8 +56,8 @@ class Agent(Module[AgentConfig]):
_thread: Thread
_stop_event: Event

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self._lock = RLock()
self._state_graph = None
self._message_queue = Queue()
Expand Down
19 changes: 13 additions & 6 deletions dimos/agents/agent_test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,36 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from collections.abc import Iterable
from threading import Event, Thread
from typing import Any

from langchain_core.messages import AIMessage
from langchain_core.messages.base import BaseMessage
from reactivex.disposable import Disposable

from dimos.agents.agent import AgentSpec
from dimos.core.core import rpc
from dimos.core.module import Module
from dimos.core.module import Module, ModuleConfig
from dimos.core.rpc_client import RPCClient
from dimos.core.stream import In, Out


class AgentTestRunner(Module):
class Config(ModuleConfig):
messages: Iterable[BaseMessage]


class AgentTestRunner(Module[Config]):
default_config = Config

agent_spec: AgentSpec
agent: In[BaseMessage]
agent_idle: In[bool]
finished: Out[bool]
added: Out[bool]

def __init__(self, messages: list[BaseMessage]) -> None:
super().__init__()
self._messages = messages
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self._idle_event = Event()
self._subscription_ready = Event()
self._thread = Thread(target=self._thread_loop, daemon=True)
Expand Down Expand Up @@ -71,7 +78,7 @@ def _thread_loop(self) -> None:
if not self._subscription_ready.wait(5):
raise TimeoutError("Timed out waiting for subscription to be ready.")

for message in self._messages:
for message in self.config.messages:
self._idle_event.clear()
self.agent_spec.add_message(message)
if not self._idle_event.wait(60):
Expand Down
2 changes: 1 addition & 1 deletion dimos/agents/demo_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

from dimos.agents.agent import Agent
from dimos.core.blueprints import autoconnect
from dimos.hardware.sensors.camera import zed
from dimos.hardware.sensors.camera.module import camera_module
from dimos.hardware.sensors.camera.webcam import Webcam
from dimos.hardware.sensors.camera.zed import compat as zed

demo_agent = autoconnect(Agent.blueprint())

Expand Down
Empty file removed dimos/agents/mcp/__init__.py
Empty file.
20 changes: 0 additions & 20 deletions dimos/agents/mcp/mcp_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@ def __init__(self, url: str | None = None, timeout: int = DEFAULT_TIMEOUT) -> No
self.url = url
self.timeout = timeout

# ------------------------------------------------------------------
# Low-level JSON-RPC
# ------------------------------------------------------------------

def call(self, method: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
"""Send a JSON-RPC request and return the parsed response.

Expand All @@ -87,10 +83,6 @@ def call(self, method: str, params: dict[str, Any] | None = None) -> dict[str, A
raise McpError(f"HTTP {resp.status_code}: {e}") from e
return resp.json() # type: ignore[no-any-return]

# ------------------------------------------------------------------
# MCP standard methods
# ------------------------------------------------------------------

def initialize(self) -> dict[str, Any]:
"""Send ``initialize`` and return server info."""
return self.call("initialize")
Expand All @@ -112,10 +104,6 @@ def call_tool_text(self, name: str, arguments: dict[str, Any] | None = None) ->
return ""
return content[0].get("text", str(content[0])) # type: ignore[no-any-return]

# ------------------------------------------------------------------
# Readiness probes
# ------------------------------------------------------------------

def wait_for_ready(self, timeout: float = 10.0, interval: float = 0.5) -> bool:
"""Poll until the MCP server responds, or return False on timeout."""
deadline = time.monotonic() + timeout
Expand Down Expand Up @@ -148,10 +136,6 @@ def wait_for_down(self, timeout: float = 10.0, interval: float = 0.5) -> bool:
time.sleep(interval)
return False

# ------------------------------------------------------------------
# Class methods for discovery
# ------------------------------------------------------------------

@classmethod
def from_run_entry(cls, entry: Any | None = None, timeout: int = DEFAULT_TIMEOUT) -> McpAdapter:
"""Create an adapter from a RunEntry, or discover the latest one.
Expand All @@ -173,10 +157,6 @@ def from_run_entry(cls, entry: Any | None = None, timeout: int = DEFAULT_TIMEOUT
url = f"http://localhost:{global_config.mcp_port}/mcp"
return cls(url=url, timeout=timeout)

# ------------------------------------------------------------------
# Internals
# ------------------------------------------------------------------

@staticmethod
def _unwrap(response: dict[str, Any]) -> dict[str, Any]:
"""Extract the ``result`` from a JSON-RPC response, raising on error."""
Expand Down
6 changes: 2 additions & 4 deletions dimos/agents/mcp/mcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from dataclasses import dataclass
from queue import Empty, Queue
from threading import Event, RLock, Thread
import time
Expand All @@ -39,7 +38,6 @@
logger = setup_logger()


@dataclass
class McpClientConfig(ModuleConfig):
system_prompt: str | None = SYSTEM_PROMPT
model: str = "gpt-4o"
Expand All @@ -62,8 +60,8 @@ class McpClient(Module[McpClientConfig]):
_http_client: httpx.Client
_seq_ids: SequentialIds

def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self._lock = RLock()
self._state_graph = None
self._message_queue = Queue()
Expand Down
35 changes: 6 additions & 29 deletions dimos/agents/mcp/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from __future__ import annotations

import asyncio
import concurrent.futures
import json
import os
import time
Expand All @@ -22,7 +23,7 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from starlette.requests import Request # noqa: TC002
from starlette.requests import Request
from starlette.responses import Response
import uvicorn

Expand All @@ -32,14 +33,11 @@
from dimos.core.rpc_client import RpcCall, RPCClient
from dimos.utils.logging_config import setup_logger

logger = setup_logger()


if TYPE_CHECKING:
import concurrent.futures

from dimos.core.module import SkillInfo

logger = setup_logger()


app = FastAPI()
app.add_middleware(
Expand All @@ -52,11 +50,6 @@
app.state.rpc_calls = {}


# ---------------------------------------------------------------------------
# JSON-RPC helpers
# ---------------------------------------------------------------------------


def _jsonrpc_result(req_id: Any, result: Any) -> dict[str, Any]:
return {"jsonrpc": "2.0", "id": req_id, "result": result}

Expand All @@ -69,11 +62,6 @@ def _jsonrpc_error(req_id: Any, code: int, message: str) -> dict[str, Any]:
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": code, "message": message}}


# ---------------------------------------------------------------------------
# JSON-RPC handlers (standard MCP protocol only)
# ---------------------------------------------------------------------------


def _handle_initialize(req_id: Any) -> dict[str, Any]:
return _jsonrpc_result(
req_id,
Expand Down Expand Up @@ -179,16 +167,9 @@ async def mcp_endpoint(request: Request) -> Response:
return JSONResponse(result)


# ---------------------------------------------------------------------------
# McpServer Module
# ---------------------------------------------------------------------------


class McpServer(Module):
def __init__(self) -> None:
super().__init__()
self._uvicorn_server: uvicorn.Server | None = None
self._serve_future: concurrent.futures.Future[None] | None = None
_uvicorn_server: uvicorn.Server | None = None
_serve_future: concurrent.futures.Future[None] | None = None

@rpc
def start(self) -> None:
Expand Down Expand Up @@ -219,10 +200,6 @@ def on_system_modules(self, modules: list[RPCClient]) -> None:
for skill_info in app.state.skills
}

# ------------------------------------------------------------------
# Introspection skills (exposed as MCP tools via tools/list)
# ------------------------------------------------------------------

@skill
def server_status(self) -> str:
"""Get MCP server status: main process PID, deployed modules, and skill count."""
Expand Down
13 changes: 6 additions & 7 deletions dimos/agents/mcp/test_mcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Any

from langchain_core.messages import HumanMessage
import pytest

from dimos.agents.annotation import skill
from dimos.core.module import Module
from dimos.msgs.sensor_msgs import Image
from dimos.msgs.sensor_msgs.Image import Image
from dimos.utils.data import get_data


Expand All @@ -40,10 +41,8 @@ def test_can_call_tool(agent_setup):


class UserRegistration(Module):
def __init__(self):
super().__init__()
self._first_call = True
self._use_upper = False
_first_call = True
_use_upper = False

@skill
def register_user(self, name: str) -> str:
Expand Down Expand Up @@ -79,8 +78,8 @@ def test_can_call_again_on_error(agent_setup):


class MultipleTools(Module):
def __init__(self):
super().__init__()
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
self._people = {"Ben": "office", "Bob": "garage"}

@skill
Expand Down
2 changes: 1 addition & 1 deletion dimos/agents/skills/demo_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from dimos.core.module import Module
from dimos.core.stream import Out
from dimos.mapping.types import LatLon
from dimos.mapping.models import LatLon


class DemoRobot(Module):
Expand Down
6 changes: 3 additions & 3 deletions dimos/agents/skills/google_maps_skill_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from dimos.core.module import Module
from dimos.core.stream import In
from dimos.mapping.google_maps.google_maps import GoogleMaps
from dimos.mapping.types import LatLon
from dimos.mapping.models import LatLon
from dimos.utils.logging_config import setup_logger

logger = setup_logger()
Expand All @@ -32,8 +32,8 @@ class GoogleMapsSkillContainer(Module):

gps_location: In[LatLon]

def __init__(self) -> None:
super().__init__()
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
try:
self._client = GoogleMaps()
except ValueError:
Expand Down
5 changes: 1 addition & 4 deletions dimos/agents/skills/gps_nav_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from dimos.core.module import Module
from dimos.core.rpc_client import RpcCall
from dimos.core.stream import In, Out
from dimos.mapping.types import LatLon
from dimos.mapping.models import LatLon
from dimos.mapping.utils.distance import distance_in_meters
from dimos.utils.logging_config import setup_logger

Expand All @@ -34,9 +34,6 @@ class GpsNavSkillContainer(Module):
gps_location: In[LatLon]
gps_goal: Out[LatLon]

def __init__(self) -> None:
super().__init__()

@rpc
def start(self) -> None:
super().start()
Expand Down
11 changes: 6 additions & 5 deletions dimos/agents/skills/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
from dimos.core.module import Module
from dimos.core.stream import In
from dimos.models.qwen.bbox import BBox
from dimos.msgs.geometry_msgs import PoseStamped, Quaternion, Vector3
from dimos.msgs.geometry_msgs.Vector3 import make_vector3
from dimos.msgs.sensor_msgs import Image
from dimos.msgs.geometry_msgs.PoseStamped import PoseStamped
from dimos.msgs.geometry_msgs.Quaternion import Quaternion
from dimos.msgs.geometry_msgs.Vector3 import Vector3, make_vector3
from dimos.msgs.sensor_msgs.Image import Image
from dimos.navigation.base import NavigationState
from dimos.navigation.visual.query import get_object_bbox_from_image
from dimos.types.robot_location import RobotLocation
Expand Down Expand Up @@ -55,8 +56,8 @@ class NavigationSkillContainer(Module):
color_image: In[Image]
odom: In[PoseStamped]

def __init__(self) -> None:
super().__init__()
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self._skill_started = False

# Here to prevent unwanted imports in the file.
Expand Down
2 changes: 1 addition & 1 deletion dimos/agents/skills/osm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
from dimos.agents.annotation import skill
from dimos.core.module import Module
from dimos.core.stream import In
from dimos.mapping.models import LatLon
from dimos.mapping.osm.current_location_map import CurrentLocationMap
from dimos.mapping.types import LatLon
from dimos.mapping.utils.distance import distance_in_meters
from dimos.models.vl.qwen import QwenVlModel
from dimos.utils.logging_config import setup_logger
Expand Down
Loading
Loading