vision-agents 0.2.3__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.
- vision_agents-0.2.3/.gitignore +90 -0
- vision_agents-0.2.3/PKG-INFO +91 -0
- vision_agents-0.2.3/README.md +13 -0
- vision_agents-0.2.3/pyproject.toml +91 -0
- vision_agents-0.2.3/vision_agents/PROTOBUF_GENERATION.md +286 -0
- vision_agents-0.2.3/vision_agents/_generate_sfu_events.py +590 -0
- vision_agents-0.2.3/vision_agents/core/__init__.py +8 -0
- vision_agents-0.2.3/vision_agents/core/agents/__init__.py +15 -0
- vision_agents-0.2.3/vision_agents/core/agents/agent_launcher.py +131 -0
- vision_agents-0.2.3/vision_agents/core/agents/agent_session.py +89 -0
- vision_agents-0.2.3/vision_agents/core/agents/agent_types.py +56 -0
- vision_agents-0.2.3/vision_agents/core/agents/agents.py +1357 -0
- vision_agents-0.2.3/vision_agents/core/agents/conversation.py +237 -0
- vision_agents-0.2.3/vision_agents/core/agents/events.py +66 -0
- vision_agents-0.2.3/vision_agents/core/agents/transcript_buffer.py +89 -0
- vision_agents-0.2.3/vision_agents/core/cli/__init__.py +0 -0
- vision_agents-0.2.3/vision_agents/core/cli/cli_runner.py +140 -0
- vision_agents-0.2.3/vision_agents/core/cli.py +92 -0
- vision_agents-0.2.3/vision_agents/core/edge/__init__.py +9 -0
- vision_agents-0.2.3/vision_agents/core/edge/edge_transport.py +61 -0
- vision_agents-0.2.3/vision_agents/core/edge/events.py +43 -0
- vision_agents-0.2.3/vision_agents/core/edge/sfu_events.py +2360 -0
- vision_agents-0.2.3/vision_agents/core/edge/types.py +49 -0
- vision_agents-0.2.3/vision_agents/core/events/__init__.py +131 -0
- vision_agents-0.2.3/vision_agents/core/events/base.py +139 -0
- vision_agents-0.2.3/vision_agents/core/events/manager.py +561 -0
- vision_agents-0.2.3/vision_agents/core/instructions.py +115 -0
- vision_agents-0.2.3/vision_agents/core/llm/__init__.py +13 -0
- vision_agents-0.2.3/vision_agents/core/llm/events.py +153 -0
- vision_agents-0.2.3/vision_agents/core/llm/function_registry.py +282 -0
- vision_agents-0.2.3/vision_agents/core/llm/llm.py +455 -0
- vision_agents-0.2.3/vision_agents/core/llm/llm_test.py +21 -0
- vision_agents-0.2.3/vision_agents/core/llm/llm_types.py +166 -0
- vision_agents-0.2.3/vision_agents/core/llm/realtime.py +188 -0
- vision_agents-0.2.3/vision_agents/core/llm/wrap_function.py +51 -0
- vision_agents-0.2.3/vision_agents/core/llm/wrap_method.py +60 -0
- vision_agents-0.2.3/vision_agents/core/mcp/__init__.py +15 -0
- vision_agents-0.2.3/vision_agents/core/mcp/mcp_base.py +189 -0
- vision_agents-0.2.3/vision_agents/core/mcp/mcp_manager.py +158 -0
- vision_agents-0.2.3/vision_agents/core/mcp/mcp_server_local.py +146 -0
- vision_agents-0.2.3/vision_agents/core/mcp/mcp_server_remote.py +153 -0
- vision_agents-0.2.3/vision_agents/core/mcp/tool_converter.py +101 -0
- vision_agents-0.2.3/vision_agents/core/observability/__init__.py +31 -0
- vision_agents-0.2.3/vision_agents/core/observability/metrics.py +77 -0
- vision_agents-0.2.3/vision_agents/core/processors/__init__.py +34 -0
- vision_agents-0.2.3/vision_agents/core/processors/base_processor.py +207 -0
- vision_agents-0.2.3/vision_agents/core/profiling/__init__.py +3 -0
- vision_agents-0.2.3/vision_agents/core/profiling/base.py +49 -0
- vision_agents-0.2.3/vision_agents/core/stt/__init__.py +4 -0
- vision_agents-0.2.3/vision_agents/core/stt/events.py +104 -0
- vision_agents-0.2.3/vision_agents/core/stt/stt.py +175 -0
- vision_agents-0.2.3/vision_agents/core/tts/__init__.py +3 -0
- vision_agents-0.2.3/vision_agents/core/tts/events.py +72 -0
- vision_agents-0.2.3/vision_agents/core/tts/manual_test.py +135 -0
- vision_agents-0.2.3/vision_agents/core/tts/testing.py +129 -0
- vision_agents-0.2.3/vision_agents/core/tts/tts.py +314 -0
- vision_agents-0.2.3/vision_agents/core/turn_detection/README.md +113 -0
- vision_agents-0.2.3/vision_agents/core/turn_detection/__init__.py +18 -0
- vision_agents-0.2.3/vision_agents/core/turn_detection/events.py +49 -0
- vision_agents-0.2.3/vision_agents/core/turn_detection/turn_detection.py +92 -0
- vision_agents-0.2.3/vision_agents/core/utils/__init__.py +13 -0
- vision_agents-0.2.3/vision_agents/core/utils/audio_forwarder.py +67 -0
- vision_agents-0.2.3/vision_agents/core/utils/audio_queue.py +275 -0
- vision_agents-0.2.3/vision_agents/core/utils/audio_track.py +11 -0
- vision_agents-0.2.3/vision_agents/core/utils/examples.py +42 -0
- vision_agents-0.2.3/vision_agents/core/utils/logging.py +108 -0
- vision_agents-0.2.3/vision_agents/core/utils/utils.py +83 -0
- vision_agents-0.2.3/vision_agents/core/utils/video_forwarder.py +185 -0
- vision_agents-0.2.3/vision_agents/core/utils/video_queue.py +30 -0
- vision_agents-0.2.3/vision_agents/core/utils/video_track.py +90 -0
- vision_agents-0.2.3/vision_agents/core/utils/video_utils.py +127 -0
- vision_agents-0.2.3/vision_agents/core/vad/__init__.py +0 -0
- vision_agents-0.2.3/vision_agents/core/vad/silero.py +96 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.cursor/*
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
.Python
|
|
9
|
+
build/
|
|
10
|
+
dist/
|
|
11
|
+
downloads/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
eggs/
|
|
14
|
+
.eggs/
|
|
15
|
+
lib64/
|
|
16
|
+
parts/
|
|
17
|
+
sdist/
|
|
18
|
+
var/
|
|
19
|
+
wheels/
|
|
20
|
+
share/python-wheels/
|
|
21
|
+
pip-wheel-metadata/
|
|
22
|
+
MANIFEST
|
|
23
|
+
*.egg-info/
|
|
24
|
+
*.egg
|
|
25
|
+
|
|
26
|
+
# Installer logs
|
|
27
|
+
pip-log.txt
|
|
28
|
+
pip-delete-this-directory.txt
|
|
29
|
+
|
|
30
|
+
# Unit test / coverage reports
|
|
31
|
+
htmlcov/
|
|
32
|
+
.tox/
|
|
33
|
+
.nox/
|
|
34
|
+
.coverage
|
|
35
|
+
.coverage.*
|
|
36
|
+
.cache
|
|
37
|
+
coverage.xml
|
|
38
|
+
nosetests.xml
|
|
39
|
+
*.cover
|
|
40
|
+
*.py,cover
|
|
41
|
+
.hypothesis/
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
|
|
44
|
+
# Type checker / lint caches
|
|
45
|
+
.mypy_cache/
|
|
46
|
+
.dmypy.json
|
|
47
|
+
dmypy.json
|
|
48
|
+
.pytype/
|
|
49
|
+
.pyre/
|
|
50
|
+
.ruff_cache/
|
|
51
|
+
|
|
52
|
+
# Environments
|
|
53
|
+
.venv
|
|
54
|
+
env/
|
|
55
|
+
venv/
|
|
56
|
+
ENV/
|
|
57
|
+
env.bak/
|
|
58
|
+
venv.bak/
|
|
59
|
+
.env
|
|
60
|
+
.env.local
|
|
61
|
+
.env.*.local
|
|
62
|
+
.env.bak
|
|
63
|
+
pyvenv.cfg
|
|
64
|
+
.python-version
|
|
65
|
+
|
|
66
|
+
# Editors / IDEs
|
|
67
|
+
.vscode/
|
|
68
|
+
.idea/
|
|
69
|
+
|
|
70
|
+
# Jupyter Notebook
|
|
71
|
+
.ipynb_checkpoints/
|
|
72
|
+
|
|
73
|
+
# OS / Misc
|
|
74
|
+
.DS_Store
|
|
75
|
+
*.log
|
|
76
|
+
|
|
77
|
+
# Tooling & repo-specific
|
|
78
|
+
pyrightconfig.json
|
|
79
|
+
shell.nix
|
|
80
|
+
bin/*
|
|
81
|
+
lib/*
|
|
82
|
+
stream-py/
|
|
83
|
+
|
|
84
|
+
# Artifacts / assets
|
|
85
|
+
*.pt
|
|
86
|
+
*.kef
|
|
87
|
+
*.onnx
|
|
88
|
+
profile.html
|
|
89
|
+
|
|
90
|
+
/opencode.json
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vision-agents
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Open video agents. Build low latency video and voice agents on any realtime edge network.
|
|
5
|
+
Project-URL: Documentation, https://visionagents.ai/
|
|
6
|
+
Project-URL: Website, https://visionagents.ai/
|
|
7
|
+
Project-URL: Source, https://github.com/GetStream/Vision-Agents
|
|
8
|
+
Keywords: AI,agents,video AI,video agents,voice AI,voice agents
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: colorlog>=6.10.1
|
|
18
|
+
Requires-Dist: getstream[telemetry,webrtc]>=2.5.16
|
|
19
|
+
Requires-Dist: mcp>=1.16.0
|
|
20
|
+
Requires-Dist: numpy>=1.24.0
|
|
21
|
+
Requires-Dist: pillow>=10.4.0
|
|
22
|
+
Requires-Dist: python-dotenv>=1.1.1
|
|
23
|
+
Provides-Extra: all-plugins
|
|
24
|
+
Requires-Dist: vision-agents-plugins-anthropic; extra == 'all-plugins'
|
|
25
|
+
Requires-Dist: vision-agents-plugins-cartesia; extra == 'all-plugins'
|
|
26
|
+
Requires-Dist: vision-agents-plugins-deepgram; extra == 'all-plugins'
|
|
27
|
+
Requires-Dist: vision-agents-plugins-elevenlabs; extra == 'all-plugins'
|
|
28
|
+
Requires-Dist: vision-agents-plugins-gemini; extra == 'all-plugins'
|
|
29
|
+
Requires-Dist: vision-agents-plugins-getstream; extra == 'all-plugins'
|
|
30
|
+
Requires-Dist: vision-agents-plugins-heygen; extra == 'all-plugins'
|
|
31
|
+
Requires-Dist: vision-agents-plugins-inworld; extra == 'all-plugins'
|
|
32
|
+
Requires-Dist: vision-agents-plugins-kokoro; extra == 'all-plugins'
|
|
33
|
+
Requires-Dist: vision-agents-plugins-moonshine; extra == 'all-plugins'
|
|
34
|
+
Requires-Dist: vision-agents-plugins-openai; extra == 'all-plugins'
|
|
35
|
+
Requires-Dist: vision-agents-plugins-roboflow; extra == 'all-plugins'
|
|
36
|
+
Requires-Dist: vision-agents-plugins-smart-turn; extra == 'all-plugins'
|
|
37
|
+
Requires-Dist: vision-agents-plugins-ultralytics; extra == 'all-plugins'
|
|
38
|
+
Requires-Dist: vision-agents-plugins-wizper; extra == 'all-plugins'
|
|
39
|
+
Requires-Dist: vision-agents-plugins-xai; extra == 'all-plugins'
|
|
40
|
+
Provides-Extra: anthropic
|
|
41
|
+
Requires-Dist: vision-agents-plugins-anthropic; extra == 'anthropic'
|
|
42
|
+
Provides-Extra: cartesia
|
|
43
|
+
Requires-Dist: vision-agents-plugins-cartesia; extra == 'cartesia'
|
|
44
|
+
Provides-Extra: deepgram
|
|
45
|
+
Requires-Dist: vision-agents-plugins-deepgram; extra == 'deepgram'
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: click; extra == 'dev'
|
|
48
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
50
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
51
|
+
Provides-Extra: elevenlabs
|
|
52
|
+
Requires-Dist: vision-agents-plugins-elevenlabs; extra == 'elevenlabs'
|
|
53
|
+
Provides-Extra: gemini
|
|
54
|
+
Requires-Dist: vision-agents-plugins-gemini; extra == 'gemini'
|
|
55
|
+
Provides-Extra: getstream
|
|
56
|
+
Requires-Dist: vision-agents-plugins-getstream; extra == 'getstream'
|
|
57
|
+
Provides-Extra: heygen
|
|
58
|
+
Requires-Dist: vision-agents-plugins-heygen; extra == 'heygen'
|
|
59
|
+
Provides-Extra: inworld
|
|
60
|
+
Requires-Dist: vision-agents-plugins-inworld; extra == 'inworld'
|
|
61
|
+
Provides-Extra: kokoro
|
|
62
|
+
Requires-Dist: vision-agents-plugins-kokoro; extra == 'kokoro'
|
|
63
|
+
Provides-Extra: moonshine
|
|
64
|
+
Requires-Dist: vision-agents-plugins-moonshine; extra == 'moonshine'
|
|
65
|
+
Provides-Extra: openai
|
|
66
|
+
Requires-Dist: vision-agents-plugins-openai; extra == 'openai'
|
|
67
|
+
Provides-Extra: roboflow
|
|
68
|
+
Requires-Dist: vision-agents-plugins-roboflow; extra == 'roboflow'
|
|
69
|
+
Provides-Extra: smart-turn
|
|
70
|
+
Requires-Dist: vision-agents-plugins-smart-turn; extra == 'smart-turn'
|
|
71
|
+
Provides-Extra: ultralytics
|
|
72
|
+
Requires-Dist: vision-agents-plugins-ultralytics; extra == 'ultralytics'
|
|
73
|
+
Provides-Extra: wizper
|
|
74
|
+
Requires-Dist: vision-agents-plugins-wizper; extra == 'wizper'
|
|
75
|
+
Provides-Extra: xai
|
|
76
|
+
Requires-Dist: vision-agents-plugins-xai; extra == 'xai'
|
|
77
|
+
Description-Content-Type: text/markdown
|
|
78
|
+
|
|
79
|
+
# Open Vision Agents by Stream
|
|
80
|
+
|
|
81
|
+
Build Vision Agents quickly with any model or video provider.
|
|
82
|
+
|
|
83
|
+
- **Video AI**: Built for real-time video AI. Combine Yolo, Roboflow and others with gemini/openai realtime
|
|
84
|
+
- **Low Latency**: Join quickly (500ms) and low audio/video latency (30ms)
|
|
85
|
+
- **Open**: Built by Stream, but use any video edge network that you like
|
|
86
|
+
- **Native APIs**: Native SDK methods from OpenAI (create response), Gemini (generate) and Claude (create message). So you're never behind on the latest features
|
|
87
|
+
- **SDKs**: SDKs for React, Android, iOS, Flutter, React, React Native and Unity.
|
|
88
|
+
|
|
89
|
+
Created by Stream, uses [Stream's edge network](https://getstream.io/video/) for ultra-low latency.
|
|
90
|
+
|
|
91
|
+
See [Github](https://github.com/GetStream/Vision-Agents).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Open Vision Agents by Stream
|
|
2
|
+
|
|
3
|
+
Build Vision Agents quickly with any model or video provider.
|
|
4
|
+
|
|
5
|
+
- **Video AI**: Built for real-time video AI. Combine Yolo, Roboflow and others with gemini/openai realtime
|
|
6
|
+
- **Low Latency**: Join quickly (500ms) and low audio/video latency (30ms)
|
|
7
|
+
- **Open**: Built by Stream, but use any video edge network that you like
|
|
8
|
+
- **Native APIs**: Native SDK methods from OpenAI (create response), Gemini (generate) and Claude (create message). So you're never behind on the latest features
|
|
9
|
+
- **SDKs**: SDKs for React, Android, iOS, Flutter, React, React Native and Unity.
|
|
10
|
+
|
|
11
|
+
Created by Stream, uses [Stream's edge network](https://getstream.io/video/) for ultra-low latency.
|
|
12
|
+
|
|
13
|
+
See [Github](https://github.com/GetStream/Vision-Agents).
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs", "setuptools-scm"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vision-agents"
|
|
7
|
+
description = "Open video agents. Build low latency video and voice agents on any realtime edge network."
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
keywords = ["video AI", "AI", "voice AI", "video agents", "voice agents", "agents", "AI"]
|
|
10
|
+
dynamic = ["version"]
|
|
11
|
+
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.10",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
requires-python = ">=3.10"
|
|
23
|
+
dependencies = [
|
|
24
|
+
"getstream[webrtc,telemetry]>=2.5.16",
|
|
25
|
+
"python-dotenv>=1.1.1",
|
|
26
|
+
"pillow>=10.4.0", # Compatible with moondream SDK (<11.0.0)
|
|
27
|
+
"numpy>=1.24.0",
|
|
28
|
+
"mcp>=1.16.0",
|
|
29
|
+
"colorlog>=6.10.1",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Documentation = "https://visionagents.ai/"
|
|
34
|
+
Website = "https://visionagents.ai/"
|
|
35
|
+
Source = "https://github.com/GetStream/Vision-Agents"
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
dev = ["pytest", "mypy", "ruff", "click"]
|
|
39
|
+
anthropic = ["vision-agents-plugins-anthropic"]
|
|
40
|
+
cartesia = ["vision-agents-plugins-cartesia"]
|
|
41
|
+
deepgram = ["vision-agents-plugins-deepgram"]
|
|
42
|
+
elevenlabs = ["vision-agents-plugins-elevenlabs"]
|
|
43
|
+
gemini = ["vision-agents-plugins-gemini"]
|
|
44
|
+
getstream = ["vision-agents-plugins-getstream"]
|
|
45
|
+
heygen = ["vision-agents-plugins-heygen"]
|
|
46
|
+
inworld = ["vision-agents-plugins-inworld"]
|
|
47
|
+
kokoro = ["vision-agents-plugins-kokoro"]
|
|
48
|
+
moonshine = ["vision-agents-plugins-moonshine"]
|
|
49
|
+
openai = ["vision-agents-plugins-openai"]
|
|
50
|
+
roboflow = ["vision-agents-plugins-roboflow"]
|
|
51
|
+
smart_turn = ["vision-agents-plugins-smart-turn"]
|
|
52
|
+
ultralytics = ["vision-agents-plugins-ultralytics"]
|
|
53
|
+
wizper = ["vision-agents-plugins-wizper"]
|
|
54
|
+
xai = ["vision-agents-plugins-xai"]
|
|
55
|
+
all-plugins = [
|
|
56
|
+
"vision-agents-plugins-anthropic",
|
|
57
|
+
"vision-agents-plugins-cartesia",
|
|
58
|
+
"vision-agents-plugins-deepgram",
|
|
59
|
+
"vision-agents-plugins-elevenlabs",
|
|
60
|
+
"vision-agents-plugins-gemini",
|
|
61
|
+
"vision-agents-plugins-getstream",
|
|
62
|
+
"vision-agents-plugins-heygen",
|
|
63
|
+
"vision-agents-plugins-inworld",
|
|
64
|
+
"vision-agents-plugins-kokoro",
|
|
65
|
+
"vision-agents-plugins-moonshine",
|
|
66
|
+
"vision-agents-plugins-roboflow",
|
|
67
|
+
"vision-agents-plugins-openai",
|
|
68
|
+
"vision-agents-plugins-smart-turn",
|
|
69
|
+
"vision-agents-plugins-ultralytics",
|
|
70
|
+
"vision-agents-plugins-wizper",
|
|
71
|
+
"vision-agents-plugins-xai",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[tool.hatch.metadata]
|
|
75
|
+
allow-direct-references = true
|
|
76
|
+
|
|
77
|
+
[tool.hatch.version]
|
|
78
|
+
source = "vcs"
|
|
79
|
+
raw-options = { root = "..", search_parent_directories = true, fallback_version = "0.0.0" }
|
|
80
|
+
|
|
81
|
+
[tool.hatch.build.targets.wheel]
|
|
82
|
+
packages = ["vision_agents"]
|
|
83
|
+
|
|
84
|
+
[tool.hatch.build.targets.sdist]
|
|
85
|
+
include = ["vision_agents"]
|
|
86
|
+
|
|
87
|
+
#[tool.uv.sources]
|
|
88
|
+
# getstream = { git = "https://github.com/GetStream/stream-py.git", branch = "audio-more" }
|
|
89
|
+
# for local development
|
|
90
|
+
# getstream = { path = "../../stream-py/", editable = true }
|
|
91
|
+
# aiortc = { path = "../stream-py/", editable = true }
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# Protobuf Event Generation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `_generate_sfu_events.py` script automatically generates Python dataclass wrappers for protobuf messages from the SFU (Selective Forwarding Unit) event system. These generated classes inherit from `BaseEvent` and provide type-safe access to protobuf fields with all fields being optional.
|
|
6
|
+
|
|
7
|
+
## Location
|
|
8
|
+
|
|
9
|
+
- **Generator Script**: `agents-core/vision_agents/_generate_sfu_events.py`
|
|
10
|
+
- **Generated Output**: `agents-core/vision_agents/core/edge/sfu_events.py`
|
|
11
|
+
|
|
12
|
+
## Key Features
|
|
13
|
+
|
|
14
|
+
### 1. BaseEvent Inheritance
|
|
15
|
+
|
|
16
|
+
All generated classes inherit from `BaseEvent`, providing:
|
|
17
|
+
- `type`: Event type identifier (auto-set from protobuf full name)
|
|
18
|
+
- `event_id`: Unique identifier (auto-generated UUID)
|
|
19
|
+
- `timestamp`: Event creation time (auto-generated)
|
|
20
|
+
- `session_id`: Optional session identifier
|
|
21
|
+
- `user_metadata`: Optional user metadata
|
|
22
|
+
|
|
23
|
+
### 2. Optional Fields
|
|
24
|
+
|
|
25
|
+
All fields are optional, allowing event creation without a payload:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
event = AudioLevelEvent() # All fields are optional
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 3. Advanced Type Mapping
|
|
32
|
+
|
|
33
|
+
The generator uses `_get_python_type_from_protobuf_field()` to map protobuf types to Python types with **full nested message type resolution**:
|
|
34
|
+
|
|
35
|
+
- Protobuf scalar types → Python primitives (int, float, str, bool, bytes)
|
|
36
|
+
- Protobuf repeated fields → `Optional[List[T]]`
|
|
37
|
+
- **Protobuf message types → Proper typed dataclass wrappers** (e.g., `Optional[Participant]`)
|
|
38
|
+
- Protobuf enum types → `Optional[int]`
|
|
39
|
+
|
|
40
|
+
All types are wrapped in `Optional` for flexibility.
|
|
41
|
+
|
|
42
|
+
#### Message Type Wrappers
|
|
43
|
+
|
|
44
|
+
The generator automatically creates dataclass wrappers for all protobuf message types used in events. These wrappers:
|
|
45
|
+
- Are placed at the top of the generated file
|
|
46
|
+
- Include all fields with proper Python types
|
|
47
|
+
- Support nested message types recursively
|
|
48
|
+
- Provide `from_proto()` class method for conversion
|
|
49
|
+
- Are fully typed for IDE autocomplete and type checking
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
```python
|
|
53
|
+
@dataclass
|
|
54
|
+
class Participant(DataClassJsonMixin):
|
|
55
|
+
"""Wrapper for stream.video.sfu.models.Participant."""
|
|
56
|
+
user_id: Optional[str] = None
|
|
57
|
+
session_id: Optional[str] = None
|
|
58
|
+
name: Optional[str] = None
|
|
59
|
+
is_speaking: Optional[bool] = None
|
|
60
|
+
audio_level: Optional[float] = None
|
|
61
|
+
# ... all other fields
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def from_proto(cls, proto_obj) -> 'Participant':
|
|
65
|
+
"""Create from protobuf Participant."""
|
|
66
|
+
# ... conversion logic
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 4. Property-Based Access
|
|
70
|
+
|
|
71
|
+
Protobuf fields are exposed as properties with proper type hints:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
@property
|
|
75
|
+
def user_id(self) -> Optional[str]:
|
|
76
|
+
"""Access user_id field from the protobuf payload."""
|
|
77
|
+
if self.payload is None:
|
|
78
|
+
return None
|
|
79
|
+
return getattr(self.payload, 'user_id', None)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 5. Protobuf Integration
|
|
83
|
+
|
|
84
|
+
Each generated class provides:
|
|
85
|
+
- `from_proto(proto_obj)`: Create event from protobuf message
|
|
86
|
+
- `as_dict()`: Convert protobuf payload to dictionary
|
|
87
|
+
- `__getattr__()`: Delegate attribute access to protobuf payload
|
|
88
|
+
|
|
89
|
+
## Usage
|
|
90
|
+
|
|
91
|
+
### Regenerating Events
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
cd agents-core
|
|
95
|
+
uv run python vision_agents/_generate_sfu_events.py
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Verification
|
|
99
|
+
|
|
100
|
+
Verify type mappings and generated classes:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Show type mappings
|
|
104
|
+
uv run python vision_agents/_generate_sfu_events.py --verify-types
|
|
105
|
+
|
|
106
|
+
# Verify generated classes
|
|
107
|
+
uv run python vision_agents/_generate_sfu_events.py --verify
|
|
108
|
+
|
|
109
|
+
# Both
|
|
110
|
+
uv run python vision_agents/_generate_sfu_events.py --verify-types --verify
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Example Usage
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from vision_agents.core.edge.sfu_events import (
|
|
117
|
+
AudioLevelEvent,
|
|
118
|
+
TrackUnpublishedEvent,
|
|
119
|
+
Participant # Now properly typed!
|
|
120
|
+
)
|
|
121
|
+
from getstream.video.rtc.pb.stream.video.sfu.event import events_pb2
|
|
122
|
+
from getstream.video.rtc.pb.stream.video.sfu.models import models_pb2
|
|
123
|
+
|
|
124
|
+
# Example 1: Simple event without payload
|
|
125
|
+
event1 = AudioLevelEvent()
|
|
126
|
+
print(event1.user_id) # None
|
|
127
|
+
|
|
128
|
+
# Example 2: Event from protobuf
|
|
129
|
+
proto = events_pb2.AudioLevel(user_id='user123', level=0.85, is_speaking=True)
|
|
130
|
+
event2 = AudioLevelEvent.from_proto(proto)
|
|
131
|
+
print(event2.user_id) # 'user123'
|
|
132
|
+
print(event2.level) # 0.85
|
|
133
|
+
print(event2.is_speaking) # True
|
|
134
|
+
print(event2.as_dict()) # {'user_id': 'user123', 'level': 0.85, 'is_speaking': True}
|
|
135
|
+
|
|
136
|
+
# Example 3: Event with nested message type (Participant)
|
|
137
|
+
proto_participant = models_pb2.Participant(
|
|
138
|
+
user_id='user456',
|
|
139
|
+
name='John Doe',
|
|
140
|
+
is_speaking=True,
|
|
141
|
+
audio_level=0.92
|
|
142
|
+
)
|
|
143
|
+
proto_track = events_pb2.TrackUnpublished(
|
|
144
|
+
user_id='user456',
|
|
145
|
+
participant=proto_participant
|
|
146
|
+
)
|
|
147
|
+
event3 = TrackUnpublishedEvent.from_proto(proto_track)
|
|
148
|
+
|
|
149
|
+
# Participant is properly typed as Participant dataclass!
|
|
150
|
+
participant: Participant = event3.participant # Type-safe!
|
|
151
|
+
print(participant.user_id) # 'user456'
|
|
152
|
+
print(participant.name) # 'John Doe'
|
|
153
|
+
print(participant.is_speaking) # True
|
|
154
|
+
print(participant.audio_level) # 0.92
|
|
155
|
+
|
|
156
|
+
# IDE autocomplete works perfectly for all Participant fields!
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Verification Functions
|
|
160
|
+
|
|
161
|
+
### `_get_python_type_from_protobuf_field(field_descriptor)`
|
|
162
|
+
|
|
163
|
+
Determines the appropriate Python type annotation from a protobuf field descriptor. Maps protobuf types to Python types with proper handling of:
|
|
164
|
+
- Scalar types (int, float, str, bool, bytes)
|
|
165
|
+
- Repeated fields (lists)
|
|
166
|
+
- Message types (nested protobuf messages)
|
|
167
|
+
- Enum types
|
|
168
|
+
|
|
169
|
+
### `verify_field_types()`
|
|
170
|
+
|
|
171
|
+
Displays a comprehensive report of all field type mappings for verification:
|
|
172
|
+
```
|
|
173
|
+
AudioLevelEvent (AudioLevel):
|
|
174
|
+
Protobuf type: stream.video.sfu.event.AudioLevel
|
|
175
|
+
- user_id: type=9 (required) → Optional[str]
|
|
176
|
+
- level: type=2 (required) → Optional[float]
|
|
177
|
+
- is_speaking: type=8 (required) → Optional[bool]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### `verify_generated_classes()`
|
|
181
|
+
|
|
182
|
+
Verifies that generated classes match protobuf definitions by checking:
|
|
183
|
+
- Class exists in generated module
|
|
184
|
+
- All protobuf fields are accessible as properties
|
|
185
|
+
- Properties have correct types
|
|
186
|
+
- No missing or incorrect field mappings
|
|
187
|
+
|
|
188
|
+
## Generated Class Structure
|
|
189
|
+
|
|
190
|
+
Each generated class follows this pattern:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
@dataclass
|
|
194
|
+
class AudioLevelEvent(BaseEvent):
|
|
195
|
+
"""Dataclass event for video.sfu.event.events_pb2.AudioLevel."""
|
|
196
|
+
type: str = field(default="stream.video.sfu.event.AudioLevel", init=False)
|
|
197
|
+
payload: Optional[events_pb2.AudioLevel] = field(default=None, repr=False)
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def user_id(self) -> Optional[str]:
|
|
201
|
+
"""Access user_id field from the protobuf payload."""
|
|
202
|
+
if self.payload is None:
|
|
203
|
+
return None
|
|
204
|
+
return getattr(self.payload, 'user_id', None)
|
|
205
|
+
|
|
206
|
+
# ... more properties ...
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def from_proto(cls, proto_obj: events_pb2.AudioLevel, **extra):
|
|
210
|
+
"""Create event instance from protobuf message."""
|
|
211
|
+
return cls(payload=proto_obj, **extra)
|
|
212
|
+
|
|
213
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
214
|
+
"""Convert protobuf payload to dictionary."""
|
|
215
|
+
if self.payload is None:
|
|
216
|
+
return {}
|
|
217
|
+
return _to_dict(self.payload)
|
|
218
|
+
|
|
219
|
+
def __getattr__(self, item: str):
|
|
220
|
+
"""Delegate attribute access to protobuf payload."""
|
|
221
|
+
if self.payload is not None:
|
|
222
|
+
return getattr(self.payload, item)
|
|
223
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{item}'")
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Import Strategy
|
|
227
|
+
|
|
228
|
+
The edge module uses absolute imports instead of relative imports to avoid naming conflicts with standard library modules (specifically avoiding conflicts with Python's `types` module).
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# In edge/__init__.py
|
|
232
|
+
from vision_agents.core.edge.edge_transport import EdgeTransport
|
|
233
|
+
from vision_agents.core.edge import sfu_events
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Event Manager Integration
|
|
237
|
+
|
|
238
|
+
The EventManager has been updated to seamlessly handle the new protobuf events:
|
|
239
|
+
|
|
240
|
+
### How It Works
|
|
241
|
+
|
|
242
|
+
1. **Register protobuf event classes** like any other event:
|
|
243
|
+
```python
|
|
244
|
+
from vision_agents.core.events.manager import EventManager
|
|
245
|
+
from vision_agents.core.edge.sfu_events import AudioLevelEvent
|
|
246
|
+
|
|
247
|
+
manager = EventManager()
|
|
248
|
+
manager.register(AudioLevelEvent)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
2. **Send events** in three ways:
|
|
252
|
+
- Send wrapped events (already BaseEvent):
|
|
253
|
+
```python
|
|
254
|
+
proto = events_pb2.AudioLevel(user_id='user123', level=0.85)
|
|
255
|
+
event = AudioLevelEvent.from_proto(proto, session_id='session123')
|
|
256
|
+
manager.send(event) # BaseEvent fields preserved
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
- Send raw protobuf messages (auto-wrapped):
|
|
260
|
+
```python
|
|
261
|
+
proto = events_pb2.AudioLevel(user_id='user456', level=0.95)
|
|
262
|
+
manager.send(proto) # Automatically wrapped in AudioLevelEvent
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
- Create events without payload (all fields optional):
|
|
266
|
+
```python
|
|
267
|
+
event = AudioLevelEvent() # No protobuf payload needed
|
|
268
|
+
manager.send(event)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
3. **Subscribe to protobuf events** like any other event:
|
|
272
|
+
```python
|
|
273
|
+
@manager.subscribe
|
|
274
|
+
async def handle_audio(event: AudioLevelEvent):
|
|
275
|
+
print(f"User: {event.user_id}, Level: {event.level}")
|
|
276
|
+
print(f"Session: {event.session_id}, ID: {event.event_id}")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Key Improvements
|
|
280
|
+
|
|
281
|
+
- **No double-wrapping**: Already-wrapped BaseEvent subclasses are not re-wrapped
|
|
282
|
+
- **BaseEvent fields preserved**: session_id, event_id, timestamp all work correctly
|
|
283
|
+
- **Simplified logic**: Single check distinguishes raw protobuf from wrapped events
|
|
284
|
+
- **Type safety**: All generated events properly inherit from BaseEvent
|
|
285
|
+
- **Flexible usage**: Use raw protobuf or wrapped events interchangeably
|
|
286
|
+
|