roomkit 0.7.2__tar.gz → 0.9.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.9.0}/PKG-INFO +6 -5
- {roomkit-0.7.2 → roomkit-0.9.0}/README.md +2 -2
- {roomkit-0.7.2 → roomkit-0.9.0}/pyproject.toml +2 -2
- roomkit-0.9.0/src/roomkit/_version.py +1 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_context.py +13 -7
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_events.py +6 -1
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_generation.py +33 -6
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_streaming.py +142 -27
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_audio.py +152 -81
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_response.py +37 -25
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_speech.py +16 -12
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_tools.py +45 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_transcription.py +6 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_tool_eviction.py +22 -7
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/ai.py +60 -1
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/base.py +11 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/realtime_voice.py +42 -10
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/event_router.py +7 -14
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/framework.py +17 -10
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/__init__.py +2 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/helpers.py +36 -4
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/inbound.py +16 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/inbound_locked.py +158 -64
- roomkit-0.9.0/src/roomkit/core/mixins/regenerate.py +143 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/base.py +18 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/sliding_window.py +5 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/channel.py +10 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/delivery.py +5 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telegram/bot.py +36 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/__init__.py +3 -0
- roomkit-0.9.0/src/roomkit/tools/context.py +48 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/_mulaw.py +14 -8
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/local.py +149 -24
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/sip.py +10 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/sip_audio.py +4 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/aec/webrtc.py +33 -13
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/fastrtc_transport.py +14 -4
- roomkit-0.9.0/src/roomkit/voice/utils.py +44 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_ai_streaming_thinking.py +126 -0
- roomkit-0.9.0/tests/test_channels/test_ai_empty_retry.py +137 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_ai_skill_gating.py +52 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_ai_tool_loop.py +3 -2
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_fastrtc_realtime_transport.py +25 -0
- roomkit-0.9.0/tests/test_inbound_visibility.py +58 -0
- roomkit-0.9.0/tests/test_integration/test_regenerate.py +132 -0
- roomkit-0.9.0/tests/test_realtime_resample_offload.py +265 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_voice.py +147 -1
- roomkit-0.9.0/tests/test_recent_events_window.py +83 -0
- roomkit-0.9.0/tests/test_rfc_conformance.py +230 -0
- roomkit-0.9.0/tests/test_tool_context.py +159 -0
- roomkit-0.9.0/tests/test_tool_eviction_room_scope.py +71 -0
- roomkit-0.9.0/tests/test_voice_dsp_vectorized.py +73 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_local.py +173 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/backends/test_sip.py +41 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/test_webrtc_aec.py +19 -0
- roomkit-0.7.2/src/roomkit/_version.py +0 -1
- roomkit-0.7.2/src/roomkit/voice/utils.py +0 -22
- {roomkit-0.7.2 → roomkit-0.9.0}/.gitignore +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/AGENTS.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/LICENSE +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/README.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/ai-channels.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/api-reference.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/architecture.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/hooks.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/identity-and-realtime.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/installation.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/ollama-provider.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/orchestration.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/overview.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/quickstart.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/realtime-voice.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/resilience.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/rooms-and-channels.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/storage.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/testing.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/transport-providers.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/voice-channels.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/c7/voice-pipeline.md +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/architecture.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/avatar-pipeline.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/message-flow.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/orchestration.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/room-lifecycle.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/video-pipeline.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/voice-orchestration.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/docs/diagrams/voice-pipeline.svg +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/llms-full.txt +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/llms.txt +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/ai_docs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_policy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_resilience.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_steering.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_ai_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_dangling_recovery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_context.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_skills.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_tool_recovery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_realtime_tool_search.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_sandbox_handlers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_skill_constants.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_skill_handlers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_task_planner.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_tool_search_constants.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_turn_config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_video_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_voice_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_voice_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_voice_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_voice_tts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/_voice_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/agent.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/av.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/cli.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/realtime_av.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/video.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/voice.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/channels/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/console/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/console/_display.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/console/_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/console/_state.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/circuit_breaker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/delivery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/exceptions.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/inbound_router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/locks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/channel_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/delegation.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/deliver.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/greeting.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/hooks_api.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/inbound_identity.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/inbound_streaming.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/realtime_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/recording.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/room_lifecycle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/source_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/mixins/voice_ops.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/rate_limiter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/retry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/task_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/core/transcoder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/delivery/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/delivery/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/delivery/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/delivery/redis.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/delivery/serialization.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/delivery/worker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/identity/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/identity/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/identity/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/knowledge/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/knowledge/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/knowledge/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/knowledge/postgres.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/budget_aware.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/compacting.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/retrieval.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/summarizing.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/memory/token_estimator.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/context.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/enums.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/framework_event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/hook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/identity.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/participant.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/pending_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/room.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/session_event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/steering.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/store_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/streaming.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/task.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/tool_call.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/trace.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/models/vision_event.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/handoff.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/session_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/state.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/status_bus.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/strategies/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/strategies/loop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/strategies/pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/strategies/supervisor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/strategies/swarm.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/orchestration/tool_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/ai/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/ai/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/ai/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anam/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anam/_convert.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anam/avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anam/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anam/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anthropic/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anthropic/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/anthropic/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/azure/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/azure/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/azure/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/elasticemail/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/elasticemail/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/elasticemail/email.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/elevenlabs/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/elevenlabs/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/elevenlabs/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/email/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/email/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/email/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/gemini/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/gemini/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/gemini/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/gemini/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/gemini/schema.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http/provider.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/http_errors.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/messenger/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/messenger/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/messenger/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/messenger/facebook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/messenger/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/messenger/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/mistral/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/mistral/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/mistral/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/ollama/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/ollama/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/ollama/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/openai/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/openai/ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/openai/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/openai/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/personaplex/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/personaplex/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/personaplex/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/rcs/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/rcs/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/rcs/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sendgrid/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sendgrid/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sendgrid/email.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sinch/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sinch/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sinch/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sms/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sms/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sms/meta.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sms/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/sms/phone.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/bot_framework.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/conversation_store.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/teams/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telegram/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telegram/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telegram/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telegram/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telegram/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telnyx/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telnyx/_signature.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telnyx/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telnyx/rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/telnyx/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/twilio/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/twilio/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/twilio/rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/twilio/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/twilio/webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/url_safety.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/vllm/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/vllm/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/voicemeup/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/voicemeup/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/voicemeup/sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/whatsapp/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/whatsapp/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/whatsapp/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/whatsapp/personal.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/xai/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/xai/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/providers/xai/realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/py.typed +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/realtime/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/realtime/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/realtime/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/recorder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/recorder/_pyav_mux.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/recorder/_room_recorder_manager.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/recorder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/recorder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/recorder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sandbox/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sandbox/executor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sandbox/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sandbox/tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/scoring/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/scoring/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/scoring/hook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/scoring/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/scoring/tracker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/skills/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/skills/executor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/skills/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/skills/parser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/skills/registry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sources/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sources/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sources/neonize.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sources/sse.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/sources/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/store/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/store/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/store/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/store/postgres.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tasks/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tasks/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tasks/cache.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tasks/delegate.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tasks/memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tasks/models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/console.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/context.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/noop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/opentelemetry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/telemetry/pyroscope.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/compose.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/external.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/human_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/mcp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/tools/policy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/ai_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/avatar/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/avatar/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/avatar/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/avatar/musetalk.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/avatar/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/local.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/screen.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/sip.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/backends/websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/decoder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/decoder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/decoder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/decoder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/encoder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/encoder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/encoder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/engine.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/censor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/mediapipe_face_touch.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/mock_face_touch.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/watermark.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/filter/yolo.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/image.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/rich.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/subtitle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/overlay/text.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/resizer/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/resizer/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/resizer/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/resizer/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/transform/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/transform/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/transform/effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/pipeline/transform/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/recorder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/recorder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/recorder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/recorder/opencv.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/recorder/pyav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/video_frame.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/encode.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/gemini.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/openai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/screen_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/screen_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/video/vision/webcam_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/audio_frame.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/_sip_types.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/sip_auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/sip_calling.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/twilio_ws.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/backends/webtransport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/inbound.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/interruption.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/aec/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/aec/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/aec/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/aec/speex.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/agc/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/agc/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/agc/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/backchannel/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/backchannel/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/backchannel/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/debug_taps.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/denoiser/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/denoiser/aicoustics.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/denoiser/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/denoiser/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/denoiser/rnnoise.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/denoiser/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/diarization/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/diarization/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/diarization/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/diarization/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/dtmf/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/dtmf/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/dtmf/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/engine.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/mixer/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/mixer/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/mixer/numpy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/mixer/python.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/postprocessor/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/postprocessor/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/recorder/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/recorder/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/recorder/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/recorder/wav.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/resampler/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/resampler/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/resampler/linear.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/resampler/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/resampler/numpy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/resampler/sinc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/turn/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/turn/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/turn/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/turn/smart_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/vad/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/vad/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/vad/energy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/vad/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/pipeline/vad/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/pacer.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/provider.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/sip_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/realtime/ws_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/deepgram.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/gradium.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/stt/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/audio_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/filters.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/gradium.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/grok.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/mock.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/neutts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/sentence_splitter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/src/roomkit/voice/tts/sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/conftest.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/test_base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/test_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/test_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/test_redis.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/test_serialization.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/delivery/test_worker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_framework_orchestration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_handoff.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_loop_strategy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_orchestration_base.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_session_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_state.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_status_bus.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_strategy_behavioral.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_strategy_loop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_strategy_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_strategy_supervisor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_strategy_swarm.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_supervisor_inline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_supervisor_strategy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/orchestration/test_tool_audit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/providers/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/providers/gemini/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/providers/gemini/test_reconfigure_preservation.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/providers/gemini/test_schema.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/tasks/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/tasks/test_cache.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/tasks/test_delegate.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/tasks/test_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/tasks/test_models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/tasks/test_runner.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_aec_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_ai_docs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_ai_streaming_tool_loop.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_aicoustics_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_anam_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_audio_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_auto_connect.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_av_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_before_ai_generation.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channel_abc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_agent.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_ai_retry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_ai_steering.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_email.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_http.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_messenger.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_sms.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_telegram.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_turn_config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_channels/test_whatsapp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_circuit_breaker.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_cli_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_compose_tool_handlers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_configs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_console.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_dangling_recovery.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_delivery_strategies.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_describe_screen_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_describe_webcam_tool.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_drain_barge_in.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_energy_vad.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_enums.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_external_tool_handler.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_face_touch_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_framework.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_framework_events.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_framework_queries.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_framework_status_bus.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_hook_side_effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_human_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_identity_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_identity_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_inbound_rate_limit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_inbound_routing.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_ai_assistant.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_ai_chain_depth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_cross_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_dynamic_channels.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_human_ai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_identity_resolution.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_observer.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_integration/test_sin_scanning.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_interruption.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_lifecycle_hooks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_local_backend_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_locks.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_mcp_tool_provider.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_mcp_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_media_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_memory_new.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_mock_providers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_models.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_observability.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_opencv_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_opentelemetry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_outbound_audio_pacer.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_personaplex_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pipeline_debug_taps.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pipeline_engine.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pipeline_providers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pipeline_resampler.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pipeline_resampler_numpy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pipeline_resampler_sinc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_postgres_store.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_protocol_trace.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_anam_avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_anam_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_anthropic.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_azure.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_elasticemail.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_gemini.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_gemini_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_http.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_messenger.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_mistral.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_ollama.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_openai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_openai_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_personaplex_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_phone.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_sendgrid.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_sinch.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_sms_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_teams.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_teams_webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_telegram_bot.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_telegram_webhook.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_telnyx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_telnyx_rcs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_twilio.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_vllm.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_voicemeup.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_whatsapp_personal.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_providers/test_xai_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_public_api.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pyav_media_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_pyav_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_av_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_skills.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_tool_search.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_voice_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_realtime_xai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_recording_wiring.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_reentry_block_side_effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_resilience.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_response_metadata.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_response_visibility.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_retrieval_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_rnnoise.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_router.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_rtp_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_scoring.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_screen_capture_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_screen_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_session_started.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sherpa_onnx_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sherpa_onnx_vad.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sip_auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sip_dial.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sip_helpers.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sip_realtime_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sip_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_skills.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_skills_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_smart_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_smoke_quickstart.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_source_rate_limit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sources.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sources_init.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sources_neonize.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sources_sse.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_sources_websocket.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_speex_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_store_activity.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_store_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_store_postgres.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_stt_qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_summarizing_memory.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_supervisor.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_task_planner.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_task_utils.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_telemetry.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_telemetry_pyroscope.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tool_policy.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tool_protocol.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_transport_auth.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tts_elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tts_grok.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tts_neutts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tts_qwen3.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_tts_text_split.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_turn_detection.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_twilio_ws_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_unified_tool_call.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_vad_debug_logging.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_ai_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_channel.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_local.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_pipeline.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_pipeline_config.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_recording.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_video_transform.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_vision_gemini.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_vision_openai.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_batch_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_binding_gate.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_channel_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_frame_limit.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_inbound.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_integration.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_map.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_say_play.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_sherpa_onnx.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_streaming_ai_tts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_streaming_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_voice_webtransport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_wav_recorder.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_websocket_lifecycle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/test_yolo_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_av_channel_fastrtc.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_fastrtc_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_overlay_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_overlay_image.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_overlay_rich.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_overlay_subtitle.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_overlay_text.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_screen_input.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_screen_input_tools.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_video_bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_video_effects.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_watermark_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_websocket_avatar.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/video/test_websocket_video_backend.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/backends/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/backends/test_rtp.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/backends/test_sip_coverage.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/backends/test_webtransport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/test_aicoustics_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/test_rnnoise_denoiser.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/test_sherpa_diarization.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/test_smart_turn.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/pipeline/test_speex_aec.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/realtime/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/realtime/test_fastrtc_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/realtime/test_realtime_bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/realtime/test_ws_transport.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/stt/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/stt/test_deepgram.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/stt/test_gradium_stt.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/stt/test_qwen3_asr.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/test_bridge.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/test_tts_filters.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/test_voice_tts_filter.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/tts/__init__.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/tts/test_elevenlabs.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.0}/tests/voice/tts/test_gradium_tts.py +0 -0
- {roomkit-0.7.2 → roomkit-0.9.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.9.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/
|
|
@@ -25,7 +25,7 @@ Requires-Dist: pydantic>=2.9
|
|
|
25
25
|
Provides-Extra: aicoustics
|
|
26
26
|
Requires-Dist: aic-sdk>=2.1; extra == 'aicoustics'
|
|
27
27
|
Provides-Extra: all
|
|
28
|
-
Requires-Dist: aiortp>=0.3.
|
|
28
|
+
Requires-Dist: aiortp>=0.3.2; extra == 'all'
|
|
29
29
|
Requires-Dist: aiosipua[rtp]>=0.4.1; extra == 'all'
|
|
30
30
|
Requires-Dist: anthropic>=0.30; extra == 'all'
|
|
31
31
|
Requires-Dist: asyncpg>=0.29; extra == 'all'
|
|
@@ -162,7 +162,7 @@ Requires-Dist: websockets>=13.0; extra == 'realtime-openai'
|
|
|
162
162
|
Provides-Extra: redis
|
|
163
163
|
Requires-Dist: redis>=5.0; extra == 'redis'
|
|
164
164
|
Provides-Extra: rtp
|
|
165
|
-
Requires-Dist: aiortp>=0.3.
|
|
165
|
+
Requires-Dist: aiortp>=0.3.2; extra == 'rtp'
|
|
166
166
|
Provides-Extra: screen-capture
|
|
167
167
|
Requires-Dist: mss>=9.0; extra == 'screen-capture'
|
|
168
168
|
Provides-Extra: screen-input
|
|
@@ -170,6 +170,7 @@ Requires-Dist: pyautogui>=0.9; extra == 'screen-input'
|
|
|
170
170
|
Provides-Extra: sherpa-onnx
|
|
171
171
|
Requires-Dist: sherpa-onnx>=1.10; extra == 'sherpa-onnx'
|
|
172
172
|
Provides-Extra: sip
|
|
173
|
+
Requires-Dist: aiortp>=0.3.2; extra == 'sip'
|
|
173
174
|
Requires-Dist: aiosipua[rtp]>=0.4.1; extra == 'sip'
|
|
174
175
|
Provides-Extra: smart-turn
|
|
175
176
|
Requires-Dist: numpy>=1.26; extra == 'smart-turn'
|
|
@@ -350,7 +351,7 @@ For development:
|
|
|
350
351
|
git clone https://github.com/roomkit-live/roomkit.git
|
|
351
352
|
cd roomkit
|
|
352
353
|
uv sync --extra dev
|
|
353
|
-
make all # ruff check +
|
|
354
|
+
make all # ruff check + ty + pytest
|
|
354
355
|
```
|
|
355
356
|
|
|
356
357
|
Requires **Python 3.12+**.
|
|
@@ -729,7 +730,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.
|
|
|
729
730
|
|
|
730
731
|
```bash
|
|
731
732
|
uv sync --extra dev
|
|
732
|
-
make all # ruff check +
|
|
733
|
+
make all # ruff check + ty + pytest
|
|
733
734
|
```
|
|
734
735
|
|
|
735
736
|
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.
|
|
@@ -52,8 +52,8 @@ video = ["av>=12.0.0", "numpy>=1.26"]
|
|
|
52
52
|
video-overlay = ["Pillow>=10.0"]
|
|
53
53
|
yolo = ["ultralytics>=8.3"]
|
|
54
54
|
mediapipe = ["mediapipe>=0.10"]
|
|
55
|
-
rtp = ["aiortp>=0.3.
|
|
56
|
-
sip = ["aiosipua[rtp]>=0.4.1"]
|
|
55
|
+
rtp = ["aiortp>=0.3.2"]
|
|
56
|
+
sip = ["aiosipua[rtp]>=0.4.1", "aiortp>=0.3.2"]
|
|
57
57
|
webtransport = ["aioquic>=1.0"]
|
|
58
58
|
twilio = ["twilio>=9.0"]
|
|
59
59
|
phonenumbers = ["phonenumbers>=8.13"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.9.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:
|
|
@@ -13,6 +13,11 @@ if TYPE_CHECKING:
|
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger("roomkit.channels.ai")
|
|
15
15
|
|
|
16
|
+
# Per-event cap on the ``thinking`` payload published to the realtime bus.
|
|
17
|
+
# Producers that must deliver longer text without loss (e.g. the streaming
|
|
18
|
+
# coalescer) split it into multiple events of at most this size.
|
|
19
|
+
THINKING_PREVIEW_LIMIT = 1000
|
|
20
|
+
|
|
16
21
|
|
|
17
22
|
class AIEventsMixin:
|
|
18
23
|
"""Publishes tool-call and thinking ephemeral events over the realtime backend."""
|
|
@@ -80,7 +85,7 @@ class AIEventsMixin:
|
|
|
80
85
|
"""Publish a thinking ephemeral event. Best-effort, never breaks the loop."""
|
|
81
86
|
if self._realtime is None or not room_id:
|
|
82
87
|
return
|
|
83
|
-
preview_limit =
|
|
88
|
+
preview_limit = THINKING_PREVIEW_LIMIT
|
|
84
89
|
data: dict[str, Any] = {
|
|
85
90
|
"thinking": thinking[:preview_limit] if len(thinking) > preview_limit else thinking,
|
|
86
91
|
"thinking_length": len(thinking),
|
|
@@ -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():
|
|
@@ -8,6 +8,7 @@ import time
|
|
|
8
8
|
from collections.abc import AsyncIterator
|
|
9
9
|
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
|
|
10
10
|
|
|
11
|
+
from roomkit.channels._ai_events import THINKING_PREVIEW_LIMIT
|
|
11
12
|
from roomkit.models.channel import ChannelOutput
|
|
12
13
|
from roomkit.models.enums import ChannelType
|
|
13
14
|
from roomkit.models.event import RoomEvent
|
|
@@ -41,6 +42,69 @@ if TYPE_CHECKING:
|
|
|
41
42
|
logger = logging.getLogger("roomkit.channels.ai")
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
class _ThinkingCoalescer:
|
|
46
|
+
"""Batches per-token thinking deltas into one ``THINKING_DELTA`` publish per window.
|
|
47
|
+
|
|
48
|
+
Reasoning models emit one ``StreamThinkingDelta`` per token, and publishing
|
|
49
|
+
each on the realtime bus is one ephemeral event + fan-out + WS serialise per
|
|
50
|
+
token — thousands for a long trace, all on the shared event loop. Buffering
|
|
51
|
+
and publishing once per time/size window (~80 ms / ~256 chars) cuts that
|
|
52
|
+
10-100x while keeping the reasoning visibly real-time: the UI appends deltas,
|
|
53
|
+
so a coalesced delta renders identically to many small ones. The complete
|
|
54
|
+
trace is still published verbatim at ``THINKING_END``.
|
|
55
|
+
|
|
56
|
+
A window of ``0`` ms disables batching — every delta publishes immediately.
|
|
57
|
+
Flushes larger than ``_publish_thinking_event``'s preview cap are split
|
|
58
|
+
into multiple publishes so a coalesced delta is never truncated, whatever
|
|
59
|
+
the configured size threshold.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
publish: Any,
|
|
65
|
+
room_id: str | None,
|
|
66
|
+
round_idx: int,
|
|
67
|
+
*,
|
|
68
|
+
flush_ms: float,
|
|
69
|
+
flush_chars: int,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._publish = publish
|
|
72
|
+
self._room_id = room_id
|
|
73
|
+
self._round_idx = round_idx
|
|
74
|
+
self._flush_ms = flush_ms
|
|
75
|
+
self._flush_chars = flush_chars
|
|
76
|
+
self._pending: list[str] = []
|
|
77
|
+
self._pending_len = 0
|
|
78
|
+
self._last_publish = time.monotonic()
|
|
79
|
+
|
|
80
|
+
async def add(self, delta: str) -> None:
|
|
81
|
+
"""Buffer a delta; publish the batch once the window is exceeded."""
|
|
82
|
+
self._pending.append(delta)
|
|
83
|
+
self._pending_len += len(delta)
|
|
84
|
+
if self._flush_ms <= 0:
|
|
85
|
+
await self.flush()
|
|
86
|
+
return
|
|
87
|
+
elapsed_ms = (time.monotonic() - self._last_publish) * 1000.0
|
|
88
|
+
if self._pending_len >= self._flush_chars or elapsed_ms >= self._flush_ms:
|
|
89
|
+
await self.flush()
|
|
90
|
+
|
|
91
|
+
async def flush(self) -> None:
|
|
92
|
+
"""Publish whatever is buffered, then reset the window."""
|
|
93
|
+
if not self._pending:
|
|
94
|
+
return
|
|
95
|
+
text = "".join(self._pending)
|
|
96
|
+
self._pending.clear()
|
|
97
|
+
self._pending_len = 0
|
|
98
|
+
self._last_publish = time.monotonic()
|
|
99
|
+
for i in range(0, len(text), THINKING_PREVIEW_LIMIT):
|
|
100
|
+
await self._publish(
|
|
101
|
+
EphemeralEventType.THINKING_DELTA,
|
|
102
|
+
self._room_id,
|
|
103
|
+
text[i : i + THINKING_PREVIEW_LIMIT],
|
|
104
|
+
self._round_idx,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
|
|
44
108
|
@runtime_checkable
|
|
45
109
|
class AIStreamingHost(Protocol):
|
|
46
110
|
"""Contract: capabilities a host class must provide for AIStreamingMixin.
|
|
@@ -70,6 +134,9 @@ class AIStreamingHost(Protocol):
|
|
|
70
134
|
_max_tool_rounds: int
|
|
71
135
|
_tool_loop_timeout_seconds: float | None
|
|
72
136
|
_tool_loop_warn_after: int
|
|
137
|
+
_max_empty_retries: int
|
|
138
|
+
_thinking_coalesce_ms: float
|
|
139
|
+
_thinking_coalesce_chars: int
|
|
73
140
|
_tool_handler: Any
|
|
74
141
|
_active_loops: dict[str, _ToolLoopContext]
|
|
75
142
|
_after_response_hook: Any
|
|
@@ -126,6 +193,9 @@ class AIStreamingMixin:
|
|
|
126
193
|
_max_tool_rounds: int
|
|
127
194
|
_tool_loop_timeout_seconds: float | None
|
|
128
195
|
_tool_loop_warn_after: int
|
|
196
|
+
_max_empty_retries: int
|
|
197
|
+
_thinking_coalesce_ms: float
|
|
198
|
+
_thinking_coalesce_chars: int
|
|
129
199
|
_tool_handler: Any
|
|
130
200
|
_active_loops: dict[str, Any]
|
|
131
201
|
_after_response_hook: Any
|
|
@@ -147,6 +217,16 @@ class AIStreamingMixin:
|
|
|
147
217
|
_publish_tool_event: Any # see AIStreamingHost
|
|
148
218
|
_telemetry_provider: Any # see AIStreamingHost
|
|
149
219
|
|
|
220
|
+
def _new_thinking_coalescer(self, room_id: str | None, round_idx: int) -> _ThinkingCoalescer:
|
|
221
|
+
"""Coalescer bound to this channel's publish hook and window config."""
|
|
222
|
+
return _ThinkingCoalescer(
|
|
223
|
+
self._publish_thinking_event,
|
|
224
|
+
room_id,
|
|
225
|
+
round_idx,
|
|
226
|
+
flush_ms=self._thinking_coalesce_ms,
|
|
227
|
+
flush_chars=self._thinking_coalesce_chars,
|
|
228
|
+
)
|
|
229
|
+
|
|
150
230
|
async def _start_streaming_response(
|
|
151
231
|
self, event: RoomEvent, binding: ChannelBinding, context: RoomContext
|
|
152
232
|
) -> ChannelOutput:
|
|
@@ -190,6 +270,7 @@ class AIStreamingMixin:
|
|
|
190
270
|
room_id = ai_context.room.room.id if ai_context.room else None
|
|
191
271
|
thinking_parts: list[str] = []
|
|
192
272
|
thinking_started = False
|
|
273
|
+
coalescer = self._new_thinking_coalescer(room_id, round_idx=0)
|
|
193
274
|
|
|
194
275
|
async for ev in self._provider.generate_structured_stream(ai_context):
|
|
195
276
|
if isinstance(ev, StreamThinkingDelta):
|
|
@@ -199,19 +280,17 @@ class AIStreamingMixin:
|
|
|
199
280
|
EphemeralEventType.THINKING_START, room_id, "", 0
|
|
200
281
|
)
|
|
201
282
|
thinking_parts.append(ev.thinking)
|
|
202
|
-
#
|
|
203
|
-
# (browser WS clients, etc.)
|
|
204
|
-
# arrives, not only the buffered text at
|
|
205
|
-
# ``thinking`` field carries the
|
|
283
|
+
# Buffer each delta and publish in windows on the realtime bus so
|
|
284
|
+
# remote subscribers (browser WS clients, etc.) stream the
|
|
285
|
+
# reasoning as it arrives, not only the buffered text at
|
|
286
|
+
# THINKING_END. The ``thinking`` field carries the delta, not the
|
|
206
287
|
# accumulator — clients append to their own buffer.
|
|
207
|
-
|
|
208
|
-
await self._publish_thinking_event(
|
|
209
|
-
EphemeralEventType.THINKING_DELTA, room_id, ev.thinking, 0
|
|
210
|
-
)
|
|
288
|
+
await coalescer.add(ev.thinking)
|
|
211
289
|
yield ThinkingDeltaMarker(thinking=ev.thinking)
|
|
212
290
|
elif isinstance(ev, StreamTextDelta):
|
|
213
291
|
if thinking_started and thinking_parts and room_id:
|
|
214
292
|
thinking_started = False
|
|
293
|
+
await coalescer.flush()
|
|
215
294
|
await self._publish_thinking_event(
|
|
216
295
|
EphemeralEventType.THINKING_END,
|
|
217
296
|
room_id,
|
|
@@ -224,6 +303,7 @@ class AIStreamingMixin:
|
|
|
224
303
|
# Thinking with no following text — close the boundary anyway so
|
|
225
304
|
# subscribers see the reasoning even if the model emitted nothing else.
|
|
226
305
|
if thinking_started and thinking_parts and room_id:
|
|
306
|
+
await coalescer.flush()
|
|
227
307
|
await self._publish_thinking_event(
|
|
228
308
|
EphemeralEventType.THINKING_END,
|
|
229
309
|
room_id,
|
|
@@ -235,26 +315,42 @@ class AIStreamingMixin:
|
|
|
235
315
|
self, event: RoomEvent, binding: ChannelBinding, context: RoomContext
|
|
236
316
|
) -> ChannelOutput:
|
|
237
317
|
"""Return a streaming response that handles tool calls between rounds."""
|
|
318
|
+
from roomkit.channels.ai import _current_loop_ctx
|
|
319
|
+
|
|
238
320
|
ai_context = await self._build_context(event, binding, context) # ty: ignore[unresolved-attribute]
|
|
239
321
|
ai_context, blocked = await self._fire_before_generation_hook(ai_context, event) # ty: ignore[unresolved-attribute]
|
|
240
322
|
if blocked:
|
|
241
323
|
return ChannelOutput.empty()
|
|
324
|
+
# The generator below executes when the CONSUMER iterates the
|
|
325
|
+
# stream — by then handle_event has reset the loop contextvar, so
|
|
326
|
+
# the parent ctx (participant role, room, the toolset stamped by
|
|
327
|
+
# _build_context) must be captured NOW and passed explicitly.
|
|
242
328
|
return ChannelOutput(
|
|
243
329
|
responded=True,
|
|
244
|
-
response_stream=self._run_streaming_tool_loop(
|
|
330
|
+
response_stream=self._run_streaming_tool_loop(
|
|
331
|
+
ai_context, parent_loop_ctx=_current_loop_ctx.get()
|
|
332
|
+
),
|
|
245
333
|
response_metadata=ai_context.response_metadata,
|
|
246
334
|
)
|
|
247
335
|
|
|
248
|
-
async def _run_streaming_tool_loop(
|
|
336
|
+
async def _run_streaming_tool_loop(
|
|
337
|
+
self, context: AIContext, *, parent_loop_ctx: Any | None = None
|
|
338
|
+
) -> AsyncIterator[StreamDelta]:
|
|
249
339
|
"""Stream text deltas, executing tool calls between generation rounds."""
|
|
250
|
-
from roomkit.channels.ai import
|
|
340
|
+
from roomkit.channels.ai import (
|
|
341
|
+
_EMPTY_RETRY_NUDGE,
|
|
342
|
+
_current_loop_ctx,
|
|
343
|
+
_ToolLoopContext,
|
|
344
|
+
)
|
|
251
345
|
from roomkit.telemetry.context import get_current_span
|
|
252
346
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if
|
|
257
|
-
|
|
347
|
+
# The handle_event ctx is gone from the contextvar by the time this
|
|
348
|
+
# generator runs (reset in handle_event's finally); the caller
|
|
349
|
+
# captured it at stream creation.
|
|
350
|
+
parent_ctx = parent_loop_ctx if parent_loop_ctx is not None else _current_loop_ctx.get()
|
|
351
|
+
loop_ctx = _ToolLoopContext.for_loop(
|
|
352
|
+
parent_ctx, context.room.room.id if context.room else None
|
|
353
|
+
)
|
|
258
354
|
_current_loop_ctx.set(loop_ctx)
|
|
259
355
|
self._active_loops[loop_ctx.loop_id] = loop_ctx
|
|
260
356
|
telemetry = self._telemetry_provider
|
|
@@ -287,6 +383,8 @@ class AIStreamingMixin:
|
|
|
287
383
|
)
|
|
288
384
|
|
|
289
385
|
_dedup_prefix = ""
|
|
386
|
+
_saw_tool_call_any = False
|
|
387
|
+
_empty_retries = 0
|
|
290
388
|
|
|
291
389
|
for _round_idx in range(self._max_tool_rounds + 1):
|
|
292
390
|
if loop_ctx.cancel_event.is_set():
|
|
@@ -302,6 +400,7 @@ class AIStreamingMixin:
|
|
|
302
400
|
text_parts: list[str] = []
|
|
303
401
|
tool_calls: list[StreamToolCall] = []
|
|
304
402
|
thinking_started = False
|
|
403
|
+
coalescer = self._new_thinking_coalescer(room_id, round_idx=_round_idx)
|
|
305
404
|
_dedup_active = bool(_dedup_prefix)
|
|
306
405
|
_dedup_offset = 0
|
|
307
406
|
_dedup_buffer: list[str] = []
|
|
@@ -323,23 +422,18 @@ class AIStreamingMixin:
|
|
|
323
422
|
_round_idx,
|
|
324
423
|
)
|
|
325
424
|
thinking_parts.append(event.thinking)
|
|
326
|
-
#
|
|
327
|
-
# remote WS subscribers stream the reasoning
|
|
328
|
-
# buffered THINKING_END below still fires so
|
|
329
|
-
# joining mid-stream
|
|
330
|
-
|
|
331
|
-
await self._publish_thinking_event(
|
|
332
|
-
EphemeralEventType.THINKING_DELTA,
|
|
333
|
-
room_id,
|
|
334
|
-
event.thinking,
|
|
335
|
-
_round_idx,
|
|
336
|
-
)
|
|
425
|
+
# Buffer the per-chunk delta and publish in windows on the
|
|
426
|
+
# realtime bus so remote WS subscribers stream the reasoning
|
|
427
|
+
# live; the buffered THINKING_END below still fires so
|
|
428
|
+
# observers joining mid-stream recover the complete trace.
|
|
429
|
+
await coalescer.add(event.thinking)
|
|
337
430
|
# Inline marker so channels can render reasoning in
|
|
338
431
|
# arrival order with text deltas.
|
|
339
432
|
yield ThinkingDeltaMarker(thinking=event.thinking)
|
|
340
433
|
elif isinstance(event, StreamTextDelta):
|
|
341
434
|
if thinking_started and thinking_parts and room_id:
|
|
342
435
|
thinking_started = False
|
|
436
|
+
await coalescer.flush()
|
|
343
437
|
await self._publish_thinking_event(
|
|
344
438
|
EphemeralEventType.THINKING_END,
|
|
345
439
|
room_id,
|
|
@@ -457,6 +551,7 @@ class AIStreamingMixin:
|
|
|
457
551
|
_dedup_buffer.clear()
|
|
458
552
|
|
|
459
553
|
if thinking_started and thinking_parts and room_id:
|
|
554
|
+
await coalescer.flush()
|
|
460
555
|
await self._publish_thinking_event(
|
|
461
556
|
EphemeralEventType.THINKING_END,
|
|
462
557
|
room_id,
|
|
@@ -465,8 +560,28 @@ class AIStreamingMixin:
|
|
|
465
560
|
)
|
|
466
561
|
|
|
467
562
|
if not tool_calls:
|
|
563
|
+
# Final answer round. If it produced no text *after* a tool
|
|
564
|
+
# round, the model skipped verbalizing the result — re-prompt
|
|
565
|
+
# once (bounded) for the final answer instead of ending empty.
|
|
566
|
+
if (
|
|
567
|
+
_saw_tool_call_any
|
|
568
|
+
and not "".join(text_parts).strip()
|
|
569
|
+
and _empty_retries < self._max_empty_retries
|
|
570
|
+
and not (deadline and asyncio.get_running_loop().time() >= deadline)
|
|
571
|
+
):
|
|
572
|
+
_empty_retries += 1
|
|
573
|
+
logger.warning(
|
|
574
|
+
"Streaming empty response after tools; re-prompting for "
|
|
575
|
+
"final answer (retry %d/%d)",
|
|
576
|
+
_empty_retries,
|
|
577
|
+
self._max_empty_retries,
|
|
578
|
+
)
|
|
579
|
+
context.messages.append(AIMessage(role="user", content=_EMPTY_RETRY_NUDGE))
|
|
580
|
+
continue
|
|
468
581
|
return
|
|
469
582
|
|
|
583
|
+
_saw_tool_call_any = True
|
|
584
|
+
|
|
470
585
|
# External tools: provider executed them internally.
|
|
471
586
|
# If ExternalToolHandler is set, hooks were already fired
|
|
472
587
|
# inline during streaming (see StreamToolCall handling above).
|