diff --git a/pyproject.toml b/pyproject.toml index fd1c80e..a0f9d85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,13 +17,15 @@ dependencies = [ "websockets>=15.0.1,<16", ] -[project.scripts] -voice-assistant = "voice_assistant:main" - [build-system] requires = ["uv_build>=0.12.17,<0.13.0"] build-backend = "uv_build" [tool.pytest.ini_options] testpaths = ["tests"] -pythonpath = ["src"] \ No newline at end of file +pythonpath = ["src"] + +[dependency-groups] +dev = [ + "ruff>=0.16.10", +] diff --git a/src/voice_assistant/__init__.py b/src/voice_assistant/__init__.py index 2807c33..3b837ed 100644 --- a/src/voice_assistant/__init__.py +++ b/src/voice_assistant/__init__.py @@ -1,2 +1,7 @@ -def main() -> None: - print("Hello from voice-assistant!") +""" +Voice Assistant package. + +Provides realtime voice processing components, including +audio transport, speech recognition, agent orchestration, +speech synthesis, and turn lifecycle management. +""" \ No newline at end of file diff --git a/src/voice_assistant/audio_gateway/app/main.py b/src/voice_assistant/audio_gateway/app/main.py index 4fa452a..0100016 100644 --- a/src/voice_assistant/audio_gateway/app/main.py +++ b/src/voice_assistant/audio_gateway/app/main.py @@ -36,7 +36,6 @@ import json import logging from fastapi import FastAPI, WebSocket, WebSocketDisconnect from pydantic import BaseModel, ValidationError -import os import asyncio @@ -45,7 +44,6 @@ from voice_assistant.stt.adapter import STTAdapter from voice_assistant.tts.adapter import TTSAdapter from voice_assistant.turn_manager import ( TurnManager, - TurnState, ) from voice_assistant.agent.adapter import AgentAdapter @@ -72,7 +70,6 @@ from voice_assistant.audio_gateway.app.protocol import ( AUDIO_SAMPLE_RATE, AUDIO_CHANNELS, AudioChunk, - AudioStart, AudioStop, Interrupt, SessionEnd, diff --git a/src/voice_assistant/providers.py b/src/voice_assistant/providers.py index 6ce3782..1432e79 100644 --- a/src/voice_assistant/providers.py +++ b/src/voice_assistant/providers.py @@ -44,7 +44,6 @@ from voice_assistant.config.models import ( from voice_assistant.stt.adapter import STTAdapter from voice_assistant.tts.adapter import TTSAdapter -from voice_assistant.audio.models import CANONICAL_AUDIO_FORMAT PROVIDER_CONTRACTS: dict[str, type] = { "stt": STTAdapter, diff --git a/tests/test_agent.py b/tests/test_agent.py index a160691..200ca42 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -4,8 +4,11 @@ from voice_assistant.agent import MockAgentAdapter @pytest.mark.anyio -async def text_mock_agent_process_text(): - agent = MackAgentAdapter() +async def test_mock_agent_process_text(): + """ + Verify that the mock Agent returns the expected response. + """ + agent = MockAgentAdapter() response = await agent.process( session_id="session-1", @@ -21,20 +24,21 @@ async def text_mock_agent_process_text(): @pytest.mark.anyio async def test_mock_agent_records_call(): + """ + Verify that the mock Agent records its invocation. + """ agent = MockAgentAdapter() await agent.process( session_id="session-1", turn_id=7, - text= "Olá", + text="Olá", ) - assert agent.calls == [ ( "session-1", 7, "Olá", ) - ] - + ] \ No newline at end of file diff --git a/tests/test_config.py b/tests/test_config.py index 9f2f0a2..e9cc509 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -37,7 +37,6 @@ Architecture: import pytest import yaml -from voice_assistant.config.loader import load_config from voice_assistant.config.loader import ( load_config, load_provider_catalog, @@ -167,7 +166,7 @@ def test_load_provider_catalog_missing_file(tmp_path): ) -def test_load_config_uses_app_env( +def test_load_config_uses_development_app_env( tmp_path, monkeypatch, ): @@ -220,7 +219,7 @@ def test_load_config_rejects_unknown_environment( config_dir=tmp_path, ) -def test_load_config_uses_app_env( +def test_load_config_uses_staging_app_env( tmp_path, monkeypatch, ): @@ -273,16 +272,3 @@ agent: assert config.agent.provider == "mock" - -def test_load_config_rejects_unknown_environment( - tmp_path, -): - with pytest.raises( - FileNotFoundError, - match="Configuration file not found", - ): - load_config( - environment="does-not-exist", - config_dir=tmp_path, - ) - diff --git a/tests/test_gateway.py b/tests/test_gateway.py index 85a3e1f..24004bf 100644 --- a/tests/test_gateway.py +++ b/tests/test_gateway.py @@ -19,7 +19,6 @@ from voice_assistant.audio_gateway.app.protocol import ( ) # Teste Agent -from voice_assistant.agent.adapter import AgentAdapter from voice_assistant.agent.mock import MockAgentAdapter # Teste TTS diff --git a/tests/test_turn_manager.py b/tests/test_turn_manager.py index bb0ebe8..e403ad4 100644 --- a/tests/test_turn_manager.py +++ b/tests/test_turn_manager.py @@ -56,18 +56,6 @@ def test_cannot_start_second_turn(): manager.start(2) -def test_cannot_stop_before_completed(): - manager = TurnManager() - - manager.start(1) - - with pytest.raises( - RuntimeError, - match="final transcript", - ): - manager.stop(1) - - def test_interrupt(): manager = TurnManager() @@ -152,7 +140,7 @@ def test_tts_completion_requires_speaking_state(): manager.on_tts_complete(1) -def test_cannot_stop_before_completed(): +def test_cannot_stop_while_listening(): manager = TurnManager() manager.start(1) diff --git a/uv.lock b/uv.lock index 9191be1..657d032 100644 --- a/uv.lock +++ b/uv.lock @@ -1086,6 +1086,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, ] +[[package]] +name = "ruff" +version = "0.16.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/49/23802c45f093eb14bde54b141d2b2f058edfa63a06db7beed047308cc08f/ruff-0.16.10.tar.gz", hash = "sha256:eff4728c4eaae93f0955cd264d24b2ab348e74bf59986ccf282ba6dc16b3b017", size = 4958724, upload-time = "2026-10-01T18:03:21.697Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/21/ebce22e1d90cdb2cd691026b9c6e9bec6499f0b396089481755b5d49efff/ruff-0.16.10-py3-none-linux_armv6l.whl", hash = "sha256:488b0fe3f3574210e5cf80d9f59b9e3ab17a127a8155de3f307b392589cfb511", size = 10095557, upload-time = "2026-10-01T18:02:36.072Z" }, + { url = "https://files.pythonhosted.org/packages/cb/98/a54de85876a8b2612bfa0d84c7b9abfb39c6a3354aee7800b09c1649b9e3/ruff-0.16.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e748ff95c934c4e978783b8e687bc174e7bd84e8ad24e3243e1ecfcda5e0282d", size = 10340577, upload-time = "2026-10-01T18:02:39.258Z" }, + { url = "https://files.pythonhosted.org/packages/9f/16/1a5a4a2657effe4806110f2b907313802f1367fcdbb29e8122766e407fab/ruff-0.16.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3031a4a2e8e7b8a46f70be45f198c35a11ece509a94b80334d8d397a33c67550", size = 9774282, upload-time = "2026-10-01T18:02:41.79Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fb/470085af734da396e68cd80fb0a3e7c109a459716ae59588c0f6fab8a17d/ruff-0.16.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:494401c86df4c4c25f69b9419605d944467ee98c42fb6ad405ef4fa40b8fb67d", size = 9920895, upload-time = "2026-10-01T18:02:44.458Z" }, + { url = "https://files.pythonhosted.org/packages/57/de/f10cffe4f88a37ea6615ec460f01bf76f0bc1477737a35d9ee61a630a78b/ruff-0.16.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d203abc0ff2b773ee33d00ab8df0bb67046fbc7c07b119332f08b9b345cf8221", size = 9902707, upload-time = "2026-10-01T18:02:47.041Z" }, + { url = "https://files.pythonhosted.org/packages/ff/44/3fdcedf83ae60ef837dd239170e480dce606a9142cfa2db911afdf855fd9/ruff-0.16.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd83d1235a5258d318477bc5b576303974cbdef5df0c01a1bff14efcc23bd12a", size = 10619287, upload-time = "2026-10-01T18:02:49.485Z" }, + { url = "https://files.pythonhosted.org/packages/c1/62/02e76a5574002153618eafbb70e159468addc72a5d2c488e65cbb4639d2d/ruff-0.16.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc2610fb269fa56dd8a68669ae470fa6272902668c0fc2ebc3aa112b2633d5b8", size = 11339942, upload-time = "2026-10-01T18:02:52.008Z" }, + { url = "https://files.pythonhosted.org/packages/6b/c4/cde27d47ad8d4126c587e608c67c46e7feac11763f606d261a1bc8a489e6/ruff-0.16.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e70175e29cc94c26ea296c80e470180b744b7419026898e58f520c6ab32578e", size = 10934316, upload-time = "2026-10-01T18:02:54.811Z" }, + { url = "https://files.pythonhosted.org/packages/e4/03/17234145f302a645a123e8c3bb2411ecf4669fbc350de3b0d803230a1729/ruff-0.16.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f33f43a864a8483eebd160e713336c8bab02c934feaff0a33cf5ccb41546d09a", size = 10387968, upload-time = "2026-10-01T18:02:57.497Z" }, + { url = "https://files.pythonhosted.org/packages/71/29/2493af60240ee7644b38a4b821f5f9c3b5a4fa3178770fe1d0c685217395/ruff-0.16.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:1dfc6f0088149fb6a362c1c446bcbb3fd2157b3852fe2fa68409276eab9ad9b3", size = 10537906, upload-time = "2026-10-01T18:03:00.006Z" }, + { url = "https://files.pythonhosted.org/packages/2e/9a/f56b28f3b143bb9e518c34fb89ab191b626bca8b70dbf8af0d2e2d473572/ruff-0.16.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6553498afc35f580f036030795810b9e6bcea31604b0fd9e8d352795473042e3", size = 10012938, upload-time = "2026-10-01T18:03:03.006Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c4/fca37362848ea4d4d80712df13632e645e7c7cfb1bdedf140699ac7a090b/ruff-0.16.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a3b8471dea115d37f123882be852bed13403746d3a76c11de4a19ec5f9ff5a03", size = 9897945, upload-time = "2026-10-01T18:03:05.818Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c7/e0bc57664d6e0c61fd22f620af260fe9662d7e1ddb320ea7f160e76ef165/ruff-0.16.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:92e59a70bcbd9d3a5483656da906ec28edfdacfce00afd99edb8b4e9d15644be", size = 10333134, upload-time = "2026-10-01T18:03:08.25Z" }, + { url = "https://files.pythonhosted.org/packages/21/aa/5c9f3b68737c0e4a33a1db5dfab44f7b786d96ca91a7233112ddab1e6dc2/ruff-0.16.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7ae7375f803b5520dc9f546bed7e3a0acb70b91812e9bb4b19927de22f25b77d", size = 10741702, upload-time = "2026-10-01T18:03:10.775Z" }, + { url = "https://files.pythonhosted.org/packages/78/fa/0f9c2020dc316c53d983be011720b8157cc052b97e3f4dfa7db6d0f880a6/ruff-0.16.10-py3-none-win32.whl", hash = "sha256:2a12e01cb9156c10c466f63b46eaae5ecea28dfbd21b5836353ae498e7d1349a", size = 10139176, upload-time = "2026-10-01T18:03:13.267Z" }, + { url = "https://files.pythonhosted.org/packages/99/29/cfb0df9448d4d4ad48c2de029ada9ebd71baa6da983a6c77ee6c6cd0fe82/ruff-0.16.10-py3-none-win_amd64.whl", hash = "sha256:97f2015c92aa97105b0eab19eb5d224884399281cfc5da86a92db4ab5e7fb2ca", size = 10584734, upload-time = "2026-10-01T18:03:16.006Z" }, + { url = "https://files.pythonhosted.org/packages/fc/05/c16957eb287c3fc062e032619a25868d93d408a844b725bcf514f7a378ff/ruff-0.16.10-py3-none-win_arm64.whl", hash = "sha256:25a65fe998c4e6861ec079ada5826a2fc605e6cbccbe9dcd7fac1f54e791621b", size = 10366440, upload-time = "2026-10-01T18:03:19.04Z" }, +] + [[package]] name = "setuptools" version = "84.0.0" @@ -1268,6 +1293,11 @@ dependencies = [ { name = "websockets" }, ] +[package.dev-dependencies] +dev = [ + { name = "ruff" }, +] + [package.metadata] requires-dist = [ { name = "fastapi", specifier = ">=0.141.1" }, @@ -1282,6 +1312,9 @@ requires-dist = [ { name = "websockets", specifier = ">=15.0.1,<16" }, ] +[package.metadata.requires-dev] +dev = [{ name = "ruff", specifier = ">=0.16.10" }] + [[package]] name = "watchfiles" version = "1.3.0"