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
286 changes: 85 additions & 201 deletions LICENSE

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Rune CLI
Copyright 2025 Rune AI
Copyright 2026 SAGEA

This product includes software developed by Mistral AI (https://mistral.ai).
Original software: Mistral Vibe (https://github.com/mistralai/mistral-vibe)
Copyright 2024 Mistral AI
This product includes software developed by SAGEA (https:/sagea.space).
Original software: RUNE (https://github.com/sagea-ai/rune)
Copyright 2026 SAGEA
Licensed under Apache License 2.0.
14 changes: 7 additions & 7 deletions tests/acp/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from tests.stubs.fake_backend import FakeBackend
from tests.stubs.fake_client import FakeClient
from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.agent_loop import AgentLoop
from rune.core.types import LLMChunk, LLMMessage, LLMUsage, Role

Expand All @@ -22,18 +22,18 @@ def backend() -> FakeBackend:
return backend


def _create_acp_agent() -> VibeAcpAgentLoop:
vibe_acp_agent = VibeAcpAgentLoop()
def _create_acp_agent() -> RuneAcpAgentLoop:
rune_acp_agent = RuneAcpAgentLoop()
client = FakeClient()

vibe_acp_agent.on_connect(client)
client.on_connect(vibe_acp_agent)
rune_acp_agent.on_connect(client)
client.on_connect(rune_acp_agent)

return vibe_acp_agent # pyright: ignore[reportReturnType]
return rune_acp_agent # pyright: ignore[reportReturnType]


@pytest.fixture
def acp_agent_loop(backend: FakeBackend) -> VibeAcpAgentLoop:
def acp_agent_loop(backend: FakeBackend) -> RuneAcpAgentLoop:
class PatchedAgent(AgentLoop):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs, backend=backend)
Expand Down
16 changes: 8 additions & 8 deletions tests/acp/test_agent_thought.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
import pytest

from tests.acp.conftest import _create_acp_agent
from tests.conftest import build_test_vibe_config
from tests.conftest import build_test_rune_config
from tests.stubs.fake_backend import FakeBackend
from tests.stubs.fake_client import FakeClient
from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.agent_loop import AgentLoop
from rune.core.types import LLMChunk, LLMMessage, LLMUsage, Role

Expand Down Expand Up @@ -38,8 +38,8 @@ def backend_with_reasoning() -> FakeBackend:
@pytest.fixture
def acp_agent_loop_with_reasoning(
backend_with_reasoning: FakeBackend,
) -> VibeAcpAgentLoop:
config = build_test_vibe_config(active_model="devstral-latest")
) -> RuneAcpAgentLoop:
config = build_test_rune_config(active_model="devstral-latest")

class PatchedAgentLoop(AgentLoop):
def __init__(self, *args, **kwargs) -> None:
Expand All @@ -54,7 +54,7 @@ def __init__(self, *args, **kwargs) -> None:
class TestACPAgentThought:
@pytest.mark.asyncio
async def test_prompt_with_reasoning_emits_agent_thought_chunk(
self, acp_agent_loop_with_reasoning: VibeAcpAgentLoop
self, acp_agent_loop_with_reasoning: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop_with_reasoning.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down Expand Up @@ -82,7 +82,7 @@ async def test_prompt_with_reasoning_emits_agent_thought_chunk(

@pytest.mark.asyncio
async def test_prompt_without_reasoning_does_not_emit_agent_thought_chunk(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -105,7 +105,7 @@ async def test_prompt_without_reasoning_does_not_emit_agent_thought_chunk(

@pytest.mark.asyncio
async def test_agent_thought_chunk_contains_text_content_block(
self, acp_agent_loop_with_reasoning: VibeAcpAgentLoop
self, acp_agent_loop_with_reasoning: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop_with_reasoning.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -129,7 +129,7 @@ async def test_agent_thought_chunk_contains_text_content_block(

@pytest.mark.asyncio
async def test_agent_thought_chunk_contains_message_id(
self, acp_agent_loop_with_reasoning: VibeAcpAgentLoop
self, acp_agent_loop_with_reasoning: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop_with_reasoning.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down
18 changes: 9 additions & 9 deletions tests/acp/test_compact_session_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@
from acp.schema import TextContentBlock, ToolCallProgress, ToolCallStart
import pytest

from tests.conftest import build_test_vibe_config
from tests.conftest import build_test_rune_config
from tests.stubs.fake_backend import FakeBackend
from tests.stubs.fake_client import FakeClient
from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.agent_loop import AgentLoop


@pytest.fixture
def acp_agent_loop(backend: FakeBackend) -> VibeAcpAgentLoop:
def acp_agent_loop(backend: FakeBackend) -> RuneAcpAgentLoop:
class PatchedAgent(AgentLoop):
def __init__(self, *args, **kwargs) -> None:
# Force our config with auto_compact_threshold=1
kwargs["config"] = build_test_vibe_config(auto_compact_threshold=1)
kwargs["config"] = build_test_rune_config(auto_compact_threshold=1)
super().__init__(*args, **kwargs, backend=backend)

patch("rune.acp.acp_agent_loop.AgentLoop", side_effect=PatchedAgent).start()
vibe_acp_agent = VibeAcpAgentLoop()
rune_acp_agent = RuneAcpAgentLoop()
client = FakeClient()
vibe_acp_agent.on_connect(client)
client.on_connect(vibe_acp_agent)
return vibe_acp_agent
rune_acp_agent.on_connect(client)
client.on_connect(rune_acp_agent)
return rune_acp_agent


class TestCompactEventHandling:
@pytest.mark.asyncio
async def test_prompt_handles_compact_events(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
"""Verify prompt() sends tool_call session updates for compact events."""
session_response = await acp_agent_loop.new_session(
Expand Down
10 changes: 5 additions & 5 deletions tests/acp/test_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
import pytest

from tests.stubs.fake_backend import FakeBackend
from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.types import Role


class TestACPContent:
@pytest.mark.asyncio
async def test_text_content(
self, acp_agent_loop: VibeAcpAgentLoop, backend: FakeBackend
self, acp_agent_loop: RuneAcpAgentLoop, backend: FakeBackend
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -43,7 +43,7 @@ async def test_text_content(

@pytest.mark.asyncio
async def test_resource_content(
self, acp_agent_loop: VibeAcpAgentLoop, backend: FakeBackend
self, acp_agent_loop: RuneAcpAgentLoop, backend: FakeBackend
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down Expand Up @@ -79,7 +79,7 @@ async def test_resource_content(

@pytest.mark.asyncio
async def test_resource_link_content(
self, acp_agent_loop: VibeAcpAgentLoop, backend: FakeBackend
self, acp_agent_loop: RuneAcpAgentLoop, backend: FakeBackend
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down Expand Up @@ -120,7 +120,7 @@ async def test_resource_link_content(

@pytest.mark.asyncio
async def test_resource_link_minimal(
self, acp_agent_loop: VibeAcpAgentLoop, backend: FakeBackend
self, acp_agent_loop: RuneAcpAgentLoop, backend: FakeBackend
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down
6 changes: 3 additions & 3 deletions tests/acp/test_initialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
)
import pytest

from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop


class TestACPInitialize:
@pytest.mark.asyncio
async def test_initialize(self, acp_agent_loop: VibeAcpAgentLoop) -> None:
async def test_initialize(self, acp_agent_loop: RuneAcpAgentLoop) -> None:
response = await acp_agent_loop.initialize(protocol_version=PROTOCOL_VERSION)

assert response.protocol_version == PROTOCOL_VERSION
Expand All @@ -32,7 +32,7 @@ async def test_initialize(self, acp_agent_loop: VibeAcpAgentLoop) -> None:

@pytest.mark.asyncio
async def test_initialize_with_terminal_auth(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
"""Test initialize with terminal-auth capabilities to check it was included."""
client_capabilities = ClientCapabilities(field_meta={"terminal-auth": True})
Expand Down
8 changes: 4 additions & 4 deletions tests/acp/test_multi_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

from tests.mock.utils import mock_llm_chunk
from tests.stubs.fake_backend import FakeBackend
from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.types import Role


class TestMultiSessionCore:
@pytest.mark.asyncio
async def test_different_sessions_use_different_agents(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
await acp_agent_loop.initialize(protocol_version=PROTOCOL_VERSION)
session1_response = await acp_agent_loop.new_session(
Expand All @@ -37,7 +37,7 @@ async def test_different_sessions_use_different_agents(

@pytest.mark.asyncio
async def test_error_on_nonexistent_session(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
await acp_agent_loop.initialize(protocol_version=PROTOCOL_VERSION)
await acp_agent_loop.new_session(cwd=str(Path.cwd()), mcp_servers=[])
Expand All @@ -55,7 +55,7 @@ async def test_error_on_nonexistent_session(

@pytest.mark.asyncio
async def test_simultaneous_message_processing(
self, acp_agent_loop: VibeAcpAgentLoop, backend: FakeBackend
self, acp_agent_loop: RuneAcpAgentLoop, backend: FakeBackend
) -> None:
await acp_agent_loop.initialize(protocol_version=PROTOCOL_VERSION)
session1_response = await acp_agent_loop.new_session(
Expand Down
12 changes: 6 additions & 6 deletions tests/acp/test_new_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
import pytest

from tests.acp.conftest import _create_acp_agent
from tests.conftest import build_test_vibe_config
from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from tests.conftest import build_test_rune_config
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.agent_loop import AgentLoop
from rune.core.agents.models import BuiltinAgentName
from rune.core.config import ModelConfig


@pytest.fixture
def acp_agent_loop(backend) -> VibeAcpAgentLoop:
config = build_test_vibe_config(
def acp_agent_loop(backend) -> RuneAcpAgentLoop:
config = build_test_rune_config(
active_model="devstral-latest",
models=[
ModelConfig(
Expand All @@ -41,7 +41,7 @@ def __init__(self, *args, **kwargs) -> None:
class TestACPNewSession:
@pytest.mark.asyncio
async def test_new_session_response_structure(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down Expand Up @@ -93,7 +93,7 @@ async def test_new_session_response_structure(
@pytest.mark.skip(reason="TODO: Fix this test")
@pytest.mark.asyncio
async def test_new_session_preserves_model_after_set_model(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down
16 changes: 8 additions & 8 deletions tests/acp/test_set_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

import pytest

from rune.acp.acp_agent_loop import VibeAcpAgentLoop
from rune.acp.acp_agent_loop import RuneAcpAgentLoop
from rune.core.agents.models import BuiltinAgentName


class TestACPSetMode:
@pytest.mark.asyncio
async def test_set_mode_to_default(self, acp_agent_loop: VibeAcpAgentLoop) -> None:
async def test_set_mode_to_default(self, acp_agent_loop: RuneAcpAgentLoop) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
Expand All @@ -32,7 +32,7 @@ async def test_set_mode_to_default(self, acp_agent_loop: VibeAcpAgentLoop) -> No

@pytest.mark.asyncio
async def test_set_mode_to_auto_approve(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -57,7 +57,7 @@ async def test_set_mode_to_auto_approve(
assert acp_session.agent_loop.auto_approve is True

@pytest.mark.asyncio
async def test_set_mode_to_plan(self, acp_agent_loop: VibeAcpAgentLoop) -> None:
async def test_set_mode_to_plan(self, acp_agent_loop: RuneAcpAgentLoop) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
)
Expand All @@ -81,7 +81,7 @@ async def test_set_mode_to_plan(self, acp_agent_loop: VibeAcpAgentLoop) -> None:

@pytest.mark.asyncio
async def test_set_mode_to_accept_edits(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -108,7 +108,7 @@ async def test_set_mode_to_accept_edits(

@pytest.mark.asyncio
async def test_set_mode_invalid_mode_returns_none(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -132,7 +132,7 @@ async def test_set_mode_invalid_mode_returns_none(

@pytest.mark.asyncio
async def test_set_mode_to_same_mode(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand All @@ -155,7 +155,7 @@ async def test_set_mode_to_same_mode(

@pytest.mark.asyncio
async def test_set_mode_with_empty_string(
self, acp_agent_loop: VibeAcpAgentLoop
self, acp_agent_loop: RuneAcpAgentLoop
) -> None:
session_response = await acp_agent_loop.new_session(
cwd=str(Path.cwd()), mcp_servers=[]
Expand Down
Loading
Loading