Skip to content
Merged
31 changes: 29 additions & 2 deletions dimos/agents2/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
)

from dimos.agents2.spec import AgentSpec
from dimos.agents2.system_prompt import get_system_prompt
from dimos.core import rpc
from dimos.msgs.sensor_msgs import Image
from dimos.protocol.skill.coordinator import SkillCoordinator, SkillState, SkillStateDict
Expand Down Expand Up @@ -178,6 +179,8 @@ def __init__(
else:
self.config.system_prompt.content += SYSTEM_MSG_APPEND
self.system_message = self.config.system_prompt
else:
self.system_message = SystemMessage(get_system_prompt() + SYSTEM_MSG_APPEND)

self.publish(self.system_message)

Expand Down Expand Up @@ -263,6 +266,7 @@ def _get_state() -> str:
# we are getting tools from the coordinator on each turn
# since this allows for skillcontainers to dynamically provide new skills
tools = self.get_tools()
print("Available tools:", [tool.name for tool in tools])
self._llm = self._llm.bind_tools(tools)

# publish to /agent topic for observability
Expand Down Expand Up @@ -331,8 +335,14 @@ def query(self, query: str):
async def query_async(self, query: str):
return await self.agent_loop(query)

def register_skills(self, container):
return self.coordinator.register_skills(container)
@rpc
def register_skills(self, container, run_implicit_name: str | None = None):
ret = self.coordinator.register_skills(container)

if run_implicit_name:
self.run_implicit_skill(run_implicit_name)

return ret

def get_tools(self):
return self.coordinator.get_tools()
Expand All @@ -346,3 +356,20 @@ def _write_debug_history_file(self):

with open(file_path, "w") as f:
json.dump(history, f, default=lambda x: repr(x), indent=2)


class LlmAgent(Agent):
@rpc
def start(self) -> None:
super().start()
self.loop_thread()

@rpc
def stop(self) -> None:
super().stop()


llm_agent = LlmAgent.blueprint


__all__ = ["Agent", "llm_agent"]
17 changes: 15 additions & 2 deletions dimos/agents2/cli/human.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
import queue

from dimos.agents2 import Output, Reducer, Stream, skill
from dimos.core import Module, pLCMTransport, rpc
from dimos.core import pLCMTransport, rpc
from reactivex.disposable import Disposable

from dimos.core.module import Module
from dimos.core.rpc_client import RpcCall


class HumanInput(Module):
running: bool = False

@skill(stream=Stream.call_agent, reducer=Reducer.string, output=Output.human)
@skill(stream=Stream.call_agent, reducer=Reducer.string, output=Output.human, hide_skill=True)
def human(self):
"""receives human input, no need to run this, it's running implicitly"""
if self.running:
Expand All @@ -43,3 +46,13 @@ def start(self) -> None:
@rpc
def stop(self) -> None:
super().stop()

@rpc
def set_LlmAgent_register_skills(self, callable: RpcCall) -> None:
callable.set_rpc(self.rpc)
callable(self, run_implicit_name="human")


human_input = HumanInput.blueprint

__all__ = ["HumanInput", "human_input"]
20 changes: 14 additions & 6 deletions dimos/agents2/skills/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
from dimos.agents2.skills.gps_nav_skill import GpsNavSkillContainer
from dimos.agents2.skills.navigation import NavigationSkillContainer
from dimos.agents2.skills.google_maps_skill_container import GoogleMapsSkillContainer
from dimos.agents2.system_prompt import get_system_prompt
from dimos.mapping.types import LatLon
from dimos.robot.robot import GpsRobot
from dimos.robot.unitree_webrtc.run_agents2 import SYSTEM_PROMPT
from dimos.utils.data import get_data
from dimos.msgs.sensor_msgs import Image


system_prompt = get_system_prompt()


@pytest.fixture(autouse=True)
def cleanup_threadpool_scheduler(monkeypatch):
# TODO: get rid of this global threadpool
Expand All @@ -42,11 +45,13 @@ def cleanup_threadpool_scheduler(monkeypatch):
threadpool.scheduler = ThreadPoolScheduler(max_workers=threadpool.get_max_workers())


# TODO: Delete
@pytest.fixture
def fake_robot(mocker):
return mocker.MagicMock()


# TODO: Delete
@pytest.fixture
def fake_gps_robot(mocker):
return mocker.Mock(spec=GpsRobot)
Expand All @@ -59,14 +64,17 @@ def fake_video_stream():
return rx.of(image)


# TODO: Delete
@pytest.fixture
def fake_gps_position_stream():
return rx.of(LatLon(lat=37.783, lon=-122.413))


@pytest.fixture
def navigation_skill_container(fake_robot, fake_video_stream):
container = NavigationSkillContainer(fake_robot, fake_video_stream)
def navigation_skill_container(mocker):
container = NavigationSkillContainer()
container.color_image.connection = mocker.MagicMock()
container.odom.connection = mocker.MagicMock()
container.start()
yield container
container.stop()
Expand All @@ -93,15 +101,15 @@ def google_maps_skill_container(fake_gps_robot, fake_gps_position_stream, mocker
def create_navigation_agent(navigation_skill_container, create_fake_agent):
return partial(
create_fake_agent,
system_prompt=SYSTEM_PROMPT,
system_prompt=system_prompt,
skill_containers=[navigation_skill_container],
)


@pytest.fixture
def create_gps_nav_agent(gps_nav_skill_container, create_fake_agent):
return partial(
create_fake_agent, system_prompt=SYSTEM_PROMPT, skill_containers=[gps_nav_skill_container]
create_fake_agent, system_prompt=system_prompt, skill_containers=[gps_nav_skill_container]
)


Expand All @@ -111,6 +119,6 @@ def create_google_maps_agent(
):
return partial(
create_fake_agent,
system_prompt=SYSTEM_PROMPT,
system_prompt=system_prompt,
skill_containers=[gps_nav_skill_container, google_maps_skill_container],
)
Loading