roomkit 0.7.2__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {roomkit-0.7.2 → roomkit-0.8.0}/PKG-INFO +3 -3
- {roomkit-0.7.2 → roomkit-0.8.0}/README.md +2 -2
- roomkit-0.8.0/src/roomkit/_version.py +1 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_context.py +13 -7
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_generation.py +33 -6
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_streaming.py +48 -8
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_tool_eviction.py +22 -7
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/ai.py +47 -1
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/event_router.py +7 -14
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/framework.py +17 -10
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/__init__.py +2 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/inbound.py +16 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/inbound_locked.py +158 -64
- roomkit-0.8.0/src/roomkit/core/mixins/regenerate.py +143 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/channel.py +10 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/delivery.py +5 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telegram/bot.py +36 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/__init__.py +3 -0
- roomkit-0.8.0/src/roomkit/tools/context.py +48 -0
- roomkit-0.8.0/tests/test_channels/test_ai_empty_retry.py +137 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_ai_skill_gating.py +52 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_ai_tool_loop.py +3 -2
- roomkit-0.8.0/tests/test_inbound_visibility.py +58 -0
- roomkit-0.8.0/tests/test_integration/test_regenerate.py +132 -0
- roomkit-0.8.0/tests/test_rfc_conformance.py +230 -0
- roomkit-0.8.0/tests/test_tool_context.py +159 -0
- roomkit-0.8.0/tests/test_tool_eviction_room_scope.py +71 -0
- roomkit-0.7.2/src/roomkit/_version.py +0 -1
- {roomkit-0.7.2 → roomkit-0.8.0}/.gitignore +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/AGENTS.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/LICENSE +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/README.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/ai-channels.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/api-reference.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/architecture.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/hooks.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/identity-and-realtime.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/installation.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/ollama-provider.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/orchestration.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/overview.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/quickstart.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/realtime-voice.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/resilience.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/rooms-and-channels.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/storage.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/testing.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/transport-providers.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/voice-channels.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/c7/voice-pipeline.md +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/architecture.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/avatar-pipeline.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/message-flow.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/orchestration.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/room-lifecycle.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/video-pipeline.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/voice-orchestration.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/docs/diagrams/voice-pipeline.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/llms-full.txt +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/llms.txt +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/pyproject.toml +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/ai_docs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_policy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_resilience.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_steering.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_ai_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_dangling_recovery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_audio.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_context.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_response.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_skills.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_speech.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_tool_recovery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_tool_search.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_realtime_transcription.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_sandbox_handlers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_skill_constants.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_skill_handlers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_task_planner.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_tool_search_constants.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_turn_config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_video_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_voice_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_voice_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_voice_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_voice_tts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/_voice_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/agent.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/av.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/cli.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/realtime_av.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/realtime_voice.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/video.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/voice.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/channels/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/console/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/console/_display.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/console/_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/console/_state.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/circuit_breaker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/delivery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/exceptions.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/inbound_router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/locks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/channel_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/delegation.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/deliver.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/greeting.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/helpers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/hooks_api.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/inbound_identity.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/inbound_streaming.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/realtime_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/recording.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/room_lifecycle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/source_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/mixins/voice_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/rate_limiter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/retry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/task_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/core/transcoder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/delivery/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/delivery/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/delivery/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/delivery/redis.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/delivery/serialization.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/delivery/worker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/identity/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/identity/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/identity/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/knowledge/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/knowledge/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/knowledge/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/knowledge/postgres.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/budget_aware.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/compacting.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/retrieval.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/sliding_window.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/summarizing.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/memory/token_estimator.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/context.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/enums.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/framework_event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/hook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/identity.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/participant.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/pending_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/room.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/session_event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/steering.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/store_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/streaming.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/task.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/tool_call.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/trace.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/models/vision_event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/handoff.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/session_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/state.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/status_bus.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/strategies/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/strategies/loop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/strategies/pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/strategies/supervisor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/strategies/swarm.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/orchestration/tool_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/ai/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/ai/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/ai/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anam/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anam/_convert.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anam/avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anam/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anam/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anthropic/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anthropic/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/anthropic/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/azure/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/azure/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/azure/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/elasticemail/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/elasticemail/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/elasticemail/email.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/elevenlabs/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/elevenlabs/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/elevenlabs/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/email/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/email/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/email/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/gemini/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/gemini/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/gemini/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/gemini/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/gemini/schema.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http/provider.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/http_errors.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/messenger/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/messenger/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/messenger/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/messenger/facebook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/messenger/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/messenger/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/mistral/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/mistral/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/mistral/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/ollama/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/ollama/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/ollama/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/openai/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/openai/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/openai/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/openai/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/personaplex/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/personaplex/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/personaplex/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/rcs/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/rcs/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/rcs/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sendgrid/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sendgrid/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sendgrid/email.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sinch/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sinch/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sinch/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sms/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sms/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sms/meta.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sms/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/sms/phone.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/bot_framework.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/conversation_store.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/teams/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telegram/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telegram/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telegram/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telegram/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telegram/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telnyx/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telnyx/_signature.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telnyx/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telnyx/rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/telnyx/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/twilio/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/twilio/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/twilio/rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/twilio/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/twilio/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/url_safety.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/vllm/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/vllm/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/voicemeup/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/voicemeup/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/voicemeup/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/whatsapp/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/whatsapp/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/whatsapp/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/whatsapp/personal.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/xai/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/xai/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/providers/xai/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/py.typed +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/realtime/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/realtime/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/realtime/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/recorder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/recorder/_pyav_mux.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/recorder/_room_recorder_manager.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/recorder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/recorder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/recorder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sandbox/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sandbox/executor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sandbox/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sandbox/tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/scoring/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/scoring/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/scoring/hook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/scoring/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/scoring/tracker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/skills/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/skills/executor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/skills/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/skills/parser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/skills/registry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sources/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sources/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sources/neonize.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sources/sse.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/sources/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/store/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/store/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/store/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/store/postgres.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tasks/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tasks/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tasks/cache.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tasks/delegate.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tasks/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tasks/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/console.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/context.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/noop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/opentelemetry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/telemetry/pyroscope.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/compose.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/external.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/human_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/mcp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/tools/policy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/ai_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/avatar/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/avatar/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/avatar/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/avatar/musetalk.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/avatar/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/local.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/screen.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/sip.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/backends/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/decoder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/decoder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/decoder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/decoder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/encoder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/encoder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/encoder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/engine.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/censor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/mediapipe_face_touch.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/mock_face_touch.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/watermark.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/filter/yolo.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/image.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/rich.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/subtitle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/overlay/text.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/resizer/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/resizer/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/resizer/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/resizer/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/transform/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/transform/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/transform/effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/pipeline/transform/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/recorder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/recorder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/recorder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/recorder/opencv.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/recorder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/video_frame.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/encode.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/gemini.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/openai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/screen_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/screen_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/video/vision/webcam_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/audio_frame.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/_mulaw.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/_sip_types.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/local.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/sip.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/sip_audio.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/sip_auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/sip_calling.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/twilio_ws.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/backends/webtransport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/inbound.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/interruption.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/aec/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/aec/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/aec/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/aec/speex.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/aec/webrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/agc/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/agc/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/agc/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/backchannel/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/backchannel/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/backchannel/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/debug_taps.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/denoiser/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/denoiser/aicoustics.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/denoiser/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/denoiser/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/denoiser/rnnoise.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/denoiser/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/diarization/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/diarization/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/diarization/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/diarization/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/dtmf/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/dtmf/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/dtmf/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/engine.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/mixer/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/mixer/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/mixer/numpy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/mixer/python.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/postprocessor/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/postprocessor/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/recorder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/recorder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/recorder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/recorder/wav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/resampler/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/resampler/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/resampler/linear.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/resampler/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/resampler/numpy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/resampler/sinc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/turn/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/turn/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/turn/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/turn/smart_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/vad/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/vad/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/vad/energy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/vad/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/pipeline/vad/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/fastrtc_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/pacer.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/provider.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/sip_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/realtime/ws_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/deepgram.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/gradium.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/stt/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/audio_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/filters.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/gradium.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/grok.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/neutts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/sentence_splitter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/tts/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/src/roomkit/voice/utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/conftest.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/test_base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/test_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/test_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/test_redis.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/test_serialization.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/delivery/test_worker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_framework_orchestration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_handoff.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_loop_strategy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_orchestration_base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_session_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_state.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_status_bus.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_strategy_behavioral.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_strategy_loop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_strategy_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_strategy_supervisor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_strategy_swarm.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_supervisor_inline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_supervisor_strategy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/orchestration/test_tool_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/providers/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/providers/gemini/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/providers/gemini/test_reconfigure_preservation.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/providers/gemini/test_schema.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/tasks/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/tasks/test_cache.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/tasks/test_delegate.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/tasks/test_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/tasks/test_models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/tasks/test_runner.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_aec_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_ai_docs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_ai_streaming_thinking.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_ai_streaming_tool_loop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_aicoustics_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_anam_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_audio_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_auto_connect.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_av_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_before_ai_generation.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channel_abc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_agent.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_ai_retry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_ai_steering.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_email.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_http.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_messenger.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_telegram.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_turn_config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_channels/test_whatsapp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_circuit_breaker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_cli_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_compose_tool_handlers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_configs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_console.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_dangling_recovery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_delivery_strategies.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_describe_screen_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_describe_webcam_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_drain_barge_in.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_energy_vad.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_enums.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_external_tool_handler.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_face_touch_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_fastrtc_realtime_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_framework.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_framework_events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_framework_queries.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_framework_status_bus.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_hook_side_effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_human_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_identity_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_identity_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_inbound_rate_limit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_inbound_routing.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_ai_assistant.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_ai_chain_depth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_cross_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_dynamic_channels.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_human_ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_identity_resolution.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_observer.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_integration/test_sin_scanning.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_interruption.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_lifecycle_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_local_backend_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_locks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_mcp_tool_provider.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_mcp_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_media_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_memory_new.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_mock_providers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_observability.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_opencv_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_opentelemetry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_outbound_audio_pacer.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_personaplex_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pipeline_debug_taps.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pipeline_engine.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pipeline_providers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pipeline_resampler.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pipeline_resampler_numpy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pipeline_resampler_sinc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_postgres_store.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_protocol_trace.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_anam_avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_anam_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_anthropic.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_azure.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_elasticemail.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_gemini.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_gemini_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_http.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_messenger.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_mistral.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_ollama.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_openai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_openai_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_personaplex_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_phone.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_sendgrid.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_sinch.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_sms_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_teams.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_teams_webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_telegram_bot.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_telegram_webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_telnyx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_telnyx_rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_twilio.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_vllm.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_voicemeup.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_whatsapp_personal.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_providers/test_xai_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_public_api.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pyav_media_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_pyav_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_av_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_skills.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_tool_search.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_voice.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_voice_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_realtime_xai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_recording_wiring.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_reentry_block_side_effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_resilience.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_response_metadata.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_response_visibility.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_retrieval_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_rnnoise.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_rtp_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_scoring.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_screen_capture_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_screen_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_session_started.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sherpa_onnx_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sherpa_onnx_vad.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sip_auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sip_dial.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sip_helpers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sip_realtime_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sip_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_skills.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_skills_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_smart_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_smoke_quickstart.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_source_rate_limit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sources.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sources_init.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sources_neonize.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sources_sse.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_sources_websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_speex_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_store_activity.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_store_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_store_postgres.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_stt_qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_summarizing_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_supervisor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_task_planner.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_task_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_telemetry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_telemetry_pyroscope.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tool_policy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tool_protocol.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_transport_auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tts_elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tts_grok.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tts_neutts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tts_qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_tts_text_split.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_turn_detection.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_twilio_ws_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_unified_tool_call.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_vad_debug_logging.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_ai_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_local.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_pipeline_config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_recording.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_video_transform.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_vision_gemini.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_vision_openai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_batch_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_binding_gate.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_channel_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_frame_limit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_inbound.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_local.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_map.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_say_play.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_streaming_ai_tts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_streaming_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_voice_webtransport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_wav_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_websocket_lifecycle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/test_yolo_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_av_channel_fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_fastrtc_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_overlay_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_overlay_image.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_overlay_rich.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_overlay_subtitle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_overlay_text.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_screen_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_screen_input_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_video_bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_video_effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_watermark_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_websocket_avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/video/test_websocket_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/backends/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/backends/test_rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/backends/test_sip.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/backends/test_sip_coverage.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/backends/test_webtransport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/test_aicoustics_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/test_rnnoise_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/test_sherpa_diarization.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/test_smart_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/test_speex_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/pipeline/test_webrtc_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/realtime/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/realtime/test_fastrtc_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/realtime/test_realtime_bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/realtime/test_ws_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/stt/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/stt/test_deepgram.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/stt/test_gradium_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/stt/test_qwen3_asr.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/test_bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/test_tts_filters.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/test_voice_tts_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/tts/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/tts/test_elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/tts/test_gradium_tts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.8.0}/tests/voice/tts/test_qwen3_tts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: roomkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Pure async Python library for multi-channel conversations
|
|
5
5
|
Project-URL: Homepage, https://roomkit.live
|
|
6
6
|
Project-URL: Documentation, https://www.roomkit.live/docs/
|
|
@@ -350,7 +350,7 @@ For development:
|
|
|
350
350
|
git clone https://github.com/roomkit-live/roomkit.git
|
|
351
351
|
cd roomkit
|
|
352
352
|
uv sync --extra dev
|
|
353
|
-
make all # ruff check +
|
|
353
|
+
make all # ruff check + ty + pytest
|
|
354
354
|
```
|
|
355
355
|
|
|
356
356
|
Requires **Python 3.12+**.
|
|
@@ -729,7 +729,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.
|
|
|
729
729
|
|
|
730
730
|
```bash
|
|
731
731
|
uv sync --extra dev
|
|
732
|
-
make all # ruff check +
|
|
732
|
+
make all # ruff check + ty + pytest
|
|
733
733
|
```
|
|
734
734
|
|
|
735
735
|
All new code needs tests. Aim for >90% coverage.
|
|
@@ -140,7 +140,7 @@ For development:
|
|
|
140
140
|
git clone https://github.com/roomkit-live/roomkit.git
|
|
141
141
|
cd roomkit
|
|
142
142
|
uv sync --extra dev
|
|
143
|
-
make all # ruff check +
|
|
143
|
+
make all # ruff check + ty + pytest
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
Requires **Python 3.12+**.
|
|
@@ -519,7 +519,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.
|
|
|
519
519
|
|
|
520
520
|
```bash
|
|
521
521
|
uv sync --extra dev
|
|
522
|
-
make all # ruff check +
|
|
522
|
+
make all # ruff check + ty + pytest
|
|
523
523
|
```
|
|
524
524
|
|
|
525
525
|
All new code needs tests. Aim for >90% coverage.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.8.0"
|
|
@@ -53,6 +53,7 @@ class AIContextHost(Protocol):
|
|
|
53
53
|
_max_tokens: Default max tokens (overridable per room).
|
|
54
54
|
_thinking_budget: Optional thinking budget for extended thinking.
|
|
55
55
|
_skills: Skill registry for tool injection.
|
|
56
|
+
_skills_in_prompt: Whether to auto-inject the skills manifest into the prompt.
|
|
56
57
|
_script_executor: Script executor for skill scripts.
|
|
57
58
|
_sandbox: Sandbox executor for ad-hoc command execution.
|
|
58
59
|
_memory: Memory provider for conversation retrieval.
|
|
@@ -75,6 +76,7 @@ class AIContextHost(Protocol):
|
|
|
75
76
|
_max_tokens: int
|
|
76
77
|
_thinking_budget: int | None
|
|
77
78
|
_skills: SkillRegistry | None
|
|
79
|
+
_skills_in_prompt: bool
|
|
78
80
|
_script_executor: ScriptExecutor | None
|
|
79
81
|
_sandbox: SandboxExecutor | None
|
|
80
82
|
_human_input_handler: HumanInputToolHandler | None
|
|
@@ -105,6 +107,7 @@ class AIContextMixin:
|
|
|
105
107
|
_max_tokens: int
|
|
106
108
|
_thinking_budget: int | None
|
|
107
109
|
_skills: SkillRegistry | None
|
|
110
|
+
_skills_in_prompt: bool
|
|
108
111
|
_script_executor: ScriptExecutor | None
|
|
109
112
|
_sandbox: SandboxExecutor | None
|
|
110
113
|
_human_input_handler: HumanInputToolHandler | None
|
|
@@ -183,15 +186,18 @@ class AIContextMixin:
|
|
|
183
186
|
existing_names = {t.name for t in tools}
|
|
184
187
|
tools.extend(t for t in hi_tools if t.name not in existing_names)
|
|
185
188
|
|
|
186
|
-
# Inject skill tools and prompt (infra tools added here, gated tools later)
|
|
189
|
+
# Inject skill tools and prompt (infra tools added here, gated tools later).
|
|
190
|
+
# The prompt block is skipped when the host renders its own skills
|
|
191
|
+
# manifest inside ``system_prompt`` (``skills_in_prompt=False``).
|
|
187
192
|
if self._skills and self._skills.skill_count > 0:
|
|
188
193
|
tools.extend(self._skill_tools())
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
if self._skills_in_prompt:
|
|
195
|
+
preamble = _SKILLS_PREAMBLE
|
|
196
|
+
if not self._script_executor:
|
|
197
|
+
preamble += _SKILLS_NO_SCRIPTS_NOTE
|
|
198
|
+
skills_xml = self._skills.to_prompt_xml()
|
|
199
|
+
skill_block = f"\n\n{preamble}\n\n{skills_xml}"
|
|
200
|
+
system_prompt = (system_prompt or "") + skill_block
|
|
195
201
|
|
|
196
202
|
# Inject sandbox tools and preamble
|
|
197
203
|
if self._sandbox is not None:
|
|
@@ -87,6 +87,7 @@ class AIGenerationHost(Protocol):
|
|
|
87
87
|
_max_tool_rounds: int
|
|
88
88
|
_tool_loop_timeout_seconds: float | None
|
|
89
89
|
_tool_loop_warn_after: int
|
|
90
|
+
_max_empty_retries: int
|
|
90
91
|
_tool_handler: Any
|
|
91
92
|
_active_loops: dict[str, _ToolLoopContext]
|
|
92
93
|
_after_response_hook: Any
|
|
@@ -143,6 +144,7 @@ class AIGenerationMixin:
|
|
|
143
144
|
_max_tool_rounds: int
|
|
144
145
|
_tool_loop_timeout_seconds: float | None
|
|
145
146
|
_tool_loop_warn_after: int
|
|
147
|
+
_max_empty_retries: int
|
|
146
148
|
_tool_handler: Any
|
|
147
149
|
_active_loops: dict[str, _ToolLoopContext]
|
|
148
150
|
_after_response_hook: Any
|
|
@@ -429,16 +431,19 @@ class AIGenerationMixin:
|
|
|
429
431
|
self, context: AIContext, *, parent_span_id: str | None = None
|
|
430
432
|
) -> ToolLoopResult:
|
|
431
433
|
"""Generate -> execute tools -> re-generate until a text response."""
|
|
432
|
-
from roomkit.channels.ai import
|
|
434
|
+
from roomkit.channels.ai import (
|
|
435
|
+
_EMPTY_RETRY_NUDGE,
|
|
436
|
+
_current_loop_ctx,
|
|
437
|
+
_ToolLoopContext,
|
|
438
|
+
)
|
|
433
439
|
|
|
434
|
-
loop_ctx = _ToolLoopContext(
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if parent_lctx is not None:
|
|
438
|
-
loop_ctx.current_participant_role = parent_lctx.current_participant_role
|
|
440
|
+
loop_ctx = _ToolLoopContext.for_loop(
|
|
441
|
+
_current_loop_ctx.get(), context.room.room.id if context.room else None
|
|
442
|
+
)
|
|
439
443
|
_current_loop_ctx.set(loop_ctx)
|
|
440
444
|
self._active_loops[loop_ctx.loop_id] = loop_ctx
|
|
441
445
|
rounds: list[ToolRound] = []
|
|
446
|
+
empty_retries = 0
|
|
442
447
|
try:
|
|
443
448
|
context, should_cancel = self._drain_steering_queue(context, loop_ctx)
|
|
444
449
|
if should_cancel:
|
|
@@ -462,6 +467,28 @@ class AIGenerationMixin:
|
|
|
462
467
|
|
|
463
468
|
for round_idx in range(self._max_tool_rounds):
|
|
464
469
|
if not response.tool_calls or self._tool_handler is None:
|
|
470
|
+
# Final answer reached. If it is empty *after* we ran tools,
|
|
471
|
+
# the model skipped verbalizing the result — re-prompt once
|
|
472
|
+
# (bounded) for the final answer instead of returning nothing.
|
|
473
|
+
if (
|
|
474
|
+
self._tool_handler is not None
|
|
475
|
+
and rounds
|
|
476
|
+
and not (response.content or "").strip()
|
|
477
|
+
and empty_retries < self._max_empty_retries
|
|
478
|
+
and not loop_ctx.cancel_event.is_set()
|
|
479
|
+
and not (deadline and asyncio.get_running_loop().time() >= deadline)
|
|
480
|
+
):
|
|
481
|
+
empty_retries += 1
|
|
482
|
+
logger.warning(
|
|
483
|
+
"Empty response after %d tool round(s); re-prompting for "
|
|
484
|
+
"final answer (retry %d/%d)",
|
|
485
|
+
len(rounds),
|
|
486
|
+
empty_retries,
|
|
487
|
+
self._max_empty_retries,
|
|
488
|
+
)
|
|
489
|
+
context.messages.append(AIMessage(role="user", content=_EMPTY_RETRY_NUDGE))
|
|
490
|
+
response = await self._generate_with_retry(context)
|
|
491
|
+
continue
|
|
465
492
|
break
|
|
466
493
|
|
|
467
494
|
if loop_ctx.cancel_event.is_set():
|
|
@@ -70,6 +70,7 @@ class AIStreamingHost(Protocol):
|
|
|
70
70
|
_max_tool_rounds: int
|
|
71
71
|
_tool_loop_timeout_seconds: float | None
|
|
72
72
|
_tool_loop_warn_after: int
|
|
73
|
+
_max_empty_retries: int
|
|
73
74
|
_tool_handler: Any
|
|
74
75
|
_active_loops: dict[str, _ToolLoopContext]
|
|
75
76
|
_after_response_hook: Any
|
|
@@ -126,6 +127,7 @@ class AIStreamingMixin:
|
|
|
126
127
|
_max_tool_rounds: int
|
|
127
128
|
_tool_loop_timeout_seconds: float | None
|
|
128
129
|
_tool_loop_warn_after: int
|
|
130
|
+
_max_empty_retries: int
|
|
129
131
|
_tool_handler: Any
|
|
130
132
|
_active_loops: dict[str, Any]
|
|
131
133
|
_after_response_hook: Any
|
|
@@ -235,26 +237,42 @@ class AIStreamingMixin:
|
|
|
235
237
|
self, event: RoomEvent, binding: ChannelBinding, context: RoomContext
|
|
236
238
|
) -> ChannelOutput:
|
|
237
239
|
"""Return a streaming response that handles tool calls between rounds."""
|
|
240
|
+
from roomkit.channels.ai import _current_loop_ctx
|
|
241
|
+
|
|
238
242
|
ai_context = await self._build_context(event, binding, context) # ty: ignore[unresolved-attribute]
|
|
239
243
|
ai_context, blocked = await self._fire_before_generation_hook(ai_context, event) # ty: ignore[unresolved-attribute]
|
|
240
244
|
if blocked:
|
|
241
245
|
return ChannelOutput.empty()
|
|
246
|
+
# The generator below executes when the CONSUMER iterates the
|
|
247
|
+
# stream — by then handle_event has reset the loop contextvar, so
|
|
248
|
+
# the parent ctx (participant role, room, the toolset stamped by
|
|
249
|
+
# _build_context) must be captured NOW and passed explicitly.
|
|
242
250
|
return ChannelOutput(
|
|
243
251
|
responded=True,
|
|
244
|
-
response_stream=self._run_streaming_tool_loop(
|
|
252
|
+
response_stream=self._run_streaming_tool_loop(
|
|
253
|
+
ai_context, parent_loop_ctx=_current_loop_ctx.get()
|
|
254
|
+
),
|
|
245
255
|
response_metadata=ai_context.response_metadata,
|
|
246
256
|
)
|
|
247
257
|
|
|
248
|
-
async def _run_streaming_tool_loop(
|
|
258
|
+
async def _run_streaming_tool_loop(
|
|
259
|
+
self, context: AIContext, *, parent_loop_ctx: Any | None = None
|
|
260
|
+
) -> AsyncIterator[StreamDelta]:
|
|
249
261
|
"""Stream text deltas, executing tool calls between generation rounds."""
|
|
250
|
-
from roomkit.channels.ai import
|
|
262
|
+
from roomkit.channels.ai import (
|
|
263
|
+
_EMPTY_RETRY_NUDGE,
|
|
264
|
+
_current_loop_ctx,
|
|
265
|
+
_ToolLoopContext,
|
|
266
|
+
)
|
|
251
267
|
from roomkit.telemetry.context import get_current_span
|
|
252
268
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if
|
|
257
|
-
|
|
269
|
+
# The handle_event ctx is gone from the contextvar by the time this
|
|
270
|
+
# generator runs (reset in handle_event's finally); the caller
|
|
271
|
+
# captured it at stream creation.
|
|
272
|
+
parent_ctx = parent_loop_ctx if parent_loop_ctx is not None else _current_loop_ctx.get()
|
|
273
|
+
loop_ctx = _ToolLoopContext.for_loop(
|
|
274
|
+
parent_ctx, context.room.room.id if context.room else None
|
|
275
|
+
)
|
|
258
276
|
_current_loop_ctx.set(loop_ctx)
|
|
259
277
|
self._active_loops[loop_ctx.loop_id] = loop_ctx
|
|
260
278
|
telemetry = self._telemetry_provider
|
|
@@ -287,6 +305,8 @@ class AIStreamingMixin:
|
|
|
287
305
|
)
|
|
288
306
|
|
|
289
307
|
_dedup_prefix = ""
|
|
308
|
+
_saw_tool_call_any = False
|
|
309
|
+
_empty_retries = 0
|
|
290
310
|
|
|
291
311
|
for _round_idx in range(self._max_tool_rounds + 1):
|
|
292
312
|
if loop_ctx.cancel_event.is_set():
|
|
@@ -465,8 +485,28 @@ class AIStreamingMixin:
|
|
|
465
485
|
)
|
|
466
486
|
|
|
467
487
|
if not tool_calls:
|
|
488
|
+
# Final answer round. If it produced no text *after* a tool
|
|
489
|
+
# round, the model skipped verbalizing the result — re-prompt
|
|
490
|
+
# once (bounded) for the final answer instead of ending empty.
|
|
491
|
+
if (
|
|
492
|
+
_saw_tool_call_any
|
|
493
|
+
and not "".join(text_parts).strip()
|
|
494
|
+
and _empty_retries < self._max_empty_retries
|
|
495
|
+
and not (deadline and asyncio.get_running_loop().time() >= deadline)
|
|
496
|
+
):
|
|
497
|
+
_empty_retries += 1
|
|
498
|
+
logger.warning(
|
|
499
|
+
"Streaming empty response after tools; re-prompting for "
|
|
500
|
+
"final answer (retry %d/%d)",
|
|
501
|
+
_empty_retries,
|
|
502
|
+
self._max_empty_retries,
|
|
503
|
+
)
|
|
504
|
+
context.messages.append(AIMessage(role="user", content=_EMPTY_RETRY_NUDGE))
|
|
505
|
+
continue
|
|
468
506
|
return
|
|
469
507
|
|
|
508
|
+
_saw_tool_call_any = True
|
|
509
|
+
|
|
470
510
|
# External tools: provider executed them internally.
|
|
471
511
|
# If ExternalToolHandler is set, hooks were already fired
|
|
472
512
|
# inline during streaming (see StreamToolCall handling above).
|
|
@@ -21,15 +21,30 @@ class ToolEviction:
|
|
|
21
21
|
stored in a FIFO-bounded buffer and replaced with a head/tail preview.
|
|
22
22
|
The ``read_tool_result`` tool definition is injected into the AI
|
|
23
23
|
context so the agent can paginate back through the full output.
|
|
24
|
+
|
|
25
|
+
The store is scoped per room: the eviction buffer lives on a channel
|
|
26
|
+
object shared by every room the channel serves, so an unscoped buffer
|
|
27
|
+
would leak one conversation's tool output into another (and inject
|
|
28
|
+
the re-read tool into rooms that evicted nothing). The room comes
|
|
29
|
+
from the tool-loop context; paths outside a loop share one fallback
|
|
30
|
+
scope.
|
|
24
31
|
"""
|
|
25
32
|
|
|
26
33
|
def __init__(self, threshold_tokens: int = 5000) -> None:
|
|
27
34
|
self.threshold_tokens = threshold_tokens
|
|
28
|
-
self._store: OrderedDict[str, str] = OrderedDict()
|
|
35
|
+
self._store: OrderedDict[tuple[str, str], str] = OrderedDict()
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def _room_scope() -> str:
|
|
39
|
+
from roomkit.channels.ai import _current_loop_ctx
|
|
40
|
+
|
|
41
|
+
ctx = _current_loop_ctx.get()
|
|
42
|
+
return (ctx.room_id if ctx is not None else None) or ""
|
|
29
43
|
|
|
30
44
|
@property
|
|
31
45
|
def has_evicted(self) -> bool:
|
|
32
|
-
|
|
46
|
+
room = self._room_scope()
|
|
47
|
+
return any(key[0] == room for key in self._store)
|
|
33
48
|
|
|
34
49
|
def maybe_evict(self, result: str, tool_call_id: str = "") -> str:
|
|
35
50
|
"""Evict large results to the store, returning a preview."""
|
|
@@ -38,7 +53,7 @@ class ToolEviction:
|
|
|
38
53
|
return result
|
|
39
54
|
|
|
40
55
|
result_id = f"evicted_{tool_call_id}" if tool_call_id else f"evicted_{id(result)}"
|
|
41
|
-
self._store[result_id] = result
|
|
56
|
+
self._store[(self._room_scope(), result_id)] = result
|
|
42
57
|
while len(self._store) > _MAX_EVICTED:
|
|
43
58
|
self._store.popitem(last=False)
|
|
44
59
|
|
|
@@ -71,11 +86,11 @@ class ToolEviction:
|
|
|
71
86
|
offset = arguments.get("offset", 0)
|
|
72
87
|
limit = arguments.get("limit", 200)
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
room = self._room_scope()
|
|
90
|
+
full_result = self._store.get((room, result_id))
|
|
75
91
|
if full_result is None:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
92
|
+
available = [rid for scope, rid in self._store if scope == room]
|
|
93
|
+
return json.dumps({"error": f"Result '{result_id}' not found", "available": available})
|
|
79
94
|
|
|
80
95
|
# Char budget per page: threshold_tokens chars ≈ threshold/4 tokens of
|
|
81
96
|
# content, leaving ample headroom for JSON escaping (worst case 2×)
|
|
@@ -89,16 +89,44 @@ class _ToolLoopContext:
|
|
|
89
89
|
activated_skills: set[str] = field(default_factory=set)
|
|
90
90
|
all_context_tools: list[Any] = field(default_factory=list)
|
|
91
91
|
current_participant_role: str | None = None
|
|
92
|
+
room_id: str | None = None
|
|
92
93
|
steering_queue: asyncio.Queue[SteeringDirective] = field(default_factory=asyncio.Queue)
|
|
93
94
|
cancel_event: asyncio.Event = field(default_factory=asyncio.Event)
|
|
94
95
|
loop_id: str = ""
|
|
95
96
|
|
|
97
|
+
@classmethod
|
|
98
|
+
def for_loop(cls, parent: _ToolLoopContext | None, room_id: str | None) -> _ToolLoopContext:
|
|
99
|
+
"""Create a tool-loop context inheriting per-turn state from *parent*.
|
|
100
|
+
|
|
101
|
+
_build_context ran under the parent (handle_event) ctx and stamped the
|
|
102
|
+
turn's full toolset there — without this inheritance the per-round
|
|
103
|
+
tools re-application never fires (skill-gated tools would stay hidden
|
|
104
|
+
after activation) and per-call allowlist accessors see nothing.
|
|
105
|
+
"""
|
|
106
|
+
ctx = cls()
|
|
107
|
+
ctx.loop_id = str(id(ctx))
|
|
108
|
+
if parent is not None:
|
|
109
|
+
ctx.current_participant_role = parent.current_participant_role
|
|
110
|
+
ctx.all_context_tools = parent.all_context_tools
|
|
111
|
+
ctx.room_id = room_id or (parent.room_id if parent else None)
|
|
112
|
+
return ctx
|
|
113
|
+
|
|
96
114
|
|
|
97
115
|
_current_loop_ctx: contextvars.ContextVar[_ToolLoopContext | None] = contextvars.ContextVar(
|
|
98
116
|
"_current_loop_ctx", default=None
|
|
99
117
|
)
|
|
100
118
|
|
|
101
119
|
|
|
120
|
+
# Corrective nudge re-injected when a generation round ends after tool calls
|
|
121
|
+
# without any final text (common with small local models): the tool results
|
|
122
|
+
# are in context, the model just failed to verbalize the answer. Re-prompting
|
|
123
|
+
# for the final answer recovers it. Bounded by ``max_empty_retries``.
|
|
124
|
+
_EMPTY_RETRY_NUDGE = (
|
|
125
|
+
"You called tools and already have their results above. Now write your "
|
|
126
|
+
"final answer to the user in plain text. Do not call any more tools."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
102
130
|
class AIChannel(
|
|
103
131
|
AIStreamingMixin,
|
|
104
132
|
AIGenerationMixin,
|
|
@@ -129,9 +157,11 @@ class AIChannel(
|
|
|
129
157
|
max_tool_rounds: int = 200,
|
|
130
158
|
tool_loop_timeout_seconds: float | None = 300.0,
|
|
131
159
|
tool_loop_warn_after: int = 50,
|
|
160
|
+
max_empty_retries: int = 1,
|
|
132
161
|
retry_policy: RetryPolicy | None = None,
|
|
133
162
|
fallback_provider: AIProvider | None = None,
|
|
134
163
|
skills: SkillRegistry | None = None,
|
|
164
|
+
skills_in_prompt: bool = True,
|
|
135
165
|
script_executor: ScriptExecutor | None = None,
|
|
136
166
|
sandbox: SandboxExecutor | None = None,
|
|
137
167
|
external_tool_handler: ExternalToolHandler | None = None,
|
|
@@ -157,9 +187,15 @@ class AIChannel(
|
|
|
157
187
|
self._max_tool_rounds = max_tool_rounds
|
|
158
188
|
self._tool_loop_timeout_seconds = tool_loop_timeout_seconds
|
|
159
189
|
self._tool_loop_warn_after = tool_loop_warn_after
|
|
190
|
+
self._max_empty_retries = max_empty_retries
|
|
160
191
|
self._retry_policy = retry_policy
|
|
161
192
|
self._fallback_provider = fallback_provider
|
|
162
193
|
self._skills = skills
|
|
194
|
+
# Hosts that render their own skills manifest inside ``system_prompt``
|
|
195
|
+
# (e.g. positioned above a prompt-cache boundary) set this to False to
|
|
196
|
+
# skip the automatic preamble+XML injection while keeping the skill
|
|
197
|
+
# activation tools.
|
|
198
|
+
self._skills_in_prompt = skills_in_prompt
|
|
163
199
|
self._script_executor = script_executor
|
|
164
200
|
self._sandbox = sandbox
|
|
165
201
|
self._memory = memory or SlidingWindowMemory(max_events=max_context_events)
|
|
@@ -310,14 +346,24 @@ class AIChannel(
|
|
|
310
346
|
|
|
311
347
|
# Resolve participant role for role-based tool policy.
|
|
312
348
|
# Set on a per-invocation _ToolLoopContext visible via contextvar so that
|
|
313
|
-
# _build_context and the tool loop methods can read it.
|
|
349
|
+
# _build_context and the tool loop methods can read it. ``room_id``
|
|
350
|
+
# rides the same contextvar: the channel object is registered once
|
|
351
|
+
# per channel_id and shared by every room it serves, so per-call
|
|
352
|
+
# room resolution (``current_tool_room_id``) is the only safe way
|
|
353
|
+
# for tool handlers to learn the originating room.
|
|
314
354
|
event_ctx = _ToolLoopContext()
|
|
315
355
|
event_ctx.current_participant_role = self._resolve_participant_role(event, context)
|
|
356
|
+
event_ctx.room_id = context.room.id if context.room else event.room_id
|
|
316
357
|
token = _current_loop_ctx.set(event_ctx)
|
|
317
358
|
try:
|
|
318
359
|
raw_tools = binding.metadata.get("tools", [])
|
|
360
|
+
# A config_provider may deliver tools at _build_context time even
|
|
361
|
+
# when the binding carries no snapshot — route to the tool loop
|
|
362
|
+
# so those tools are executable. An empty turn toolset just runs
|
|
363
|
+
# the loop for a single round.
|
|
319
364
|
has_tools = (
|
|
320
365
|
bool(raw_tools)
|
|
366
|
+
or self._config_provider is not None
|
|
321
367
|
or bool(self._user_tools)
|
|
322
368
|
or bool(self._injected_tools)
|
|
323
369
|
or (self._skills is not None and self._skills.skill_count > 0)
|
|
@@ -148,22 +148,15 @@ class EventRouter:
|
|
|
148
148
|
|
|
149
149
|
result = BroadcastResult()
|
|
150
150
|
|
|
151
|
-
# Check source can write
|
|
152
|
-
|
|
151
|
+
# Check source can write (RFC §7.5). Inbound events from non-writable
|
|
152
|
+
# sources are already blocked before broadcast in the inbound pipeline;
|
|
153
|
+
# this guards reentry events and any direct broadcast callers.
|
|
154
|
+
if not source_binding.can_write:
|
|
153
155
|
logger.debug(
|
|
154
|
-
"Source %s
|
|
155
|
-
source_binding.channel_id,
|
|
156
|
-
extra={"room_id": event.room_id, "channel_id": source_binding.channel_id},
|
|
157
|
-
)
|
|
158
|
-
reset_span(broadcast_token)
|
|
159
|
-
telemetry.end_span(span_id, attributes={"target_count": 0})
|
|
160
|
-
return result
|
|
161
|
-
|
|
162
|
-
# Check source is not muted
|
|
163
|
-
if source_binding.muted:
|
|
164
|
-
logger.debug(
|
|
165
|
-
"Source %s is muted",
|
|
156
|
+
"Source %s cannot write (access=%s, muted=%s) — not broadcasting",
|
|
166
157
|
source_binding.channel_id,
|
|
158
|
+
source_binding.access,
|
|
159
|
+
source_binding.muted,
|
|
167
160
|
extra={"room_id": event.room_id, "channel_id": source_binding.channel_id},
|
|
168
161
|
)
|
|
169
162
|
reset_span(broadcast_token)
|
|
@@ -53,6 +53,7 @@ from roomkit.core.mixins import (
|
|
|
53
53
|
InboundStreamingMixin,
|
|
54
54
|
RealtimeOpsMixin,
|
|
55
55
|
RecordingMixin,
|
|
56
|
+
RegenerateMixin,
|
|
56
57
|
RoomLifecycleMixin,
|
|
57
58
|
SourceOpsMixin,
|
|
58
59
|
VoiceOpsMixin,
|
|
@@ -60,6 +61,7 @@ from roomkit.core.mixins import (
|
|
|
60
61
|
from roomkit.core.transcoder import DefaultContentTranscoder
|
|
61
62
|
from roomkit.identity.base import IdentityResolver
|
|
62
63
|
from roomkit.models.channel import RateLimit
|
|
64
|
+
from roomkit.models.context import RoomContext
|
|
63
65
|
from roomkit.models.enums import (
|
|
64
66
|
ChannelType,
|
|
65
67
|
EventStatus,
|
|
@@ -105,6 +107,7 @@ class RoomKit(
|
|
|
105
107
|
InboundIdentityMixin,
|
|
106
108
|
InboundLockedMixin,
|
|
107
109
|
InboundStreamingMixin,
|
|
110
|
+
RegenerateMixin,
|
|
108
111
|
ChannelOpsMixin,
|
|
109
112
|
RoomLifecycleMixin,
|
|
110
113
|
VoiceOpsMixin,
|
|
@@ -510,19 +513,23 @@ class RoomKit(
|
|
|
510
513
|
)
|
|
511
514
|
token = set_current_span(span_id, telemetry_ctx=telemetry.get_span_context(span_id))
|
|
512
515
|
try:
|
|
516
|
+
# Direct injection traverses the SAME locked pipeline as inbound
|
|
517
|
+
# (RFC §10.5): index assignment, BEFORE_BROADCAST hooks, edit/delete
|
|
518
|
+
# handling, source write-permission gate, persistence, broadcast,
|
|
519
|
+
# reentry drain and AFTER_BROADCAST hooks. This keeps a single
|
|
520
|
+
# validation/hooks/indexing/persistence model across entry points.
|
|
521
|
+
pending_after_broadcast: list[tuple[RoomEvent, RoomContext]] = []
|
|
513
522
|
async with self._lock_manager.locked(room_id):
|
|
514
|
-
count = await self._store.get_event_count(room_id)
|
|
515
|
-
event = event.model_copy(update={"index": count})
|
|
516
|
-
await self._persist_event(event)
|
|
517
|
-
|
|
518
523
|
context = await self._build_context(room_id)
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
room_id, HookTrigger.AFTER_BROADCAST, event, context
|
|
524
|
+
result = await self._process_locked(
|
|
525
|
+
event,
|
|
526
|
+
room_id,
|
|
527
|
+
context,
|
|
528
|
+
pending_after_broadcast_out=pending_after_broadcast,
|
|
525
529
|
)
|
|
530
|
+
event = result.event or event
|
|
531
|
+
# AFTER_BROADCAST runs outside the room lock (RFC §10.1)
|
|
532
|
+
await self._run_deferred_after_broadcast(room_id, pending_after_broadcast)
|
|
526
533
|
|
|
527
534
|
telemetry.end_span(span_id)
|
|
528
535
|
except Exception as exc:
|
|
@@ -14,6 +14,7 @@ from roomkit.core.mixins.inbound_locked import InboundLockedMixin
|
|
|
14
14
|
from roomkit.core.mixins.inbound_streaming import InboundStreamingMixin
|
|
15
15
|
from roomkit.core.mixins.realtime_ops import RealtimeOpsMixin
|
|
16
16
|
from roomkit.core.mixins.recording import RecordingMixin
|
|
17
|
+
from roomkit.core.mixins.regenerate import RegenerateMixin
|
|
17
18
|
from roomkit.core.mixins.room_lifecycle import RoomLifecycleMixin
|
|
18
19
|
from roomkit.core.mixins.source_ops import SourceOpsMixin
|
|
19
20
|
from roomkit.core.mixins.voice_ops import VoiceOpsMixin
|
|
@@ -33,6 +34,7 @@ __all__ = [
|
|
|
33
34
|
"InboundStreamingMixin",
|
|
34
35
|
"RealtimeOpsMixin",
|
|
35
36
|
"RecordingMixin",
|
|
37
|
+
"RegenerateMixin",
|
|
36
38
|
"RoomLifecycleMixin",
|
|
37
39
|
"SourceOpsMixin",
|
|
38
40
|
"VoiceOpsMixin",
|
|
@@ -9,11 +9,13 @@ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
|
|
|
9
9
|
from roomkit.core.exceptions import ChannelNotRegisteredError
|
|
10
10
|
from roomkit.core.mixins.helpers import HelpersMixin
|
|
11
11
|
from roomkit.core.mixins.inbound_identity import _IdentityBlockedError
|
|
12
|
+
from roomkit.models.context import RoomContext
|
|
12
13
|
from roomkit.models.delivery import InboundMessage, InboundResult
|
|
13
14
|
from roomkit.models.enums import (
|
|
14
15
|
ChannelType,
|
|
15
16
|
HookTrigger,
|
|
16
17
|
)
|
|
18
|
+
from roomkit.models.event import RoomEvent
|
|
17
19
|
|
|
18
20
|
if TYPE_CHECKING:
|
|
19
21
|
from roomkit.channels.base import Channel
|
|
@@ -47,6 +49,7 @@ class InboundHost(Protocol):
|
|
|
47
49
|
Cross-mixin methods (provided by other mixins in the MRO):
|
|
48
50
|
_resolve_identity: From :class:`InboundIdentityMixin`.
|
|
49
51
|
_process_locked: From :class:`InboundLockedMixin`.
|
|
52
|
+
_run_deferred_after_broadcast: From :class:`InboundLockedMixin`.
|
|
50
53
|
_process_streaming_responses: From :class:`InboundStreamingMixin`.
|
|
51
54
|
create_room: From :class:`RoomLifecycleMixin`.
|
|
52
55
|
attach_channel: From :class:`ChannelOpsMixin`.
|
|
@@ -88,6 +91,7 @@ class InboundMixin(HelpersMixin):
|
|
|
88
91
|
# Cross-mixin methods — attribute annotations avoid MRO shadowing
|
|
89
92
|
_resolve_identity: Any # see InboundHost
|
|
90
93
|
_process_locked: Any # see InboundHost
|
|
94
|
+
_run_deferred_after_broadcast: Any # see InboundHost
|
|
91
95
|
_process_streaming_responses: Any # see InboundHost
|
|
92
96
|
create_room: Any # see InboundHost
|
|
93
97
|
attach_channel: Any # see InboundHost
|
|
@@ -181,6 +185,11 @@ class InboundMixin(HelpersMixin):
|
|
|
181
185
|
# Let channel process inbound
|
|
182
186
|
event = await channel.handle_inbound(message, context)
|
|
183
187
|
|
|
188
|
+
# Caller-requested visibility (e.g. ``"transport"`` for a proactive
|
|
189
|
+
# notification that must not wake the room's intelligence channel).
|
|
190
|
+
if message.visibility != "all" and event.visibility == "all":
|
|
191
|
+
event = event.model_copy(update={"visibility": message.visibility})
|
|
192
|
+
|
|
184
193
|
# Identity resolution pipeline (RFC §7)
|
|
185
194
|
try:
|
|
186
195
|
event, resolved_identity, pending_id_result = await self._resolve_identity(
|
|
@@ -191,6 +200,7 @@ class InboundMixin(HelpersMixin):
|
|
|
191
200
|
|
|
192
201
|
# Process under room lock
|
|
193
202
|
pending_streams: list[Any] = []
|
|
203
|
+
pending_after_broadcast: list[tuple[RoomEvent, RoomContext]] = []
|
|
194
204
|
async with self._lock_manager.locked(room_id):
|
|
195
205
|
try:
|
|
196
206
|
result: InboundResult = await asyncio.wait_for(
|
|
@@ -201,6 +211,7 @@ class InboundMixin(HelpersMixin):
|
|
|
201
211
|
resolved_identity=resolved_identity,
|
|
202
212
|
pending_id_result=pending_id_result,
|
|
203
213
|
pending_streams_out=pending_streams,
|
|
214
|
+
pending_after_broadcast_out=pending_after_broadcast,
|
|
204
215
|
),
|
|
205
216
|
timeout=self._process_timeout,
|
|
206
217
|
)
|
|
@@ -218,6 +229,11 @@ class InboundMixin(HelpersMixin):
|
|
|
218
229
|
)
|
|
219
230
|
return InboundResult(blocked=True, reason="process_timeout")
|
|
220
231
|
|
|
232
|
+
# Run AFTER_BROADCAST async hooks now that the room lock is released
|
|
233
|
+
# (RFC §10.1) — a slow observer hook no longer blocks concurrent
|
|
234
|
+
# process_inbound calls for the same room.
|
|
235
|
+
await self._run_deferred_after_broadcast(room_id, pending_after_broadcast)
|
|
236
|
+
|
|
221
237
|
# Handle streaming responses outside lock (TTS delivery can take seconds;
|
|
222
238
|
# holding the lock would block concurrent process_inbound calls)
|
|
223
239
|
if pending_streams:
|