mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-31 03:12:16 +00:00
Add orchestrator training, channels, LiteLLM engine, and simplify learning taxonomy
Major changes across parallel sessions: - Add orchestrator SFT & GRPO training subpackage (learning/orchestrator/) with episode types, multi-objective reward, prompt registry, policy model, RL environment, and registered learning policies - Add structured THOUGHT/TOOL/INPUT/FINAL_ANSWER mode to OrchestratorAgent - Add 15 channel backends (Discord, Slack, Telegram, Email, Webhook, IRC, Matrix, Teams, WhatsApp, Signal, Mattermost, BlueBubbles, Feishu, Google Chat, Webchat) with channel tools and config - Add LiteLLM engine backend for unified LLM provider access - Add RLM agent and REPL tool - Remove ToolLearningPolicy — learning taxonomy now only targets Intelligence (LM weights/routing) and Agents (logic/ICL/tool strategies) - Rename SFTPolicy to SFTRouterPolicy (backward-compat alias kept) - Remove OpenClaw agent infrastructure (openclaw*.py, openclaw_bridge.py) - Fix async streaming tests (asyncio.run vs deprecated get_event_loop) - Fix server channel route tests (pytest.importorskip for optional fastapi) - Track uv.lock for reproducibility - Update CLAUDE.md and docs to reflect all changes 1676 tests pass, 37 skipped. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a0961633a3
commit
8d538cd1b0
@@ -31,7 +31,6 @@ def _mock_engine(content="Hello from engine"):
|
||||
def _register_agents():
|
||||
"""Re-register agents after registry clear."""
|
||||
from openjarvis.agents.custom import CustomAgent
|
||||
from openjarvis.agents.openclaw import OpenClawAgent
|
||||
from openjarvis.agents.orchestrator import OrchestratorAgent
|
||||
from openjarvis.agents.simple import SimpleAgent
|
||||
from openjarvis.core.registry import AgentRegistry
|
||||
@@ -40,7 +39,6 @@ def _register_agents():
|
||||
("simple", SimpleAgent),
|
||||
("orchestrator", OrchestratorAgent),
|
||||
("custom", CustomAgent),
|
||||
("openclaw", OpenClawAgent),
|
||||
]:
|
||||
if not AgentRegistry.contains(name):
|
||||
AgentRegistry.register_value(name, cls)
|
||||
|
||||
@@ -15,9 +15,9 @@ def _patch_channel(
|
||||
send_return=True,
|
||||
status_return=ChannelStatus.DISCONNECTED,
|
||||
):
|
||||
"""Return patches for load_config and OpenClawChannelBridge."""
|
||||
"""Return patches for load_config and _get_channel."""
|
||||
cfg = mock.MagicMock()
|
||||
cfg.channel.gateway_url = "ws://127.0.0.1:18789/ws"
|
||||
cfg.channel.default_channel = ""
|
||||
|
||||
bridge_instance = mock.MagicMock()
|
||||
bridge_instance.list_channels.return_value = list_channels or []
|
||||
@@ -27,11 +27,11 @@ def _patch_channel(
|
||||
config_patch = mock.patch(
|
||||
"openjarvis.core.config.load_config", return_value=cfg,
|
||||
)
|
||||
bridge_patch = mock.patch(
|
||||
"openjarvis.channels.openclaw_bridge.OpenClawChannelBridge",
|
||||
get_channel_patch = mock.patch(
|
||||
"openjarvis.cli.channel_cmd._get_channel",
|
||||
return_value=bridge_instance,
|
||||
)
|
||||
return config_patch, bridge_patch, bridge_instance
|
||||
return config_patch, get_channel_patch, bridge_instance
|
||||
|
||||
|
||||
class TestChannelHelp:
|
||||
@@ -45,24 +45,26 @@ class TestChannelHelp:
|
||||
|
||||
class TestChannelList:
|
||||
def test_list_with_channels(self) -> None:
|
||||
config_p, bridge_p, _ = _patch_channel(list_channels=["slack", "discord"])
|
||||
with config_p, bridge_p:
|
||||
config_p, getch_p, _ = _patch_channel(
|
||||
list_channels=["slack", "discord"],
|
||||
)
|
||||
with config_p, getch_p:
|
||||
result = CliRunner().invoke(cli, ["channel", "list"])
|
||||
assert result.exit_code == 0
|
||||
assert "slack" in result.output
|
||||
assert "discord" in result.output
|
||||
|
||||
def test_list_no_channels(self) -> None:
|
||||
config_p, bridge_p, _ = _patch_channel(list_channels=[])
|
||||
with config_p, bridge_p:
|
||||
config_p, getch_p, _ = _patch_channel(list_channels=[])
|
||||
with config_p, getch_p:
|
||||
result = CliRunner().invoke(cli, ["channel", "list"])
|
||||
assert result.exit_code == 0
|
||||
assert "No channels available" in result.output
|
||||
|
||||
def test_list_connection_error(self) -> None:
|
||||
config_p, bridge_p, inst = _patch_channel()
|
||||
config_p, getch_p, inst = _patch_channel()
|
||||
inst.list_channels.side_effect = ConnectionError("refused")
|
||||
with config_p, bridge_p:
|
||||
with config_p, getch_p:
|
||||
result = CliRunner().invoke(cli, ["channel", "list"])
|
||||
assert result.exit_code == 0
|
||||
assert "Failed" in result.output or "refused" in result.output
|
||||
@@ -70,25 +72,30 @@ class TestChannelList:
|
||||
|
||||
class TestChannelSend:
|
||||
def test_send_success(self) -> None:
|
||||
config_p, bridge_p, _ = _patch_channel(send_return=True)
|
||||
with config_p, bridge_p:
|
||||
result = CliRunner().invoke(cli, ["channel", "send", "slack", "Hello!"])
|
||||
config_p, getch_p, _ = _patch_channel(send_return=True)
|
||||
with config_p, getch_p:
|
||||
result = CliRunner().invoke(
|
||||
cli, ["channel", "send", "slack", "Hello!"],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "Message sent" in result.output
|
||||
|
||||
def test_send_failure(self) -> None:
|
||||
config_p, bridge_p, _ = _patch_channel(send_return=False)
|
||||
with config_p, bridge_p:
|
||||
result = CliRunner().invoke(cli, ["channel", "send", "slack", "Hello!"])
|
||||
config_p, getch_p, _ = _patch_channel(send_return=False)
|
||||
with config_p, getch_p:
|
||||
result = CliRunner().invoke(
|
||||
cli, ["channel", "send", "slack", "Hello!"],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "Failed to send" in result.output
|
||||
|
||||
|
||||
class TestChannelStatus:
|
||||
def test_status_shows_info(self) -> None:
|
||||
config_p, bridge_p, _ = _patch_channel(status_return=ChannelStatus.DISCONNECTED)
|
||||
with config_p, bridge_p:
|
||||
config_p, getch_p, _ = _patch_channel(
|
||||
status_return=ChannelStatus.DISCONNECTED,
|
||||
)
|
||||
with config_p, getch_p:
|
||||
result = CliRunner().invoke(cli, ["channel", "status"])
|
||||
assert result.exit_code == 0
|
||||
assert "disconnected" in result.output
|
||||
assert "127.0.0.1" in result.output
|
||||
|
||||
Reference in New Issue
Block a user