Remove SPADE dependency #29
@@ -8,7 +8,7 @@ formatters:
|
|||||||
# Console output
|
# Console output
|
||||||
colored:
|
colored:
|
||||||
(): "colorlog.ColoredFormatter"
|
(): "colorlog.ColoredFormatter"
|
||||||
format: "{log_color}{asctime} | {levelname:11} | {name:70} | {message}"
|
format: "{log_color}{asctime}.{msecs:03.0f} | {levelname:11} | {name:70} | {message}"
|
||||||
style: "{"
|
style: "{"
|
||||||
datefmt: "%H:%M:%S"
|
datefmt: "%H:%M:%S"
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ description = "Add your description here"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"agentspeak>=0.2.2",
|
||||||
"colorlog>=6.10.1",
|
"colorlog>=6.10.1",
|
||||||
"fastapi[all]>=0.115.6",
|
"fastapi[all]>=0.115.6",
|
||||||
"mlx-whisper>=0.4.3 ; sys_platform == 'darwin'",
|
"mlx-whisper>=0.4.3 ; sys_platform == 'darwin'",
|
||||||
|
|||||||
@@ -13,11 +13,12 @@ from control_backend.schemas.ri_message import SpeechCommand
|
|||||||
|
|
||||||
|
|
||||||
class BDICoreAgent(BaseAgent):
|
class BDICoreAgent(BaseAgent):
|
||||||
|
bdi_agent: agentspeak.runtime.Agent
|
||||||
|
|
||||||
def __init__(self, name: str, asl: str):
|
def __init__(self, name: str, asl: str):
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
self.asl_file = asl
|
self.asl_file = asl
|
||||||
self.env = agentspeak.runtime.Environment()
|
self.env = agentspeak.runtime.Environment()
|
||||||
self.bdi_agent = None
|
|
||||||
self.actions = agentspeak.stdlib.actions
|
self.actions = agentspeak.stdlib.actions
|
||||||
|
|
||||||
async def setup(self) -> None:
|
async def setup(self) -> None:
|
||||||
@@ -42,7 +43,6 @@ class BDICoreAgent(BaseAgent):
|
|||||||
async def _bdi_loop(self):
|
async def _bdi_loop(self):
|
||||||
"""Runs the AgentSpeak BDI loop."""
|
"""Runs the AgentSpeak BDI loop."""
|
||||||
while self._running:
|
while self._running:
|
||||||
assert self.bdi_agent is not None
|
|
||||||
self.bdi_agent.step()
|
self.bdi_agent.step()
|
||||||
await asyncio.sleep(0.01)
|
await asyncio.sleep(0.01)
|
||||||
|
|
||||||
@@ -74,30 +74,72 @@ class BDICoreAgent(BaseAgent):
|
|||||||
)
|
)
|
||||||
await self.send(out_msg)
|
await self.send(out_msg)
|
||||||
|
|
||||||
# TODO: test way of adding beliefs
|
|
||||||
def _add_beliefs(self, beliefs: dict[str, list[str]]):
|
def _add_beliefs(self, beliefs: dict[str, list[str]]):
|
||||||
if not beliefs:
|
if not beliefs:
|
||||||
return
|
return
|
||||||
|
|
||||||
for belief_name, args in beliefs.items():
|
for name, args in beliefs.items():
|
||||||
self._add_belief(belief_name, args)
|
self._add_belief(name, args)
|
||||||
|
|
||||||
if belief_name == "user_said":
|
def _add_belief(self, name: str, args: Iterable[str] = []):
|
||||||
self._add_belief("new_message")
|
new_args = (agentspeak.Literal(arg) for arg in args)
|
||||||
|
term = agentspeak.Literal(name, new_args)
|
||||||
def _add_belief(self, belief_name: str, arguments: Iterable[str] = []):
|
|
||||||
args = (agentspeak.Literal(arg) for arg in arguments)
|
|
||||||
literal_belief = agentspeak.Literal(belief_name, args)
|
|
||||||
|
|
||||||
assert self.bdi_agent is not None
|
assert self.bdi_agent is not None
|
||||||
|
|
||||||
self.bdi_agent.call(
|
self.bdi_agent.call(
|
||||||
agentspeak.Trigger.addition,
|
agentspeak.Trigger.addition,
|
||||||
agentspeak.GoalType.belief,
|
agentspeak.GoalType.belief,
|
||||||
literal_belief,
|
term,
|
||||||
agentspeak.runtime.Intention(),
|
agentspeak.runtime.Intention(),
|
||||||
)
|
)
|
||||||
self.logger.debug(f"Added belief {belief_name}({','.join(arguments)})")
|
self.logger.debug(f"Added belief {self.format_belief_string(name, args)}")
|
||||||
|
|
||||||
|
def _remove_belief(self, name: str, args: Iterable[str]):
|
||||||
|
"""
|
||||||
|
Removes a specific belief (with arguments), if it exists.
|
||||||
|
"""
|
||||||
|
new_args = (agentspeak.Literal(arg) for arg in args)
|
||||||
|
term = agentspeak.Literal(name, new_args)
|
||||||
|
|
||||||
|
assert self.bdi_agent is not None
|
||||||
|
|
||||||
|
result = self.bdi_agent.call(
|
||||||
|
agentspeak.Trigger.removal,
|
||||||
|
agentspeak.GoalType.belief,
|
||||||
|
term,
|
||||||
|
agentspeak.runtime.Intention(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
self.logger.debug(f"Removed belief {self.format_belief_string(name, args)}")
|
||||||
|
else:
|
||||||
|
self.logger.debug("Failed to remove belief (it was not in the belief base).")
|
||||||
|
|
||||||
|
# TODO: decide if this is needed
|
||||||
|
def _remove_all_with_name(self, name: str):
|
||||||
|
"""
|
||||||
|
Removes all beliefs that match the given `name`.
|
||||||
|
"""
|
||||||
|
assert self.bdi_agent is not None
|
||||||
|
|
||||||
|
relevant_groups = []
|
||||||
|
for key in self.bdi_agent.beliefs:
|
||||||
|
if key[0] == name:
|
||||||
|
relevant_groups.append(key)
|
||||||
|
|
||||||
|
removed_count = 0
|
||||||
|
for group in relevant_groups:
|
||||||
|
for belief in self.bdi_agent.beliefs[group]:
|
||||||
|
self.bdi_agent.call(
|
||||||
|
agentspeak.Trigger.removal,
|
||||||
|
agentspeak.GoalType.belief,
|
||||||
|
belief,
|
||||||
|
agentspeak.runtime.Intention(),
|
||||||
|
)
|
||||||
|
removed_count += 1
|
||||||
|
|
||||||
|
self.logger.debug(f"Removed {removed_count} beliefs.")
|
||||||
|
|
||||||
def _add_custom_actions(self) -> None:
|
def _add_custom_actions(self) -> None:
|
||||||
"""Add any custom actions here."""
|
"""Add any custom actions here."""
|
||||||
@@ -119,3 +161,10 @@ class BDICoreAgent(BaseAgent):
|
|||||||
msg = InternalMessage(to=settings.agent_settings.llm_name, sender=self.name, body=text)
|
msg = InternalMessage(to=settings.agent_settings.llm_name, sender=self.name, body=text)
|
||||||
await self.send(msg)
|
await self.send(msg)
|
||||||
self.logger.info("Message sent to LLM agent: %s", text)
|
self.logger.info("Message sent to LLM agent: %s", text)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_belief_string(name: str, args: Iterable[str] = []):
|
||||||
|
"""
|
||||||
|
Given a belief's name and its args, return a string of the form "name(*args)"
|
||||||
|
"""
|
||||||
|
return f"{name}{'(' if args else ''}{','.join(args)}{')' if args else ''}"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
+new_message : user_said(Message) <-
|
+user_said(NewMessage) <-
|
||||||
-new_message;
|
-user_said(NewMessage);
|
||||||
.reply(Message).
|
.reply(NewMessage).
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class VADAgent(BaseAgent):
|
|||||||
self.model = None
|
self.model = None
|
||||||
|
|
||||||
async def setup(self):
|
async def setup(self):
|
||||||
self.logger.info("Setting up %s", self.jid)
|
self.logger.info("Setting up %s", self.name)
|
||||||
|
|
||||||
self._connect_audio_in_socket()
|
self._connect_audio_in_socket()
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class VADAgent(BaseAgent):
|
|||||||
transcriber = TranscriptionAgent(audio_out_address)
|
transcriber = TranscriptionAgent(audio_out_address)
|
||||||
await transcriber.start()
|
await transcriber.start()
|
||||||
|
|
||||||
self.logger.info("Finished setting up %s", self.jid)
|
self.logger.info("Finished setting up %s", self.name)
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
# Central directory to resolve agent names to instances
|
# Central directory to resolve agent names to instances
|
||||||
_agent_directory: dict[str, "BaseAgent"] = {}
|
_agent_directory: dict[str, "BaseAgent"] = {}
|
||||||
@@ -14,7 +13,6 @@ class InternalMessage:
|
|||||||
sender: str
|
sender: str
|
||||||
body: str
|
body: str
|
||||||
thread: str | None = None
|
thread: str | None = None
|
||||||
metadata: dict[str, Any] = field(default_factory=dict)
|
|
||||||
|
|
||||||
|
|
||||||
class AgentDirectory:
|
class AgentDirectory:
|
||||||
@@ -32,7 +30,6 @@ class BaseAgent(ABC):
|
|||||||
|
|
||||||
def __init__(self, name: str):
|
def __init__(self, name: str):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.jid = name # present for backwards compatibility
|
|
||||||
self.inbox: asyncio.Queue[InternalMessage] = asyncio.Queue()
|
self.inbox: asyncio.Queue[InternalMessage] = asyncio.Queue()
|
||||||
self._tasks: set[asyncio.Task] = set()
|
self._tasks: set[asyncio.Task] = set()
|
||||||
self._running = False
|
self._running = False
|
||||||
@@ -83,5 +80,3 @@ class BaseAgent(ABC):
|
|||||||
task = asyncio.create_task(coro)
|
task = asyncio.create_task(coro)
|
||||||
self._tasks.add(task)
|
self._tasks.add(task)
|
||||||
task.add_done_callback(self._tasks.discard)
|
task.add_done_callback(self._tasks.discard)
|
||||||
|
|
||||||
# await asyncio.sleep(1)
|
|
||||||
|
|||||||
14
uv.lock
generated
14
uv.lock
generated
@@ -6,6 +6,18 @@ resolution-markers = [
|
|||||||
"python_full_version < '3.14'",
|
"python_full_version < '3.14'",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "agentspeak"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d0/a3/f8e9292cfd47aa5558f4578c498ca12c068a3a1d60ddfd0af13a87c1e47a/agentspeak-0.2.2.tar.gz", hash = "sha256:7c7fcf689fd54460597be1798ce11535f42a60c3d79af59381af3e13ef7a41bb", size = 59628, upload-time = "2024-03-21T11:55:39.026Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/b5/e95cbd9d9e999ac8dc4e0bb7a940112a2751cf98880b4ff0626e53d14249/agentspeak-0.2.2-py3-none-any.whl", hash = "sha256:9b454bc0adf63cb0d73fb4a3a9a489e7d892d5fbf17f750de532670736c0c4dd", size = 61628, upload-time = "2024-03-21T11:55:36.741Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alabaster"
|
name = "alabaster"
|
||||||
version = "0.7.16"
|
version = "0.7.16"
|
||||||
@@ -975,6 +987,7 @@ name = "pepperplus-cb"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "agentspeak" },
|
||||||
{ name = "colorlog" },
|
{ name = "colorlog" },
|
||||||
{ name = "fastapi", extra = ["all"] },
|
{ name = "fastapi", extra = ["all"] },
|
||||||
{ name = "mlx-whisper", marker = "sys_platform == 'darwin'" },
|
{ name = "mlx-whisper", marker = "sys_platform == 'darwin'" },
|
||||||
@@ -1016,6 +1029,7 @@ test = [
|
|||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
|
{ name = "agentspeak", specifier = ">=0.2.2" },
|
||||||
{ name = "colorlog", specifier = ">=6.10.1" },
|
{ name = "colorlog", specifier = ">=6.10.1" },
|
||||||
{ name = "fastapi", extras = ["all"], specifier = ">=0.115.6" },
|
{ name = "fastapi", extras = ["all"], specifier = ">=0.115.6" },
|
||||||
{ name = "mlx-whisper", marker = "sys_platform == 'darwin'", specifier = ">=0.4.3" },
|
{ name = "mlx-whisper", marker = "sys_platform == 'darwin'", specifier = ">=0.4.3" },
|
||||||
|
|||||||
Reference in New Issue
Block a user