@livekit/agents 1.0.47 → 1.1.0-dev.0
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.
- package/dist/beta/index.cjs +29 -0
- package/dist/beta/index.cjs.map +1 -0
- package/dist/beta/index.d.cts +2 -0
- package/dist/beta/index.d.ts +2 -0
- package/dist/beta/index.d.ts.map +1 -0
- package/dist/beta/index.js +7 -0
- package/dist/beta/index.js.map +1 -0
- package/dist/beta/workflows/index.cjs +29 -0
- package/dist/beta/workflows/index.cjs.map +1 -0
- package/dist/beta/workflows/index.d.cts +2 -0
- package/dist/beta/workflows/index.d.ts +2 -0
- package/dist/beta/workflows/index.d.ts.map +1 -0
- package/dist/beta/workflows/index.js +7 -0
- package/dist/beta/workflows/index.js.map +1 -0
- package/dist/beta/workflows/task_group.cjs +162 -0
- package/dist/beta/workflows/task_group.cjs.map +1 -0
- package/dist/beta/workflows/task_group.d.cts +32 -0
- package/dist/beta/workflows/task_group.d.ts +32 -0
- package/dist/beta/workflows/task_group.d.ts.map +1 -0
- package/dist/beta/workflows/task_group.js +138 -0
- package/dist/beta/workflows/task_group.js.map +1 -0
- package/dist/constants.cjs +27 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +9 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +18 -0
- package/dist/constants.js.map +1 -1
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/inference/api_protos.d.cts +12 -12
- package/dist/inference/api_protos.d.ts +12 -12
- package/dist/inference/interruption/defaults.cjs +81 -0
- package/dist/inference/interruption/defaults.cjs.map +1 -0
- package/dist/inference/interruption/defaults.d.cts +19 -0
- package/dist/inference/interruption/defaults.d.ts +19 -0
- package/dist/inference/interruption/defaults.d.ts.map +1 -0
- package/dist/inference/interruption/defaults.js +46 -0
- package/dist/inference/interruption/defaults.js.map +1 -0
- package/dist/inference/interruption/errors.cjs +44 -0
- package/dist/inference/interruption/errors.cjs.map +1 -0
- package/dist/inference/interruption/errors.d.cts +12 -0
- package/dist/inference/interruption/errors.d.ts +12 -0
- package/dist/inference/interruption/errors.d.ts.map +1 -0
- package/dist/inference/interruption/errors.js +20 -0
- package/dist/inference/interruption/errors.js.map +1 -0
- package/dist/inference/interruption/http_transport.cjs +147 -0
- package/dist/inference/interruption/http_transport.cjs.map +1 -0
- package/dist/inference/interruption/http_transport.d.cts +63 -0
- package/dist/inference/interruption/http_transport.d.ts +63 -0
- package/dist/inference/interruption/http_transport.d.ts.map +1 -0
- package/dist/inference/interruption/http_transport.js +121 -0
- package/dist/inference/interruption/http_transport.js.map +1 -0
- package/dist/inference/interruption/interruption_cache_entry.cjs +58 -0
- package/dist/inference/interruption/interruption_cache_entry.cjs.map +1 -0
- package/dist/inference/interruption/interruption_cache_entry.d.cts +30 -0
- package/dist/inference/interruption/interruption_cache_entry.d.ts +30 -0
- package/dist/inference/interruption/interruption_cache_entry.d.ts.map +1 -0
- package/dist/inference/interruption/interruption_cache_entry.js +34 -0
- package/dist/inference/interruption/interruption_cache_entry.js.map +1 -0
- package/dist/inference/interruption/interruption_detector.cjs +181 -0
- package/dist/inference/interruption/interruption_detector.cjs.map +1 -0
- package/dist/inference/interruption/interruption_detector.d.cts +59 -0
- package/dist/inference/interruption/interruption_detector.d.ts +59 -0
- package/dist/inference/interruption/interruption_detector.d.ts.map +1 -0
- package/dist/inference/interruption/interruption_detector.js +147 -0
- package/dist/inference/interruption/interruption_detector.js.map +1 -0
- package/dist/inference/interruption/interruption_stream.cjs +368 -0
- package/dist/inference/interruption/interruption_stream.cjs.map +1 -0
- package/dist/inference/interruption/interruption_stream.d.cts +46 -0
- package/dist/inference/interruption/interruption_stream.d.ts +46 -0
- package/dist/inference/interruption/interruption_stream.d.ts.map +1 -0
- package/dist/inference/interruption/interruption_stream.js +344 -0
- package/dist/inference/interruption/interruption_stream.js.map +1 -0
- package/dist/inference/interruption/types.cjs +17 -0
- package/dist/inference/interruption/types.cjs.map +1 -0
- package/dist/inference/interruption/types.d.cts +66 -0
- package/dist/inference/interruption/types.d.ts +66 -0
- package/dist/inference/interruption/types.d.ts.map +1 -0
- package/dist/inference/interruption/types.js +1 -0
- package/dist/inference/interruption/types.js.map +1 -0
- package/dist/inference/interruption/utils.cjs +130 -0
- package/dist/inference/interruption/utils.cjs.map +1 -0
- package/dist/inference/interruption/utils.d.cts +41 -0
- package/dist/inference/interruption/utils.d.ts +41 -0
- package/dist/inference/interruption/utils.d.ts.map +1 -0
- package/dist/inference/interruption/utils.js +105 -0
- package/dist/inference/interruption/utils.js.map +1 -0
- package/dist/inference/interruption/utils.test.cjs +105 -0
- package/dist/inference/interruption/utils.test.cjs.map +1 -0
- package/dist/inference/interruption/utils.test.js +104 -0
- package/dist/inference/interruption/utils.test.js.map +1 -0
- package/dist/inference/interruption/ws_transport.cjs +329 -0
- package/dist/inference/interruption/ws_transport.cjs.map +1 -0
- package/dist/inference/interruption/ws_transport.d.cts +33 -0
- package/dist/inference/interruption/ws_transport.d.ts +33 -0
- package/dist/inference/interruption/ws_transport.d.ts.map +1 -0
- package/dist/inference/interruption/ws_transport.js +295 -0
- package/dist/inference/interruption/ws_transport.js.map +1 -0
- package/dist/inference/llm.cjs +14 -10
- package/dist/inference/llm.cjs.map +1 -1
- package/dist/inference/llm.d.cts +2 -1
- package/dist/inference/llm.d.ts +2 -1
- package/dist/inference/llm.d.ts.map +1 -1
- package/dist/inference/llm.js +8 -10
- package/dist/inference/llm.js.map +1 -1
- package/dist/inference/stt.cjs +7 -2
- package/dist/inference/stt.cjs.map +1 -1
- package/dist/inference/stt.d.cts +2 -0
- package/dist/inference/stt.d.ts +2 -0
- package/dist/inference/stt.d.ts.map +1 -1
- package/dist/inference/stt.js +8 -3
- package/dist/inference/stt.js.map +1 -1
- package/dist/inference/tts.cjs +7 -2
- package/dist/inference/tts.cjs.map +1 -1
- package/dist/inference/tts.d.cts +2 -0
- package/dist/inference/tts.d.ts +2 -0
- package/dist/inference/tts.d.ts.map +1 -1
- package/dist/inference/tts.js +8 -3
- package/dist/inference/tts.js.map +1 -1
- package/dist/inference/utils.cjs +26 -7
- package/dist/inference/utils.cjs.map +1 -1
- package/dist/inference/utils.d.cts +13 -0
- package/dist/inference/utils.d.ts +13 -0
- package/dist/inference/utils.d.ts.map +1 -1
- package/dist/inference/utils.js +18 -2
- package/dist/inference/utils.js.map +1 -1
- package/dist/llm/chat_context.cjs +108 -2
- package/dist/llm/chat_context.cjs.map +1 -1
- package/dist/llm/chat_context.d.cts +28 -1
- package/dist/llm/chat_context.d.ts +28 -1
- package/dist/llm/chat_context.d.ts.map +1 -1
- package/dist/llm/chat_context.js +108 -2
- package/dist/llm/chat_context.js.map +1 -1
- package/dist/llm/chat_context.test.cjs +43 -0
- package/dist/llm/chat_context.test.cjs.map +1 -1
- package/dist/llm/chat_context.test.js +43 -0
- package/dist/llm/chat_context.test.js.map +1 -1
- package/dist/llm/index.cjs +2 -0
- package/dist/llm/index.cjs.map +1 -1
- package/dist/llm/index.d.cts +2 -2
- package/dist/llm/index.d.ts +2 -2
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +3 -1
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/llm.cjs +16 -1
- package/dist/llm/llm.cjs.map +1 -1
- package/dist/llm/llm.d.cts +9 -0
- package/dist/llm/llm.d.ts +9 -0
- package/dist/llm/llm.d.ts.map +1 -1
- package/dist/llm/llm.js +16 -1
- package/dist/llm/llm.js.map +1 -1
- package/dist/llm/provider_format/index.d.cts +1 -1
- package/dist/llm/provider_format/index.d.ts +1 -1
- package/dist/llm/realtime.cjs +3 -0
- package/dist/llm/realtime.cjs.map +1 -1
- package/dist/llm/realtime.d.cts +1 -0
- package/dist/llm/realtime.d.ts +1 -0
- package/dist/llm/realtime.d.ts.map +1 -1
- package/dist/llm/realtime.js +3 -0
- package/dist/llm/realtime.js.map +1 -1
- package/dist/llm/tool_context.cjs +7 -0
- package/dist/llm/tool_context.cjs.map +1 -1
- package/dist/llm/tool_context.d.cts +10 -2
- package/dist/llm/tool_context.d.ts +10 -2
- package/dist/llm/tool_context.d.ts.map +1 -1
- package/dist/llm/tool_context.js +6 -0
- package/dist/llm/tool_context.js.map +1 -1
- package/dist/metrics/base.cjs.map +1 -1
- package/dist/metrics/base.d.cts +45 -1
- package/dist/metrics/base.d.ts +45 -1
- package/dist/metrics/base.d.ts.map +1 -1
- package/dist/metrics/index.cjs +5 -0
- package/dist/metrics/index.cjs.map +1 -1
- package/dist/metrics/index.d.cts +2 -1
- package/dist/metrics/index.d.ts +2 -1
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +6 -0
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/model_usage.cjs +189 -0
- package/dist/metrics/model_usage.cjs.map +1 -0
- package/dist/metrics/model_usage.d.cts +92 -0
- package/dist/metrics/model_usage.d.ts +92 -0
- package/dist/metrics/model_usage.d.ts.map +1 -0
- package/dist/metrics/model_usage.js +164 -0
- package/dist/metrics/model_usage.js.map +1 -0
- package/dist/metrics/model_usage.test.cjs +474 -0
- package/dist/metrics/model_usage.test.cjs.map +1 -0
- package/dist/metrics/model_usage.test.js +476 -0
- package/dist/metrics/model_usage.test.js.map +1 -0
- package/dist/metrics/usage_collector.cjs +3 -0
- package/dist/metrics/usage_collector.cjs.map +1 -1
- package/dist/metrics/usage_collector.d.cts +9 -0
- package/dist/metrics/usage_collector.d.ts +9 -0
- package/dist/metrics/usage_collector.d.ts.map +1 -1
- package/dist/metrics/usage_collector.js +3 -0
- package/dist/metrics/usage_collector.js.map +1 -1
- package/dist/metrics/utils.cjs +9 -0
- package/dist/metrics/utils.cjs.map +1 -1
- package/dist/metrics/utils.d.ts.map +1 -1
- package/dist/metrics/utils.js +9 -0
- package/dist/metrics/utils.js.map +1 -1
- package/dist/stream/multi_input_stream.test.cjs +4 -0
- package/dist/stream/multi_input_stream.test.cjs.map +1 -1
- package/dist/stream/multi_input_stream.test.js +5 -1
- package/dist/stream/multi_input_stream.test.js.map +1 -1
- package/dist/stream/stream_channel.cjs +31 -0
- package/dist/stream/stream_channel.cjs.map +1 -1
- package/dist/stream/stream_channel.d.cts +4 -2
- package/dist/stream/stream_channel.d.ts +4 -2
- package/dist/stream/stream_channel.d.ts.map +1 -1
- package/dist/stream/stream_channel.js +31 -0
- package/dist/stream/stream_channel.js.map +1 -1
- package/dist/stt/stt.cjs +34 -2
- package/dist/stt/stt.cjs.map +1 -1
- package/dist/stt/stt.d.cts +22 -0
- package/dist/stt/stt.d.ts +22 -0
- package/dist/stt/stt.d.ts.map +1 -1
- package/dist/stt/stt.js +34 -2
- package/dist/stt/stt.js.map +1 -1
- package/dist/telemetry/otel_http_exporter.cjs +24 -5
- package/dist/telemetry/otel_http_exporter.cjs.map +1 -1
- package/dist/telemetry/otel_http_exporter.d.cts +1 -0
- package/dist/telemetry/otel_http_exporter.d.ts +1 -0
- package/dist/telemetry/otel_http_exporter.d.ts.map +1 -1
- package/dist/telemetry/otel_http_exporter.js +24 -5
- package/dist/telemetry/otel_http_exporter.js.map +1 -1
- package/dist/telemetry/trace_types.cjs +5 -5
- package/dist/telemetry/trace_types.cjs.map +1 -1
- package/dist/telemetry/trace_types.d.cts +9 -5
- package/dist/telemetry/trace_types.d.ts +9 -5
- package/dist/telemetry/trace_types.d.ts.map +1 -1
- package/dist/telemetry/trace_types.js +5 -5
- package/dist/telemetry/trace_types.js.map +1 -1
- package/dist/telemetry/traces.cjs +47 -8
- package/dist/telemetry/traces.cjs.map +1 -1
- package/dist/telemetry/traces.d.ts.map +1 -1
- package/dist/telemetry/traces.js +47 -8
- package/dist/telemetry/traces.js.map +1 -1
- package/dist/tts/tts.cjs +64 -2
- package/dist/tts/tts.cjs.map +1 -1
- package/dist/tts/tts.d.cts +34 -0
- package/dist/tts/tts.d.ts +34 -0
- package/dist/tts/tts.d.ts.map +1 -1
- package/dist/tts/tts.js +64 -2
- package/dist/tts/tts.js.map +1 -1
- package/dist/utils.cjs +1 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -0
- package/dist/utils.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist/voice/agent.cjs +34 -4
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +11 -2
- package/dist/voice/agent.d.ts +11 -2
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +34 -4
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent_activity.cjs +292 -44
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +27 -6
- package/dist/voice/agent_activity.d.ts +27 -6
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +293 -45
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +105 -48
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +90 -20
- package/dist/voice/agent_session.d.ts +90 -20
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +105 -46
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +287 -6
- package/dist/voice/audio_recognition.cjs.map +1 -1
- package/dist/voice/audio_recognition.d.cts +42 -3
- package/dist/voice/audio_recognition.d.ts +42 -3
- package/dist/voice/audio_recognition.d.ts.map +1 -1
- package/dist/voice/audio_recognition.js +289 -7
- package/dist/voice/audio_recognition.js.map +1 -1
- package/dist/voice/client_events.cjs +554 -0
- package/dist/voice/client_events.cjs.map +1 -0
- package/dist/voice/client_events.d.cts +195 -0
- package/dist/voice/client_events.d.ts +195 -0
- package/dist/voice/client_events.d.ts.map +1 -0
- package/dist/voice/client_events.js +548 -0
- package/dist/voice/client_events.js.map +1 -0
- package/dist/voice/events.cjs +1 -0
- package/dist/voice/events.cjs.map +1 -1
- package/dist/voice/events.d.cts +8 -5
- package/dist/voice/events.d.ts +8 -5
- package/dist/voice/events.d.ts.map +1 -1
- package/dist/voice/events.js +1 -0
- package/dist/voice/events.js.map +1 -1
- package/dist/voice/generation.cjs +43 -8
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.cts +3 -3
- package/dist/voice/generation.d.ts +3 -3
- package/dist/voice/generation.d.ts.map +1 -1
- package/dist/voice/generation.js +43 -8
- package/dist/voice/generation.js.map +1 -1
- package/dist/voice/index.cjs +1 -0
- package/dist/voice/index.cjs.map +1 -1
- package/dist/voice/index.d.cts +1 -0
- package/dist/voice/index.d.ts +1 -0
- package/dist/voice/index.d.ts.map +1 -1
- package/dist/voice/index.js +1 -0
- package/dist/voice/index.js.map +1 -1
- package/dist/voice/report.cjs +20 -8
- package/dist/voice/report.cjs.map +1 -1
- package/dist/voice/report.d.cts +5 -0
- package/dist/voice/report.d.ts +5 -0
- package/dist/voice/report.d.ts.map +1 -1
- package/dist/voice/report.js +20 -8
- package/dist/voice/report.js.map +1 -1
- package/dist/voice/report.test.cjs +106 -0
- package/dist/voice/report.test.cjs.map +1 -0
- package/dist/voice/report.test.js +105 -0
- package/dist/voice/report.test.js.map +1 -0
- package/dist/voice/room_io/room_io.cjs +16 -41
- package/dist/voice/room_io/room_io.cjs.map +1 -1
- package/dist/voice/room_io/room_io.d.cts +4 -9
- package/dist/voice/room_io/room_io.d.ts +4 -9
- package/dist/voice/room_io/room_io.d.ts.map +1 -1
- package/dist/voice/room_io/room_io.js +17 -43
- package/dist/voice/room_io/room_io.js.map +1 -1
- package/dist/voice/testing/fake_llm.cjs +127 -0
- package/dist/voice/testing/fake_llm.cjs.map +1 -0
- package/dist/voice/testing/fake_llm.d.cts +30 -0
- package/dist/voice/testing/fake_llm.d.ts +30 -0
- package/dist/voice/testing/fake_llm.d.ts.map +1 -0
- package/dist/voice/testing/fake_llm.js +103 -0
- package/dist/voice/testing/fake_llm.js.map +1 -0
- package/dist/voice/testing/index.cjs +3 -0
- package/dist/voice/testing/index.cjs.map +1 -1
- package/dist/voice/testing/index.d.cts +1 -0
- package/dist/voice/testing/index.d.ts +1 -0
- package/dist/voice/testing/index.d.ts.map +1 -1
- package/dist/voice/testing/index.js +2 -0
- package/dist/voice/testing/index.js.map +1 -1
- package/dist/voice/turn_config/endpointing.cjs +33 -0
- package/dist/voice/turn_config/endpointing.cjs.map +1 -0
- package/dist/voice/turn_config/endpointing.d.cts +30 -0
- package/dist/voice/turn_config/endpointing.d.ts +30 -0
- package/dist/voice/turn_config/endpointing.d.ts.map +1 -0
- package/dist/voice/turn_config/endpointing.js +9 -0
- package/dist/voice/turn_config/endpointing.js.map +1 -0
- package/dist/voice/turn_config/interruption.cjs +37 -0
- package/dist/voice/turn_config/interruption.cjs.map +1 -0
- package/dist/voice/turn_config/interruption.d.cts +53 -0
- package/dist/voice/turn_config/interruption.d.ts +53 -0
- package/dist/voice/turn_config/interruption.d.ts.map +1 -0
- package/dist/voice/turn_config/interruption.js +13 -0
- package/dist/voice/turn_config/interruption.js.map +1 -0
- package/dist/voice/turn_config/turn_handling.cjs +35 -0
- package/dist/voice/turn_config/turn_handling.cjs.map +1 -0
- package/dist/voice/turn_config/turn_handling.d.cts +36 -0
- package/dist/voice/turn_config/turn_handling.d.ts +36 -0
- package/dist/voice/turn_config/turn_handling.d.ts.map +1 -0
- package/dist/voice/turn_config/turn_handling.js +11 -0
- package/dist/voice/turn_config/turn_handling.js.map +1 -0
- package/dist/voice/turn_config/utils.cjs +97 -0
- package/dist/voice/turn_config/utils.cjs.map +1 -0
- package/dist/voice/turn_config/utils.d.cts +25 -0
- package/dist/voice/turn_config/utils.d.ts +25 -0
- package/dist/voice/turn_config/utils.d.ts.map +1 -0
- package/dist/voice/turn_config/utils.js +73 -0
- package/dist/voice/turn_config/utils.js.map +1 -0
- package/dist/voice/turn_config/utils.test.cjs +86 -0
- package/dist/voice/turn_config/utils.test.cjs.map +1 -0
- package/dist/voice/turn_config/utils.test.js +85 -0
- package/dist/voice/turn_config/utils.test.js.map +1 -0
- package/dist/voice/wire_format.cjs +798 -0
- package/dist/voice/wire_format.cjs.map +1 -0
- package/dist/voice/wire_format.d.cts +5503 -0
- package/dist/voice/wire_format.d.ts +5503 -0
- package/dist/voice/wire_format.d.ts.map +1 -0
- package/dist/voice/wire_format.js +728 -0
- package/dist/voice/wire_format.js.map +1 -0
- package/package.json +2 -1
- package/src/beta/index.ts +9 -0
- package/src/beta/workflows/index.ts +9 -0
- package/src/beta/workflows/task_group.ts +194 -0
- package/src/constants.ts +13 -0
- package/src/index.ts +2 -1
- package/src/inference/interruption/defaults.ts +51 -0
- package/src/inference/interruption/errors.ts +25 -0
- package/src/inference/interruption/http_transport.ts +187 -0
- package/src/inference/interruption/interruption_cache_entry.ts +50 -0
- package/src/inference/interruption/interruption_detector.ts +188 -0
- package/src/inference/interruption/interruption_stream.ts +467 -0
- package/src/inference/interruption/types.ts +84 -0
- package/src/inference/interruption/utils.test.ts +132 -0
- package/src/inference/interruption/utils.ts +137 -0
- package/src/inference/interruption/ws_transport.ts +402 -0
- package/src/inference/llm.ts +9 -12
- package/src/inference/stt.ts +10 -3
- package/src/inference/tts.ts +10 -3
- package/src/inference/utils.ts +29 -1
- package/src/llm/chat_context.test.ts +48 -0
- package/src/llm/chat_context.ts +161 -0
- package/src/llm/index.ts +2 -0
- package/src/llm/llm.ts +16 -0
- package/src/llm/realtime.ts +4 -0
- package/src/llm/tool_context.ts +14 -0
- package/src/metrics/base.ts +48 -1
- package/src/metrics/index.ts +11 -0
- package/src/metrics/model_usage.test.ts +545 -0
- package/src/metrics/model_usage.ts +262 -0
- package/src/metrics/usage_collector.ts +11 -0
- package/src/metrics/utils.ts +11 -0
- package/src/stream/multi_input_stream.test.ts +6 -1
- package/src/stream/stream_channel.ts +34 -2
- package/src/stt/stt.ts +38 -0
- package/src/telemetry/otel_http_exporter.ts +28 -5
- package/src/telemetry/trace_types.ts +11 -8
- package/src/telemetry/traces.ts +111 -54
- package/src/tts/tts.ts +69 -1
- package/src/utils.ts +5 -0
- package/src/voice/agent.ts +41 -3
- package/src/voice/agent_activity.ts +371 -34
- package/src/voice/agent_session.ts +207 -59
- package/src/voice/audio_recognition.ts +385 -9
- package/src/voice/client_events.ts +838 -0
- package/src/voice/events.ts +14 -4
- package/src/voice/generation.ts +52 -9
- package/src/voice/index.ts +1 -0
- package/src/voice/report.test.ts +117 -0
- package/src/voice/report.ts +29 -6
- package/src/voice/room_io/room_io.ts +21 -64
- package/src/voice/testing/fake_llm.ts +138 -0
- package/src/voice/testing/index.ts +2 -0
- package/src/voice/turn_config/endpointing.ts +33 -0
- package/src/voice/turn_config/interruption.ts +56 -0
- package/src/voice/turn_config/turn_handling.ts +45 -0
- package/src/voice/turn_config/utils.test.ts +100 -0
- package/src/voice/turn_config/utils.ts +103 -0
- package/src/voice/wire_format.ts +827 -0
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import type { Room, RpcInvocationData, TextStreamInfo, TextStreamReader } from '@livekit/rtc-node';
|
|
5
|
+
import type { TypedEventEmitter } from '@livekit/typed-emitter';
|
|
6
|
+
import EventEmitter from 'events';
|
|
7
|
+
import type { z } from 'zod';
|
|
8
|
+
import {
|
|
9
|
+
RPC_GET_AGENT_INFO,
|
|
10
|
+
RPC_GET_CHAT_HISTORY,
|
|
11
|
+
RPC_GET_SESSION_STATE,
|
|
12
|
+
RPC_SEND_MESSAGE,
|
|
13
|
+
TOPIC_AGENT_REQUEST,
|
|
14
|
+
TOPIC_AGENT_RESPONSE,
|
|
15
|
+
TOPIC_CHAT,
|
|
16
|
+
TOPIC_CLIENT_EVENTS,
|
|
17
|
+
} from '../constants.js';
|
|
18
|
+
import type { OverlappingSpeechEvent } from '../inference/interruption/types.js';
|
|
19
|
+
import type { ToolContext } from '../llm/tool_context.js';
|
|
20
|
+
import { log } from '../log.js';
|
|
21
|
+
import { Future, Task, cancelAndWait, shortuuid } from '../utils.js';
|
|
22
|
+
import type { AgentSession } from './agent_session.js';
|
|
23
|
+
import {
|
|
24
|
+
AgentSessionEventTypes,
|
|
25
|
+
type AgentStateChangedEvent,
|
|
26
|
+
type ConversationItemAddedEvent,
|
|
27
|
+
type ErrorEvent,
|
|
28
|
+
type FunctionToolsExecutedEvent,
|
|
29
|
+
type MetricsCollectedEvent,
|
|
30
|
+
type UserInputTranscribedEvent,
|
|
31
|
+
type UserStateChangedEvent,
|
|
32
|
+
} from './events.js';
|
|
33
|
+
import type { RoomIO } from './room_io/room_io.js';
|
|
34
|
+
import {
|
|
35
|
+
agentMetricsToWire,
|
|
36
|
+
agentSessionUsageToWire,
|
|
37
|
+
chatItemToWire,
|
|
38
|
+
chatMessageToWire,
|
|
39
|
+
type clientAgentStateChangedSchema,
|
|
40
|
+
type clientConversationItemAddedSchema,
|
|
41
|
+
type clientErrorSchema,
|
|
42
|
+
clientEventSchema,
|
|
43
|
+
type clientFunctionToolsExecutedSchema,
|
|
44
|
+
type clientMetricsCollectedSchema,
|
|
45
|
+
type clientSessionUsageSchema,
|
|
46
|
+
type clientUserInputTranscribedSchema,
|
|
47
|
+
type clientUserOverlappingSpeechSchema,
|
|
48
|
+
type clientUserStateChangedSchema,
|
|
49
|
+
functionCallOutputToWire,
|
|
50
|
+
functionCallToWire,
|
|
51
|
+
getAgentInfoResponseSchema,
|
|
52
|
+
getChatHistoryResponseSchema,
|
|
53
|
+
getRTCStatsResponseSchema,
|
|
54
|
+
getSessionStateResponseSchema,
|
|
55
|
+
getSessionUsageResponseSchema,
|
|
56
|
+
msToS,
|
|
57
|
+
sendMessageRequestSchema,
|
|
58
|
+
sendMessageResponseSchema,
|
|
59
|
+
streamRequestSchema,
|
|
60
|
+
streamResponseSchema,
|
|
61
|
+
} from './wire_format.js';
|
|
62
|
+
|
|
63
|
+
/** @experimental */
|
|
64
|
+
export type ClientAgentStateChangedEvent = z.infer<typeof clientAgentStateChangedSchema>;
|
|
65
|
+
|
|
66
|
+
/** @experimental */
|
|
67
|
+
export type ClientUserStateChangedEvent = z.infer<typeof clientUserStateChangedSchema>;
|
|
68
|
+
|
|
69
|
+
/** @experimental */
|
|
70
|
+
export type ClientConversationItemAddedEvent = z.infer<typeof clientConversationItemAddedSchema>;
|
|
71
|
+
|
|
72
|
+
/** @experimental */
|
|
73
|
+
export type ClientUserInputTranscribedEvent = z.infer<typeof clientUserInputTranscribedSchema>;
|
|
74
|
+
|
|
75
|
+
/** @experimental */
|
|
76
|
+
export type ClientFunctionToolsExecutedEvent = z.infer<typeof clientFunctionToolsExecutedSchema>;
|
|
77
|
+
|
|
78
|
+
/** @experimental */
|
|
79
|
+
export type ClientMetricsCollectedEvent = z.infer<typeof clientMetricsCollectedSchema>;
|
|
80
|
+
|
|
81
|
+
/** @experimental */
|
|
82
|
+
export type ClientErrorEvent = z.infer<typeof clientErrorSchema>;
|
|
83
|
+
|
|
84
|
+
/** @experimental */
|
|
85
|
+
export type ClientUserOverlappingSpeechEvent = z.infer<typeof clientUserOverlappingSpeechSchema>;
|
|
86
|
+
|
|
87
|
+
/** @experimental */
|
|
88
|
+
export type ClientSessionUsageEvent = z.infer<typeof clientSessionUsageSchema>;
|
|
89
|
+
|
|
90
|
+
/** @experimental */
|
|
91
|
+
export type ClientEvent = z.infer<typeof clientEventSchema>;
|
|
92
|
+
|
|
93
|
+
/** @experimental */
|
|
94
|
+
export type ClientEventType = ClientEvent['type'];
|
|
95
|
+
|
|
96
|
+
/** @experimental */
|
|
97
|
+
export type StreamRequest = z.infer<typeof streamRequestSchema>;
|
|
98
|
+
|
|
99
|
+
/** @experimental */
|
|
100
|
+
export type StreamResponse = z.infer<typeof streamResponseSchema>;
|
|
101
|
+
|
|
102
|
+
/** @experimental */
|
|
103
|
+
export type GetSessionStateRequest = Record<string, never>;
|
|
104
|
+
|
|
105
|
+
/** @experimental */
|
|
106
|
+
export type GetSessionStateResponse = z.infer<typeof getSessionStateResponseSchema>;
|
|
107
|
+
|
|
108
|
+
/** @experimental */
|
|
109
|
+
export type GetChatHistoryRequest = Record<string, never>;
|
|
110
|
+
|
|
111
|
+
/** @experimental */
|
|
112
|
+
export type GetChatHistoryResponse = z.infer<typeof getChatHistoryResponseSchema>;
|
|
113
|
+
|
|
114
|
+
/** @experimental */
|
|
115
|
+
export type GetAgentInfoRequest = Record<string, never>;
|
|
116
|
+
|
|
117
|
+
/** @experimental */
|
|
118
|
+
export type GetAgentInfoResponse = z.infer<typeof getAgentInfoResponseSchema>;
|
|
119
|
+
|
|
120
|
+
/** @experimental */
|
|
121
|
+
export type SendMessageRequest = z.infer<typeof sendMessageRequestSchema>;
|
|
122
|
+
|
|
123
|
+
/** @experimental */
|
|
124
|
+
export type SendMessageResponse = z.infer<typeof sendMessageResponseSchema>;
|
|
125
|
+
|
|
126
|
+
/** @experimental */
|
|
127
|
+
export type GetRTCStatsRequest = Record<string, never>;
|
|
128
|
+
|
|
129
|
+
/** @experimental */
|
|
130
|
+
export type GetRTCStatsResponse = z.infer<typeof getRTCStatsResponseSchema>;
|
|
131
|
+
|
|
132
|
+
/** @experimental */
|
|
133
|
+
export type GetSessionUsageRequest = Record<string, never>;
|
|
134
|
+
|
|
135
|
+
/** @experimental */
|
|
136
|
+
export type GetSessionUsageResponse = z.infer<typeof getSessionUsageResponseSchema>;
|
|
137
|
+
|
|
138
|
+
function serializeOptions(opts: {
|
|
139
|
+
turnHandling?: {
|
|
140
|
+
endpointing?: unknown;
|
|
141
|
+
interruption?: unknown;
|
|
142
|
+
};
|
|
143
|
+
maxToolSteps?: number;
|
|
144
|
+
userAwayTimeout?: number | null;
|
|
145
|
+
preemptiveGeneration?: boolean;
|
|
146
|
+
useTtsAlignedTranscript?: boolean;
|
|
147
|
+
}): Record<string, unknown> {
|
|
148
|
+
return {
|
|
149
|
+
endpointing: opts.turnHandling?.endpointing ?? {},
|
|
150
|
+
interruption: opts.turnHandling?.interruption ?? {},
|
|
151
|
+
max_tool_steps: opts.maxToolSteps,
|
|
152
|
+
user_away_timeout: opts.userAwayTimeout,
|
|
153
|
+
preemptive_generation: opts.preemptiveGeneration,
|
|
154
|
+
use_tts_aligned_transcript: opts.useTtsAlignedTranscript,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function toolNames(toolCtx: ToolContext | undefined): string[] {
|
|
159
|
+
if (!toolCtx) return [];
|
|
160
|
+
return Object.keys(toolCtx);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** @experimental */
|
|
164
|
+
export type RemoteSessionEventTypes =
|
|
165
|
+
| 'agent_state_changed'
|
|
166
|
+
| 'user_state_changed'
|
|
167
|
+
| 'conversation_item_added'
|
|
168
|
+
| 'user_input_transcribed'
|
|
169
|
+
| 'function_tools_executed'
|
|
170
|
+
| 'metrics_collected'
|
|
171
|
+
| 'user_overlapping_speech'
|
|
172
|
+
| 'session_usage'
|
|
173
|
+
| 'error';
|
|
174
|
+
|
|
175
|
+
/** @experimental */
|
|
176
|
+
export type RemoteSessionCallbacks = {
|
|
177
|
+
agent_state_changed: (ev: ClientAgentStateChangedEvent) => void;
|
|
178
|
+
user_state_changed: (ev: ClientUserStateChangedEvent) => void;
|
|
179
|
+
conversation_item_added: (ev: ClientConversationItemAddedEvent) => void;
|
|
180
|
+
user_input_transcribed: (ev: ClientUserInputTranscribedEvent) => void;
|
|
181
|
+
function_tools_executed: (ev: ClientFunctionToolsExecutedEvent) => void;
|
|
182
|
+
metrics_collected: (ev: ClientMetricsCollectedEvent) => void;
|
|
183
|
+
user_overlapping_speech: (ev: ClientUserOverlappingSpeechEvent) => void;
|
|
184
|
+
session_usage: (ev: ClientSessionUsageEvent) => void;
|
|
185
|
+
error: (ev: ClientErrorEvent) => void;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export interface TextInputEvent {
|
|
189
|
+
text: string;
|
|
190
|
+
info: TextStreamInfo;
|
|
191
|
+
participantIdentity: string;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export type TextInputCallback = (session: AgentSession, ev: TextInputEvent) => void | Promise<void>;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Handles exposing AgentSession state to room participants and allows interaction.
|
|
198
|
+
*
|
|
199
|
+
* This class provides:
|
|
200
|
+
* - Event streaming: Automatically streams AgentSession events to clients via a text stream
|
|
201
|
+
* - RPC handlers: Allows clients to request state, chat history, and agent info on demand
|
|
202
|
+
* - Text input handling: Receives text messages from clients and generates agent replies
|
|
203
|
+
*/
|
|
204
|
+
|
|
205
|
+
/** @experimental */
|
|
206
|
+
export class ClientEventsHandler {
|
|
207
|
+
private readonly session: AgentSession;
|
|
208
|
+
private readonly roomIO: RoomIO;
|
|
209
|
+
|
|
210
|
+
private textInputCb?: TextInputCallback;
|
|
211
|
+
private textStreamHandlerRegistered = false;
|
|
212
|
+
private rpcHandlersRegistered = false;
|
|
213
|
+
private requestHandlerRegistered = false;
|
|
214
|
+
private eventHandlersRegistered = false;
|
|
215
|
+
private started = false;
|
|
216
|
+
|
|
217
|
+
private readonly tasks = new Set<Task<void>>();
|
|
218
|
+
private readonly logger = log();
|
|
219
|
+
|
|
220
|
+
constructor(session: AgentSession, roomIO: RoomIO) {
|
|
221
|
+
this.session = session;
|
|
222
|
+
this.roomIO = roomIO;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private get room(): Room {
|
|
226
|
+
return this.roomIO.rtcRoom;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async start(): Promise<void> {
|
|
230
|
+
if (this.started) return;
|
|
231
|
+
|
|
232
|
+
this.started = true;
|
|
233
|
+
this.registerRpcHandlers();
|
|
234
|
+
this.registerRequestHandler();
|
|
235
|
+
this.registerEventHandlers();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async close(): Promise<void> {
|
|
239
|
+
if (!this.started) return;
|
|
240
|
+
this.started = false;
|
|
241
|
+
|
|
242
|
+
if (this.textStreamHandlerRegistered) {
|
|
243
|
+
this.room.unregisterTextStreamHandler(TOPIC_CHAT);
|
|
244
|
+
this.textStreamHandlerRegistered = false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (this.rpcHandlersRegistered) {
|
|
248
|
+
const localParticipant = this.room.localParticipant;
|
|
249
|
+
if (localParticipant) {
|
|
250
|
+
localParticipant.unregisterRpcMethod(RPC_GET_SESSION_STATE);
|
|
251
|
+
localParticipant.unregisterRpcMethod(RPC_GET_CHAT_HISTORY);
|
|
252
|
+
localParticipant.unregisterRpcMethod(RPC_GET_AGENT_INFO);
|
|
253
|
+
localParticipant.unregisterRpcMethod(RPC_SEND_MESSAGE);
|
|
254
|
+
}
|
|
255
|
+
this.rpcHandlersRegistered = false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (this.requestHandlerRegistered) {
|
|
259
|
+
this.room.unregisterTextStreamHandler(TOPIC_AGENT_REQUEST);
|
|
260
|
+
this.requestHandlerRegistered = false;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (this.eventHandlersRegistered) {
|
|
264
|
+
this.session.off(AgentSessionEventTypes.AgentStateChanged, this.onAgentStateChanged);
|
|
265
|
+
this.session.off(AgentSessionEventTypes.UserStateChanged, this.onUserStateChanged);
|
|
266
|
+
this.session.off(AgentSessionEventTypes.ConversationItemAdded, this.onConversationItemAdded);
|
|
267
|
+
this.session.off(AgentSessionEventTypes.FunctionToolsExecuted, this.onFunctionToolsExecuted);
|
|
268
|
+
this.session.off(AgentSessionEventTypes.MetricsCollected, this.onMetricsCollected);
|
|
269
|
+
this.session.off(AgentSessionEventTypes.UserInputTranscribed, this.onUserInputTranscribed);
|
|
270
|
+
this.session.off(AgentSessionEventTypes.UserOverlappingSpeech, this.onUserOverlapSpeech);
|
|
271
|
+
this.session.off(AgentSessionEventTypes.Error, this.onError);
|
|
272
|
+
this.eventHandlersRegistered = false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
await cancelAndWait([...this.tasks]);
|
|
276
|
+
this.tasks.clear();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Registers a callback to handle text input from clients.
|
|
281
|
+
*
|
|
282
|
+
* This callback will be called when a client sends a text message to the agent.
|
|
283
|
+
* The callback should return a promise that resolves when the text input has been processed.
|
|
284
|
+
*
|
|
285
|
+
* @param textInputCb - The callback to handle text input.
|
|
286
|
+
*/
|
|
287
|
+
registerTextInput(textInputCb: TextInputCallback): void {
|
|
288
|
+
this.textInputCb = textInputCb;
|
|
289
|
+
if (this.textStreamHandlerRegistered) return;
|
|
290
|
+
this.room.registerTextStreamHandler(TOPIC_CHAT, this.onUserTextInput);
|
|
291
|
+
this.textStreamHandlerRegistered = true;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private registerRpcHandlers(): void {
|
|
295
|
+
if (this.rpcHandlersRegistered) return;
|
|
296
|
+
|
|
297
|
+
const localParticipant = this.room.localParticipant;
|
|
298
|
+
if (!localParticipant) return;
|
|
299
|
+
|
|
300
|
+
localParticipant.registerRpcMethod(RPC_GET_SESSION_STATE, this.rpcGetSessionState);
|
|
301
|
+
localParticipant.registerRpcMethod(RPC_GET_CHAT_HISTORY, this.rpcGetChatHistory);
|
|
302
|
+
localParticipant.registerRpcMethod(RPC_GET_AGENT_INFO, this.rpcGetAgentInfo);
|
|
303
|
+
localParticipant.registerRpcMethod(RPC_SEND_MESSAGE, this.rpcSendMessage);
|
|
304
|
+
this.rpcHandlersRegistered = true;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private registerRequestHandler(): void {
|
|
308
|
+
if (this.requestHandlerRegistered) return;
|
|
309
|
+
|
|
310
|
+
this.room.registerTextStreamHandler(TOPIC_AGENT_REQUEST, this.onStreamRequest);
|
|
311
|
+
this.requestHandlerRegistered = true;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private registerEventHandlers(): void {
|
|
315
|
+
if (this.eventHandlersRegistered) return;
|
|
316
|
+
|
|
317
|
+
this.session.on(AgentSessionEventTypes.AgentStateChanged, this.onAgentStateChanged);
|
|
318
|
+
this.session.on(AgentSessionEventTypes.UserStateChanged, this.onUserStateChanged);
|
|
319
|
+
this.session.on(AgentSessionEventTypes.ConversationItemAdded, this.onConversationItemAdded);
|
|
320
|
+
this.session.on(AgentSessionEventTypes.FunctionToolsExecuted, this.onFunctionToolsExecuted);
|
|
321
|
+
this.session.on(AgentSessionEventTypes.MetricsCollected, this.onMetricsCollected);
|
|
322
|
+
this.session.on(AgentSessionEventTypes.UserInputTranscribed, this.onUserInputTranscribed);
|
|
323
|
+
this.session.on(AgentSessionEventTypes.UserOverlappingSpeech, this.onUserOverlapSpeech);
|
|
324
|
+
this.session.on(AgentSessionEventTypes.Error, this.onError);
|
|
325
|
+
this.eventHandlersRegistered = true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private onStreamRequest = (
|
|
329
|
+
reader: TextStreamReader,
|
|
330
|
+
participantInfo: { identity: string },
|
|
331
|
+
): void => {
|
|
332
|
+
const task = Task.from(async () => this.handleStreamRequest(reader, participantInfo.identity));
|
|
333
|
+
this.trackTask(task);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
private async handleStreamRequest(
|
|
337
|
+
reader: TextStreamReader,
|
|
338
|
+
participantIdentity: string,
|
|
339
|
+
): Promise<void> {
|
|
340
|
+
try {
|
|
341
|
+
const data = await reader.readAll();
|
|
342
|
+
const request = streamRequestSchema.parse(JSON.parse(data));
|
|
343
|
+
|
|
344
|
+
let responsePayload = '';
|
|
345
|
+
let error: string | null = null;
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
switch (request.method) {
|
|
349
|
+
case 'get_session_state':
|
|
350
|
+
responsePayload = await this.streamGetSessionState();
|
|
351
|
+
break;
|
|
352
|
+
case 'get_chat_history':
|
|
353
|
+
responsePayload = await this.streamGetChatHistory();
|
|
354
|
+
break;
|
|
355
|
+
case 'get_agent_info':
|
|
356
|
+
responsePayload = await this.streamGetAgentInfo();
|
|
357
|
+
break;
|
|
358
|
+
case 'send_message':
|
|
359
|
+
responsePayload = await this.streamSendMessage(request.payload);
|
|
360
|
+
break;
|
|
361
|
+
case 'get_rtc_stats':
|
|
362
|
+
responsePayload = await this.streamGetRtcStats();
|
|
363
|
+
break;
|
|
364
|
+
case 'get_session_usage':
|
|
365
|
+
responsePayload = await this.streamGetSessionUsage();
|
|
366
|
+
break;
|
|
367
|
+
default:
|
|
368
|
+
error = `Unknown method: ${request.method}`;
|
|
369
|
+
}
|
|
370
|
+
} catch (e) {
|
|
371
|
+
error = e instanceof Error ? e.message : String(e);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const response: StreamResponse = {
|
|
375
|
+
request_id: request.request_id,
|
|
376
|
+
payload: responsePayload,
|
|
377
|
+
error,
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
const localParticipant = this.room.localParticipant;
|
|
381
|
+
await localParticipant!.sendText(JSON.stringify(response), {
|
|
382
|
+
topic: TOPIC_AGENT_RESPONSE,
|
|
383
|
+
destinationIdentities: [participantIdentity],
|
|
384
|
+
});
|
|
385
|
+
} catch (e) {
|
|
386
|
+
this.logger.warn({ error: e }, 'failed to handle stream request');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
private async streamGetSessionState(): Promise<string> {
|
|
391
|
+
const agent = this.session.currentAgent;
|
|
392
|
+
|
|
393
|
+
const response: GetSessionStateResponse = {
|
|
394
|
+
agent_state: this.session.agentState,
|
|
395
|
+
user_state: this.session.userState,
|
|
396
|
+
agent_id: agent.id,
|
|
397
|
+
options: serializeOptions({
|
|
398
|
+
turnHandling: this.session.options.turnHandling,
|
|
399
|
+
maxToolSteps: this.session.options.maxToolSteps,
|
|
400
|
+
userAwayTimeout: this.session.options.userAwayTimeout,
|
|
401
|
+
preemptiveGeneration: this.session.options.preemptiveGeneration,
|
|
402
|
+
useTtsAlignedTranscript: this.session.options.useTtsAlignedTranscript,
|
|
403
|
+
}),
|
|
404
|
+
created_at: msToS(this.session._startedAt ?? Date.now()),
|
|
405
|
+
};
|
|
406
|
+
return JSON.stringify(response);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private async streamGetChatHistory(): Promise<string> {
|
|
410
|
+
return JSON.stringify({
|
|
411
|
+
items: this.session.history.items.map(chatItemToWire),
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private async streamGetAgentInfo(): Promise<string> {
|
|
416
|
+
const agent = this.session.currentAgent;
|
|
417
|
+
return JSON.stringify({
|
|
418
|
+
id: agent.id,
|
|
419
|
+
instructions: agent.instructions,
|
|
420
|
+
tools: toolNames(agent.toolCtx),
|
|
421
|
+
chat_ctx: agent.chatCtx.items.map(chatItemToWire),
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
private async streamSendMessage(payload: string): Promise<string> {
|
|
426
|
+
const request = sendMessageRequestSchema.parse(JSON.parse(payload));
|
|
427
|
+
const runResult = this.session.run({ userInput: request.text });
|
|
428
|
+
await runResult.wait();
|
|
429
|
+
return JSON.stringify({
|
|
430
|
+
items: runResult.events.map((ev) => chatItemToWire(ev.item)),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private async streamGetRtcStats(): Promise<string> {
|
|
435
|
+
// TODO(parity): map rtc stats fields once getRtcStats API shape is finalized in rtc-node.
|
|
436
|
+
return JSON.stringify({
|
|
437
|
+
publisher_stats: [],
|
|
438
|
+
subscriber_stats: [],
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
private async streamGetSessionUsage(): Promise<string> {
|
|
443
|
+
return JSON.stringify({
|
|
444
|
+
usage: agentSessionUsageToWire(this.session.usage),
|
|
445
|
+
created_at: msToS(Date.now()),
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
private onUserOverlapSpeech = (event: OverlappingSpeechEvent): void => {
|
|
450
|
+
const clientEvent: ClientUserOverlappingSpeechEvent = {
|
|
451
|
+
type: 'user_overlapping_speech',
|
|
452
|
+
is_interruption: event.isInterruption,
|
|
453
|
+
created_at: msToS(event.timestamp),
|
|
454
|
+
overlap_started_at: event.overlapStartedAt != null ? msToS(event.overlapStartedAt) : null,
|
|
455
|
+
detection_delay: event.detectionDelayInS,
|
|
456
|
+
sent_at: msToS(Date.now()),
|
|
457
|
+
};
|
|
458
|
+
this.streamClientEvent(clientEvent);
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
private onAgentStateChanged = (event: AgentStateChangedEvent): void => {
|
|
462
|
+
const clientEvent: ClientAgentStateChangedEvent = {
|
|
463
|
+
type: 'agent_state_changed',
|
|
464
|
+
old_state: event.oldState,
|
|
465
|
+
new_state: event.newState,
|
|
466
|
+
created_at: msToS(event.createdAt),
|
|
467
|
+
};
|
|
468
|
+
this.streamClientEvent(clientEvent);
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
private onUserStateChanged = (event: UserStateChangedEvent): void => {
|
|
472
|
+
const clientEvent: ClientUserStateChangedEvent = {
|
|
473
|
+
type: 'user_state_changed',
|
|
474
|
+
old_state: event.oldState,
|
|
475
|
+
new_state: event.newState,
|
|
476
|
+
created_at: msToS(event.createdAt),
|
|
477
|
+
};
|
|
478
|
+
this.streamClientEvent(clientEvent);
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
private onConversationItemAdded = (event: ConversationItemAddedEvent): void => {
|
|
482
|
+
if (event.item.type !== 'message') {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
this.streamClientEvent({
|
|
486
|
+
type: 'conversation_item_added',
|
|
487
|
+
item: chatMessageToWire(event.item) as ClientConversationItemAddedEvent['item'],
|
|
488
|
+
created_at: msToS(event.createdAt),
|
|
489
|
+
});
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
private onUserInputTranscribed = (event: UserInputTranscribedEvent): void => {
|
|
493
|
+
this.streamClientEvent({
|
|
494
|
+
type: 'user_input_transcribed',
|
|
495
|
+
transcript: event.transcript,
|
|
496
|
+
is_final: event.isFinal,
|
|
497
|
+
language: event.language,
|
|
498
|
+
created_at: msToS(event.createdAt),
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
private onFunctionToolsExecuted = (event: FunctionToolsExecutedEvent): void => {
|
|
503
|
+
this.streamClientEvent({
|
|
504
|
+
type: 'function_tools_executed',
|
|
505
|
+
function_calls: event.functionCalls.map(
|
|
506
|
+
functionCallToWire,
|
|
507
|
+
) as ClientFunctionToolsExecutedEvent['function_calls'],
|
|
508
|
+
function_call_outputs: event.functionCallOutputs.map((o) =>
|
|
509
|
+
o
|
|
510
|
+
? (functionCallOutputToWire(o) as NonNullable<
|
|
511
|
+
ClientFunctionToolsExecutedEvent['function_call_outputs'][number]
|
|
512
|
+
>)
|
|
513
|
+
: null,
|
|
514
|
+
),
|
|
515
|
+
created_at: msToS(event.createdAt),
|
|
516
|
+
});
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
private onMetricsCollected = (event: MetricsCollectedEvent): void => {
|
|
520
|
+
this.streamClientEvent({
|
|
521
|
+
type: 'metrics_collected',
|
|
522
|
+
metrics: agentMetricsToWire(event.metrics) as ClientMetricsCollectedEvent['metrics'],
|
|
523
|
+
created_at: msToS(event.createdAt),
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
this.streamClientEvent({
|
|
527
|
+
type: 'session_usage',
|
|
528
|
+
usage: agentSessionUsageToWire(this.session.usage) as ClientSessionUsageEvent['usage'],
|
|
529
|
+
created_at: msToS(Date.now()),
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
private onError = (event: ErrorEvent): void => {
|
|
534
|
+
const clientEvent: ClientErrorEvent = {
|
|
535
|
+
type: 'error',
|
|
536
|
+
message: event.error ? String(event.error) : 'Unknown error',
|
|
537
|
+
created_at: msToS(event.createdAt),
|
|
538
|
+
};
|
|
539
|
+
this.streamClientEvent(clientEvent);
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
private getTargetIdentities(): string[] | null {
|
|
543
|
+
const linked = this.roomIO.linkedParticipant;
|
|
544
|
+
|
|
545
|
+
// TODO(permissions): check linked.permissions.can_subscribe_metrics
|
|
546
|
+
return linked ? [linked.identity] : null;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
private streamClientEvent(event: ClientEvent): void {
|
|
550
|
+
const task = Task.from(async () => this.sendClientEvent(event));
|
|
551
|
+
this.trackTask(task);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
private async sendClientEvent(event: ClientEvent): Promise<void> {
|
|
555
|
+
if (!this.room.isConnected) return;
|
|
556
|
+
|
|
557
|
+
const destinationIdentities = this.getTargetIdentities();
|
|
558
|
+
if (!destinationIdentities) return;
|
|
559
|
+
|
|
560
|
+
try {
|
|
561
|
+
const localParticipant = this.room.localParticipant;
|
|
562
|
+
if (!localParticipant) return;
|
|
563
|
+
|
|
564
|
+
const writer = await localParticipant.streamText({
|
|
565
|
+
topic: TOPIC_CLIENT_EVENTS,
|
|
566
|
+
destinationIdentities,
|
|
567
|
+
});
|
|
568
|
+
await writer.write(JSON.stringify(event));
|
|
569
|
+
await writer.close();
|
|
570
|
+
} catch (e) {
|
|
571
|
+
this.logger.warn({ error: e }, 'failed to stream event to clients');
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
private rpcGetSessionState = async (): Promise<string> => {
|
|
576
|
+
return this.streamGetSessionState();
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
private rpcGetChatHistory = async (): Promise<string> => {
|
|
580
|
+
return this.streamGetChatHistory();
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
private rpcGetAgentInfo = async (): Promise<string> => {
|
|
584
|
+
return this.streamGetAgentInfo();
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
private rpcSendMessage = async (data: RpcInvocationData): Promise<string> => {
|
|
588
|
+
return this.streamSendMessage(data.payload);
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
private onUserTextInput = (
|
|
592
|
+
reader: TextStreamReader,
|
|
593
|
+
participantInfo: { identity: string },
|
|
594
|
+
): void => {
|
|
595
|
+
const linkedParticipant = this.roomIO.linkedParticipant;
|
|
596
|
+
if (linkedParticipant && participantInfo.identity !== linkedParticipant.identity) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const participant = this.room.remoteParticipants.get(participantInfo.identity);
|
|
601
|
+
if (!participant) {
|
|
602
|
+
this.logger.warn('participant not found, ignoring text input');
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (!this.textInputCb) {
|
|
607
|
+
this.logger.error('text input callback is not set, ignoring text input');
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const task = Task.from(async () => {
|
|
612
|
+
const text = await reader.readAll();
|
|
613
|
+
const result = this.textInputCb!(this.session, {
|
|
614
|
+
text,
|
|
615
|
+
info: reader.info,
|
|
616
|
+
participantIdentity: participantInfo.identity,
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
if (result instanceof Promise) {
|
|
620
|
+
await result;
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
this.trackTask(task);
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
private trackTask(task: Task<void>): void {
|
|
628
|
+
this.tasks.add(task);
|
|
629
|
+
task.addDoneCallback(() => {
|
|
630
|
+
this.tasks.delete(task);
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Client-side interface to interact with a remote AgentSession.
|
|
637
|
+
*
|
|
638
|
+
* This class allows frontends/clients to:
|
|
639
|
+
* - Subscribe to real-time events from the agent session
|
|
640
|
+
* - Query session state, chat history, and agent info via RPC
|
|
641
|
+
* - Send messages to the agent
|
|
642
|
+
*
|
|
643
|
+
* Example:
|
|
644
|
+
* ```typescript
|
|
645
|
+
* const session = new RemoteSession(room, agentIdentity);
|
|
646
|
+
* session.on('agent_state_changed', (event) => {
|
|
647
|
+
* console.log('Agent state changed:', event.new_state);
|
|
648
|
+
* });
|
|
649
|
+
* session.on('user_state_changed', (event) => {
|
|
650
|
+
* console.log('User state changed:', event.new_state);
|
|
651
|
+
* });
|
|
652
|
+
* session.on('conversation_item_added', (event) => {
|
|
653
|
+
* console.log('Conversation item added:', event.item);
|
|
654
|
+
* });
|
|
655
|
+
* await session.start();
|
|
656
|
+
*
|
|
657
|
+
* const state = await session.fetchSessionState();
|
|
658
|
+
* console.log('Session state:', state);
|
|
659
|
+
*
|
|
660
|
+
* const response = await session.sendMessage('Hello!');
|
|
661
|
+
* console.log('Response:', response);
|
|
662
|
+
* ```
|
|
663
|
+
*/
|
|
664
|
+
// TODO: expose this class
|
|
665
|
+
/** @experimental */
|
|
666
|
+
export class RemoteSession extends (EventEmitter as new () => TypedEventEmitter<RemoteSessionCallbacks>) {
|
|
667
|
+
private readonly room: Room;
|
|
668
|
+
private readonly agentIdentity: string;
|
|
669
|
+
private started = false;
|
|
670
|
+
|
|
671
|
+
private readonly tasks = new Set<Task<void>>();
|
|
672
|
+
private readonly pendingRequests = new Map<string, Future<StreamResponse>>();
|
|
673
|
+
private readonly logger = log();
|
|
674
|
+
|
|
675
|
+
constructor(room: Room, agentIdentity: string) {
|
|
676
|
+
super();
|
|
677
|
+
this.room = room;
|
|
678
|
+
this.agentIdentity = agentIdentity;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
async start(): Promise<void> {
|
|
682
|
+
if (this.started) return;
|
|
683
|
+
this.started = true;
|
|
684
|
+
this.room.registerTextStreamHandler(TOPIC_CLIENT_EVENTS, this.onEventStream);
|
|
685
|
+
this.room.registerTextStreamHandler(TOPIC_AGENT_RESPONSE, this.onResponseStream);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
async close(): Promise<void> {
|
|
689
|
+
if (!this.started) return;
|
|
690
|
+
|
|
691
|
+
this.started = false;
|
|
692
|
+
this.room.unregisterTextStreamHandler(TOPIC_CLIENT_EVENTS);
|
|
693
|
+
this.room.unregisterTextStreamHandler(TOPIC_AGENT_RESPONSE);
|
|
694
|
+
|
|
695
|
+
for (const pending of this.pendingRequests.values()) {
|
|
696
|
+
pending.reject(new Error('RemoteSession closed'));
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
this.pendingRequests.clear();
|
|
700
|
+
|
|
701
|
+
await cancelAndWait([...this.tasks]);
|
|
702
|
+
this.tasks.clear();
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
private onEventStream = (
|
|
706
|
+
reader: TextStreamReader,
|
|
707
|
+
participantInfo: { identity: string },
|
|
708
|
+
): void => {
|
|
709
|
+
if (participantInfo.identity !== this.agentIdentity) return;
|
|
710
|
+
this.trackTask(Task.from(async () => this.readEvent(reader)));
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
private onResponseStream = (
|
|
714
|
+
reader: TextStreamReader,
|
|
715
|
+
participantInfo: { identity: string },
|
|
716
|
+
): void => {
|
|
717
|
+
if (participantInfo.identity !== this.agentIdentity) return;
|
|
718
|
+
this.trackTask(Task.from(async () => this.readResponse(reader)));
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
private async readResponse(reader: TextStreamReader): Promise<void> {
|
|
722
|
+
try {
|
|
723
|
+
const data = await reader.readAll();
|
|
724
|
+
const response = streamResponseSchema.parse(JSON.parse(data));
|
|
725
|
+
const future = this.pendingRequests.get(response.request_id);
|
|
726
|
+
this.pendingRequests.delete(response.request_id);
|
|
727
|
+
|
|
728
|
+
if (!future || future.done) return;
|
|
729
|
+
future.resolve(response);
|
|
730
|
+
} catch (e) {
|
|
731
|
+
this.logger.warn({ error: e }, 'failed to read stream response');
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
private async readEvent(reader: TextStreamReader): Promise<void> {
|
|
736
|
+
try {
|
|
737
|
+
const data = await reader.readAll();
|
|
738
|
+
const event = this.parseEvent(data);
|
|
739
|
+
if (event) {
|
|
740
|
+
this.emit(event.type, event as never);
|
|
741
|
+
}
|
|
742
|
+
} catch (e) {
|
|
743
|
+
this.logger.warn({ error: e }, 'failed to parse client event');
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
private parseEvent(data: string): ClientEvent | null {
|
|
748
|
+
try {
|
|
749
|
+
const result = clientEventSchema.safeParse(JSON.parse(data));
|
|
750
|
+
if (!result.success) {
|
|
751
|
+
this.logger.warn({ error: result.error }, 'failed to validate event');
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
return result.data;
|
|
755
|
+
} catch (e) {
|
|
756
|
+
this.logger.warn({ error: e }, 'failed to parse event');
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
private async sendRequest(method: string, payload: string, timeout = 60000): Promise<string> {
|
|
762
|
+
const requestId = shortuuid('req_');
|
|
763
|
+
const request: StreamRequest = {
|
|
764
|
+
request_id: requestId,
|
|
765
|
+
method,
|
|
766
|
+
payload,
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
const future = new Future<StreamResponse>();
|
|
770
|
+
this.pendingRequests.set(requestId, future);
|
|
771
|
+
|
|
772
|
+
const localParticipant = this.room.localParticipant;
|
|
773
|
+
if (!localParticipant) {
|
|
774
|
+
this.pendingRequests.delete(requestId);
|
|
775
|
+
throw new Error('RemoteSession room has no local participant');
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
await localParticipant.sendText(JSON.stringify(request), {
|
|
779
|
+
topic: TOPIC_AGENT_REQUEST,
|
|
780
|
+
destinationIdentities: [this.agentIdentity],
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
const timer = setTimeout(() => {
|
|
784
|
+
if (!future.done) {
|
|
785
|
+
this.pendingRequests.delete(requestId);
|
|
786
|
+
future.reject(new Error(`RemoteSession request timed out: ${method}`));
|
|
787
|
+
}
|
|
788
|
+
}, timeout);
|
|
789
|
+
|
|
790
|
+
try {
|
|
791
|
+
const response = await future.await;
|
|
792
|
+
if (response.error) {
|
|
793
|
+
throw new Error(response.error);
|
|
794
|
+
}
|
|
795
|
+
return response.payload;
|
|
796
|
+
} finally {
|
|
797
|
+
clearTimeout(timer);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
async fetchSessionState(): Promise<GetSessionStateResponse> {
|
|
802
|
+
const raw = JSON.parse(await this.sendRequest('get_session_state', '{}'));
|
|
803
|
+
return getSessionStateResponseSchema.parse(raw);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
async fetchChatHistory(): Promise<GetChatHistoryResponse> {
|
|
807
|
+
const raw = JSON.parse(await this.sendRequest('get_chat_history', '{}'));
|
|
808
|
+
return getChatHistoryResponseSchema.parse(raw);
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
async fetchAgentInfo(): Promise<GetAgentInfoResponse> {
|
|
812
|
+
const raw = JSON.parse(await this.sendRequest('get_agent_info', '{}'));
|
|
813
|
+
return getAgentInfoResponseSchema.parse(raw);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
async sendMessage(text: string, responseTimeout = 60000): Promise<SendMessageResponse> {
|
|
817
|
+
const payload = JSON.stringify({ text } satisfies SendMessageRequest);
|
|
818
|
+
const raw = JSON.parse(await this.sendRequest('send_message', payload, responseTimeout));
|
|
819
|
+
return sendMessageResponseSchema.parse(raw);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
async fetchRtcStats(): Promise<GetRTCStatsResponse> {
|
|
823
|
+
const raw = JSON.parse(await this.sendRequest('get_rtc_stats', '{}'));
|
|
824
|
+
return getRTCStatsResponseSchema.parse(raw);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
async fetchSessionUsage(): Promise<GetSessionUsageResponse> {
|
|
828
|
+
const raw = JSON.parse(await this.sendRequest('get_session_usage', '{}'));
|
|
829
|
+
return getSessionUsageResponseSchema.parse(raw);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
private trackTask(task: Task<void>): void {
|
|
833
|
+
this.tasks.add(task);
|
|
834
|
+
task.addDoneCallback(() => {
|
|
835
|
+
this.tasks.delete(task);
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|