feat: Cricket DRS AI — Real-time Third Umpire using Gemini Live + YOLO#379
feat: Cricket DRS AI — Real-time Third Umpire using Gemini Live + YOLO#379jaya6400 wants to merge 15 commits intoGetStream:mainfrom
Conversation
- cricket_umpire.py: Main agent using Gemini Live + YOLO pose detection - cricket_umpire.md: Third umpire instructions (run out, stumping, catch, boundary) - pyproject.toml: Project dependencies - README.md: Setup and usage documentation
- Fixed YOLOPoseProcessor import and model name - Added keepalive loop (every 20s) to prevent Gemini disconnecting - Added separate token_server.py on port 8001 for frontend auth - Agent continuously watches video and announces decisions"
- Built React frontend with Stream Video SDK - Cricket-branded dark UI (Third Umpire AI branding) - 5 scenario buttons: Run Out, Stumping, Catch, Boundary, LBW - Decision log panel showing AI verdicts in real-time - Screen share, camera, mic controls - YOLO Pose Detection active badge - Token fetched from token_server.py on port 8001"
- Simplified to LBW and Run Out only (DRS-focused) - Removed YOLO processor to fix AudioQueue buffer overflow - Added Text-to-Speech for spoken verdict on decision - Removed fake setTimeout, replaced with DRS-accurate decisions - Updated cricket_umpire.md with voice-trigger instructions - Fixed run.sh to use correct script directory paths - Cleaned up App.css to match two-panel layout - Removed screen share audio to prevent WebRTC track timeout
- Re-added YOLOPoseProcessor at imgsz=256 (down from 320/1080p) - Reduced Gemini fps to 2 to reduce processing load - Root cause of AudioQueue overflow was SCREEN_SHARE_AUDIO track - Fix: uncheck 'Share tab audio' in Chrome screen share dialog - YOLO now runs without timeout at 256px resolution on CPU
- Added FastAPI server on port 8002 to receive review triggers - Button click now calls POST /review/lbw or /review/runout - Triggers agent.llm.simple_response() with analysis prompt - Gemini watches live screen share and speaks real verdict - YOLO pose detection running at imgsz=256 without timeouts - Added requirements.txt for Python dependencies - Verified: real DECISION/REVIEW TYPE/REASON/CONFIDENCE from Gemini
📝 WalkthroughWalkthroughIntroduces a complete Cricket DRS example application featuring a decision-review system for women's cricket. Includes a Python backend with an AI umpire agent using Gemini Realtime and YOLO pose detection, a token server, a FastAPI review endpoint, and a React + Vite frontend UI for managing review scenarios and displaying verdicts. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (12)
examples/09_cricket_umpire/pyproject.toml (1)
14-14: Non-standard build backend specified.
setuptools.backends.legacy:buildis atypical. The standard backend issetuptools.build_meta.🛠️ Proposed fix
-build-backend = "setuptools.backends.legacy:build" +build-backend = "setuptools.build_meta"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/pyproject.toml` at line 14, The pyproject specifies a non-standard build backend via build-backend = "setuptools.backends.legacy:build"; replace this with the standard setuptools backend by setting build-backend to "setuptools.build_meta" (update the build-backend entry in pyproject.toml to use setuptools.build_meta) so the project uses the supported build backend.examples/09_cricket_umpire/README.md (1)
109-120: Consider adding language identifiers to fenced code blocks.Markdown linters recommend specifying a language (e.g.,
textorplaintext) for code blocks to improve rendering consistency.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/README.md` around lines 109 - 120, Update the fenced code block in examples/09_cricket_umpire/README.md (the directory tree block showing cricket_umpire.py, cricket_umpire.md, token_server.py, run.sh, requirements.txt, and frontend/src/App.jsx/App.css) to include a language identifier such as "text" or "plaintext" (i.e., replace the opening ``` with ```text) so Markdown linters/renderers correctly treat the block as plain text.examples/09_cricket_umpire/frontend/eslint.config.js (1)
16-24: RedundantecmaVersionsettings.
ecmaVersionis set to2020at line 17 and'latest'at line 20. TheparserOptions.ecmaVersionwill override the outer setting. Consider keeping only one.🛠️ Proposed fix
languageOptions: { - ecmaVersion: 2020, globals: globals.browser, parserOptions: { ecmaVersion: 'latest',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/frontend/eslint.config.js` around lines 16 - 24, Remove the redundant ecmaVersion by keeping a single definitive setting: either delete the outer languageOptions.ecmaVersion or remove parserOptions.ecmaVersion so only one ecmaVersion remains; locate the languageOptions block and the nested parserOptions (symbols: languageOptions, parserOptions, ecmaVersion) and ensure the chosen ecmaVersion is the one in parserOptions if you expect parser-specific behavior (or keep the outer one and remove the nested override).examples/09_cricket_umpire/frontend/README.md (1)
1-16: Consider customizing this README for the Cricket DRS frontend.This appears to be the default Vite template README. Consider replacing or augmenting it with project-specific documentation covering the DRS UI components, Stream Video SDK integration, and how to trigger reviews.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/frontend/README.md` around lines 1 - 16, The README.md in the frontend currently contains the default Vite template text; replace or augment it with Cricket DRS-specific documentation: update README.md to describe the DRS UI (key components like UmpireReviewPanel, BallEventList, DecisionModal), explain how to set up and run the frontend dev server, list Stream Video SDK integration steps and required environment variables, and document how to trigger and test reviews (manual steps and any API endpoints or mock data used). Ensure the new README includes a quick start, development commands, testing instructions, and links to relevant source files and components so contributors can quickly run and exercise the DRS review flow.examples/09_cricket_umpire/token_server.py (1)
27-37: Consider adding return type annotations and a brief docstring.Functions lack return type hints and docstrings per coding guidelines.
🛠️ Proposed fix
`@app.get`("/token") -async def get_token(user_id: str): +async def get_token(user_id: str) -> JSONResponse: + """Generate a Stream token for the given user_id.""" try:`@app.get`("/health") -async def health(): +async def health() -> dict[str, str]: + """Health check endpoint.""" return {"status": "ok"}As per coding guidelines: "Use modern type annotation syntax everywhere" and "Use Google style docstrings."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/token_server.py` around lines 27 - 37, Add a Google-style docstring and explicit return type annotation to the FastAPI handler get_token: document the user_id parameter and that the function returns a fastapi.responses.JSONResponse containing either token and user_id or an error; annotate the function signature as async def get_token(user_id: str) -> JSONResponse. Reference the existing get_token function and the use of StreamClient.create_token so the docstring briefly explains that it creates a Stream token for the given user_id and returns a JSONResponse with {"token": token, "user_id": user_id} or an error payload on exception.examples/09_cricket_umpire/cricket_umpire.py (4)
34-43: Add a brief Google-style docstring tojoin_call.Same as above—document the function purpose.
📝 Proposed fix
async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None: + """Join a call with the agent and announce readiness.""" global active_agentAs per coding guidelines: "Use Google style docstrings and keep them short."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/cricket_umpire.py` around lines 34 - 43, Add a short Google-style docstring to the async function join_call describing its purpose, parameters, and return type; place it immediately below the def line in cricket_umpire.py and mention that it sets the global active_agent, creates and joins a call via Agent.create_call/Agent.join, sends a simple_response, and finishes the agent; include param entries for agent (Agent), call_type (str), call_id (str), and **kwargs, plus a Returns: None line.
18-31: Add a brief Google-style docstring tocreate_agent.Per guidelines, functions should have docstrings following Google style. A short summary suffices.
📝 Proposed fix
async def create_agent(**kwargs) -> Agent: + """Create a Cricket DRS Third Umpire agent with Gemini and YOLO processors.""" agent = Agent(As per coding guidelines: "Use Google style docstrings and keep them short."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/cricket_umpire.py` around lines 18 - 31, Add a short Google-style docstring to the create_agent function that briefly describes its purpose (e.g., constructs and returns an Agent configured for the Third Umpire DRS with edge, user, instructions, LLM, and processors), mention the return type (Agent), and place it immediately below the async def create_agent(**kwargs) signature; ensure it is concise (one or two lines) and follows Google docstring format (summary line plus "Returns:" section).
53-65: Add a brief docstring totrigger_reviewand consider returning a proper error status code.Currently, when no agent is connected, the endpoint returns a 200 with
{"error": "Agent not connected"}. A 503 or 400 would be more semantically correct.♻️ Proposed fix
+from fastapi import FastAPI, HTTPException + `@review_app.post`("/review/{review_type}") async def trigger_review(review_type: str): + """Trigger an LBW or Run Out review analysis via the active agent.""" global active_agent if active_agent is None: - return {"error": "Agent not connected"} + raise HTTPException(status_code=503, detail="Agent not connected")🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/cricket_umpire.py` around lines 53 - 65, Add a short docstring to the endpoint function trigger_review explaining its purpose and parameters, and change the error path so it returns a proper HTTP status instead of a 200 JSON error; e.g., raise FastAPI's HTTPException(status_code=503, detail="Agent not connected") or return a Response with status_code=503 when active_agent is None, while keeping the rest of the logic unchanged.
1-12: Movethreadinganduvicornimports to the top of the module.The coding guidelines specify that local imports should be avoided—imports belong at the module level. Currently
threadinganduvicornare imported inside__main__(lines 69-70).♻️ Proposed fix
import asyncio import logging +import threading from contextlib import asynccontextmanager from dotenv import load_dotenv from fastapi import FastAPI +import uvicorn from vision_agents.core import Agent, Runner, User from vision_agents.core.agents import AgentLauncher from vision_agents.plugins import gemini, getstream, ultralyticsThen remove the local imports in
__main__:if __name__ == "__main__": - import threading - import uvicorn - def run_api():As per coding guidelines: "Do not use local imports; import at the top of the module."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/cricket_umpire.py` around lines 1 - 12, The threading and uvicorn imports currently done inside the __main__ block should be moved to module-level imports at the top of the file; add "import threading" and "import uvicorn" alongside the existing imports and remove the local imports inside the if __name__ == '__main__': section so that no local imports remain (look for the local usage in the __main__ block and any calls to threading or uvicorn.run to verify behavior after moving).examples/09_cricket_umpire/frontend/src/App.css (1)
1-1: Consider using string notation for the font import.Stylelint prefers string notation over
url()for@importstatements.📝 Proposed fix
-@import url('https://fonts.googleapis.com/css2?family=Oswald:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500&family=Source+Sans+3:wght@400;500;600&display=swap'); +@import 'https://fonts.googleapis.com/css2?family=Oswald:wght@400;600;700&family=IBM+Plex+Mono:wght@400;500&family=Source+Sans+3:wght@400;500;600&display=swap';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/frontend/src/App.css` at line 1, The `@import` line in App.css uses url(...) which Stylelint flags; replace the url(...) form with string notation by changing the `@import` to use a quoted string (keeping the same Google Fonts URL and query parameters) so the rule uses `@import` 'https://fonts.googleapis.com/…' instead of `@import` url(...), ensuring the font families (Oswald, IBM Plex Mono, Source Sans 3) and display parameter remain unchanged.examples/09_cricket_umpire/frontend/src/App.jsx (1)
13-16: Consider externalizing backend URLs to environment variables.The hardcoded
localhost:8001andlocalhost:8002URLs (lines 59, 194) will break outside local development. Extract these toimport.meta.envvariables for flexibility.♻️ Proposed fix
const API_KEY = import.meta.env.VITE_STREAM_API_KEY; +const TOKEN_SERVER_URL = import.meta.env.VITE_TOKEN_SERVER_URL || "http://localhost:8001"; +const REVIEW_API_URL = import.meta.env.VITE_REVIEW_API_URL || "http://localhost:8002"; const CALL_TYPE = "default";Then update usages:
- await fetch("http://localhost:8002/review/" + scenario.id, { method: "POST" }); + await fetch(`${REVIEW_API_URL}/review/${scenario.id}`, { method: "POST" });- const res = await fetch("http://localhost:8001/token?user_id=" + USER.id); + const res = await fetch(`${TOKEN_SERVER_URL}/token?user_id=${USER.id}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/frontend/src/App.jsx` around lines 13 - 16, Replace the hardcoded backend URLs with environment variables accessed via import.meta.env (e.g. add VITE_BACKEND_URL and VITE_SIGNALING_URL constants and fall back to "http://localhost:8001" / "http://localhost:8002" for local dev); update every usage of the literal "localhost:8001" and "localhost:8002" (the fetch/connection calls in the App where the backend and signaling endpoints are constructed) to use these new constants so the app works outside local development. Ensure the new env vars are referenced where CALL_ID / API_KEY are defined and used so all endpoint construction uses the env-driven base URLs.examples/09_cricket_umpire/frontend/index.html (1)
5-7: Update the page title and verify the favicon exists.The generic title "frontend" should reflect the application purpose. Also ensure
/vite.svgis present in thepublic/folder or update the href.📝 Proposed fix
- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> + <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <!-- or use a cricket emoji favicon --> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>frontend</title> + <title>Cricket DRS AI</title>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/09_cricket_umpire/frontend/index.html` around lines 5 - 7, Update the generic <title> element to a descriptive app name (replace "frontend" in the <title> tag with something like "Cricket Umpire" or the actual app name) and verify the favicon href (currently href="/vite.svg" on the <link rel="icon">) points to an existing file in your public assets; if the file is missing, either add vite.svg to the public/ folder or update the href to the correct favicon path (e.g., /favicon.svg or /assets/favicon.ico) so the icon resolves.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/09_cricket_umpire/cricket_umpire.py`:
- Around line 14-15: The global active_agent variable creates a race condition
when concurrent HTTP requests (e.g., /review/{review_type}) call join_call and
set/clear active_agent; protect access by introducing an asyncio.Lock (e.g.,
agent_lock) and acquire it around all places that read or write active_agent
(including join_call and any HTTP handler functions that inspect or mutate
active_agent) so modifications are serialized; ensure the lock is awaited (async
with agent_lock:) wherever active_agent is mutated or checked to prevent
interleaving and clear/reset operations from racing.
- Around line 68-80: The current pattern starts uvicorn in a daemon thread
(run_api -> uvicorn.run) and logs the server as running immediately, which can
hide startup errors; modify run_api to wrap uvicorn.run in a try/except that
logs any exception via logger.error and sets a threading.Event on success,
create a threading.Event (e.g., server_started_event) before starting
api_thread, start the thread non-daemon (api_thread = threading.Thread(...,
daemon=False)) or keep daemon but wait on the event, and only call logger.info
after the event is set (or perform a short health-check loop against
http://localhost:8002 to confirm the server is listening) so startup failures
are caught and reported before launching AgentLauncher/Runner.
In `@examples/09_cricket_umpire/frontend/src/App.jsx`:
- Around line 211-218: The disconnect function can throw from call.leave() or
client.disconnectUser(); wrap the await calls inside a try/catch and handle
errors (e.g., log them) to prevent unhandled rejections, and move state cleanup
(setCall(null), setClient(null), setStatus("idle"), setLastDecision(null)) into
a finally block so state is reset regardless of errors; update the disconnect
function and reference the existing call.leave(), client.disconnectUser(),
setCall, setClient, setStatus and setLastDecision identifiers.
- Around line 49-74: sendScenario currently starts a timeout that may run after
unmount and it also swallows fetch failures while still showing the fallback
decision; update sendScenario to store the timeout id (and any in-flight fetch
controller) in a ref, only schedule the fallback decision if the POST succeeded,
and in the catch branch push an error message to the transcript and clear
sending instead of showing the fallback decision; also add a cleanup useEffect
that clears the timeout and aborts the request on unmount to avoid setState
after unmount. Ensure you modify the logic around fetch, setTimeout,
setTranscript, setSending and call onDecision only when appropriate.
In `@examples/09_cricket_umpire/pyproject.toml`:
- Line 5: The pyproject.toml's requires-python = ">=3.12" conflicts with the
README's "Python 3.10+"; update one to match the other so they are
consistent—either change pyproject.toml's requires-python to ">=3.10" or update
the README to state "Python 3.12+"; edit the requires-python key in
pyproject.toml (and/or the Python version text in README.md) so both files
reference the same minimum Python version.
In `@examples/09_cricket_umpire/README.md`:
- Around line 13-16: Update the table link text to be descriptive for
accessibility: replace the generic "Link" label for the Frontend entry with a
descriptive phrase such as "Live demo" or the full URL (e.g., "Live demo —
ai-drs-vision-agents-sdk") and update the Backend entry text from "Runs locally
(see setup below)" to something like "Local backend (see setup below)" so screen
readers convey the destination; edit the README table row entries where the
Frontend and Backend link texts appear.
In `@examples/09_cricket_umpire/requirements.txt`:
- Around line 102-103: The requirements file currently lists Windows-only
packages pywin32 and pywin32-ctypes which will break installs on non-Windows
systems; update the requirements to conditionally install these packages using
environment markers (e.g., append a sys_platform marker like ; sys_platform ==
"win32" to the pywin32 and pywin32-ctypes entries) or move them into a
Windows-specific extras entry and/or add a README note documenting the platform
limitation so non-Windows users don’t attempt to install them unconditionally.
- Around line 136-139: Update the git dependency URLs in requirements.txt to
point to the official GetStream repository and use POSIX path separators;
specifically replace occurrences of
"git+https://github.com/jaya6400/Vision-Agents.git@..." with
"git+https://github.com/GetStream/Vision-Agents.git@..." and change any
backslashes in subdirectory fragments (e.g., "plugins\gemini" or
"plugins\ultralytics") to forward slashes ("plugins/gemini",
"plugins/ultralytics"), keeping the same `#egg` names (vision_agents,
vision_agents_plugins_gemini, vision_agents_plugins_getstream,
vision_agents_plugins_ultralytics) so pip can resolve the editable git
subpackages correctly.
In `@examples/09_cricket_umpire/run.sh`:
- Around line 6-7: The script sets SCRIPT_DIR and then runs cd "$SCRIPT_DIR"
without checking for failure; change the cd invocation (the line using
SCRIPT_DIR and the cd command) to guard against failure by testing its exit
status and aborting (or returning a non-zero exit) with an error message if cd
fails (e.g., use a conditional or "|| exit 1" style) so the script never
continues in the wrong working directory.
- Around line 28-31: The trap and directory change need two small fixes: quote
the trap body to make intent explicit (e.g., use single quotes so the kill
command is not expanded at trap definition: trap 'kill "$TOKEN_PID" "$AGENT_PID"
2>/dev/null' EXIT) and guard the cd frontend by failing early if it cannot
change directories (e.g., change the cd frontend line in run.sh to cd frontend
|| exit 1 or similar error handling) so npm run dev is not executed in the wrong
directory; update references to TOKEN_PID and AGENT_PID in the trap as shown.
In `@examples/09_cricket_umpire/token_server.py`:
- Around line 18-24: The CORS setup in app.add_middleware using CORSMiddleware
currently sets allow_origins=["*"] together with allow_credentials=True which is
insecure and blocked by browsers; update the CORSMiddleware configuration in
token_server.py (the app.add_middleware call) to either set
allow_credentials=False or replace the wildcard origin with an explicit list
(e.g., "http://localhost:3000" or your frontend URL) — alternatively use
allow_origin_regex to match trusted origins — and ensure
allow_methods/allow_headers remain as intended.
- Around line 36-37: Replace the bare except in token_server.py that currently
returns JSONResponse({"error": str(e)}, status_code=500) with explicit exception
handlers: catch KeyError for missing environment variables and return a
JSONResponse with a clear message and 400/500 as appropriate, and catch the
SDK-specific error type used by the token creation call (import and reference
the actual SDK exception class instead of a generic name) to return a
JSONResponse with that error and a 500 status; keep a final generic fallback
only if you re-raise or log it, and ensure you still use JSONResponse for the
handled cases (reference: JSONResponse and the existing except block).
---
Nitpick comments:
In `@examples/09_cricket_umpire/cricket_umpire.py`:
- Around line 34-43: Add a short Google-style docstring to the async function
join_call describing its purpose, parameters, and return type; place it
immediately below the def line in cricket_umpire.py and mention that it sets the
global active_agent, creates and joins a call via Agent.create_call/Agent.join,
sends a simple_response, and finishes the agent; include param entries for agent
(Agent), call_type (str), call_id (str), and **kwargs, plus a Returns: None
line.
- Around line 18-31: Add a short Google-style docstring to the create_agent
function that briefly describes its purpose (e.g., constructs and returns an
Agent configured for the Third Umpire DRS with edge, user, instructions, LLM,
and processors), mention the return type (Agent), and place it immediately below
the async def create_agent(**kwargs) signature; ensure it is concise (one or two
lines) and follows Google docstring format (summary line plus "Returns:"
section).
- Around line 53-65: Add a short docstring to the endpoint function
trigger_review explaining its purpose and parameters, and change the error path
so it returns a proper HTTP status instead of a 200 JSON error; e.g., raise
FastAPI's HTTPException(status_code=503, detail="Agent not connected") or return
a Response with status_code=503 when active_agent is None, while keeping the
rest of the logic unchanged.
- Around line 1-12: The threading and uvicorn imports currently done inside the
__main__ block should be moved to module-level imports at the top of the file;
add "import threading" and "import uvicorn" alongside the existing imports and
remove the local imports inside the if __name__ == '__main__': section so that
no local imports remain (look for the local usage in the __main__ block and any
calls to threading or uvicorn.run to verify behavior after moving).
In `@examples/09_cricket_umpire/frontend/eslint.config.js`:
- Around line 16-24: Remove the redundant ecmaVersion by keeping a single
definitive setting: either delete the outer languageOptions.ecmaVersion or
remove parserOptions.ecmaVersion so only one ecmaVersion remains; locate the
languageOptions block and the nested parserOptions (symbols: languageOptions,
parserOptions, ecmaVersion) and ensure the chosen ecmaVersion is the one in
parserOptions if you expect parser-specific behavior (or keep the outer one and
remove the nested override).
In `@examples/09_cricket_umpire/frontend/index.html`:
- Around line 5-7: Update the generic <title> element to a descriptive app name
(replace "frontend" in the <title> tag with something like "Cricket Umpire" or
the actual app name) and verify the favicon href (currently href="/vite.svg" on
the <link rel="icon">) points to an existing file in your public assets; if the
file is missing, either add vite.svg to the public/ folder or update the href to
the correct favicon path (e.g., /favicon.svg or /assets/favicon.ico) so the icon
resolves.
In `@examples/09_cricket_umpire/frontend/README.md`:
- Around line 1-16: The README.md in the frontend currently contains the default
Vite template text; replace or augment it with Cricket DRS-specific
documentation: update README.md to describe the DRS UI (key components like
UmpireReviewPanel, BallEventList, DecisionModal), explain how to set up and run
the frontend dev server, list Stream Video SDK integration steps and required
environment variables, and document how to trigger and test reviews (manual
steps and any API endpoints or mock data used). Ensure the new README includes a
quick start, development commands, testing instructions, and links to relevant
source files and components so contributors can quickly run and exercise the DRS
review flow.
In `@examples/09_cricket_umpire/frontend/src/App.css`:
- Line 1: The `@import` line in App.css uses url(...) which Stylelint flags;
replace the url(...) form with string notation by changing the `@import` to use a
quoted string (keeping the same Google Fonts URL and query parameters) so the
rule uses `@import` 'https://fonts.googleapis.com/…' instead of `@import` url(...),
ensuring the font families (Oswald, IBM Plex Mono, Source Sans 3) and display
parameter remain unchanged.
In `@examples/09_cricket_umpire/frontend/src/App.jsx`:
- Around line 13-16: Replace the hardcoded backend URLs with environment
variables accessed via import.meta.env (e.g. add VITE_BACKEND_URL and
VITE_SIGNALING_URL constants and fall back to "http://localhost:8001" /
"http://localhost:8002" for local dev); update every usage of the literal
"localhost:8001" and "localhost:8002" (the fetch/connection calls in the App
where the backend and signaling endpoints are constructed) to use these new
constants so the app works outside local development. Ensure the new env vars
are referenced where CALL_ID / API_KEY are defined and used so all endpoint
construction uses the env-driven base URLs.
In `@examples/09_cricket_umpire/pyproject.toml`:
- Line 14: The pyproject specifies a non-standard build backend via
build-backend = "setuptools.backends.legacy:build"; replace this with the
standard setuptools backend by setting build-backend to "setuptools.build_meta"
(update the build-backend entry in pyproject.toml to use setuptools.build_meta)
so the project uses the supported build backend.
In `@examples/09_cricket_umpire/README.md`:
- Around line 109-120: Update the fenced code block in
examples/09_cricket_umpire/README.md (the directory tree block showing
cricket_umpire.py, cricket_umpire.md, token_server.py, run.sh, requirements.txt,
and frontend/src/App.jsx/App.css) to include a language identifier such as
"text" or "plaintext" (i.e., replace the opening ``` with ```text) so Markdown
linters/renderers correctly treat the block as plain text.
In `@examples/09_cricket_umpire/token_server.py`:
- Around line 27-37: Add a Google-style docstring and explicit return type
annotation to the FastAPI handler get_token: document the user_id parameter and
that the function returns a fastapi.responses.JSONResponse containing either
token and user_id or an error; annotate the function signature as async def
get_token(user_id: str) -> JSONResponse. Reference the existing get_token
function and the use of StreamClient.create_token so the docstring briefly
explains that it creates a Stream token for the given user_id and returns a
JSONResponse with {"token": token, "user_id": user_id} or an error payload on
exception.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (9)
examples/09_cricket_umpire/docs/screenshots/bash.PNGis excluded by!**/*.pngexamples/09_cricket_umpire/docs/screenshots/frontend.PNGis excluded by!**/*.pngexamples/09_cricket_umpire/docs/screenshots/realtime-voice-agent.PNGis excluded by!**/*.pngexamples/09_cricket_umpire/docs/screenshots/stream-ui.PNGis excluded by!**/*.pngexamples/09_cricket_umpire/docs/videos/lbw.mp4is excluded by!**/*.mp4examples/09_cricket_umpire/docs/videos/ro.mp4is excluded by!**/*.mp4examples/09_cricket_umpire/frontend/package-lock.jsonis excluded by!**/package-lock.jsonexamples/09_cricket_umpire/frontend/public/vite.svgis excluded by!**/*.svgexamples/09_cricket_umpire/frontend/src/assets/react.svgis excluded by!**/*.svg
📒 Files selected for processing (17)
examples/09_cricket_umpire/README.mdexamples/09_cricket_umpire/cricket_umpire.mdexamples/09_cricket_umpire/cricket_umpire.pyexamples/09_cricket_umpire/frontend/.gitignoreexamples/09_cricket_umpire/frontend/README.mdexamples/09_cricket_umpire/frontend/eslint.config.jsexamples/09_cricket_umpire/frontend/index.htmlexamples/09_cricket_umpire/frontend/package.jsonexamples/09_cricket_umpire/frontend/src/App.cssexamples/09_cricket_umpire/frontend/src/App.jsxexamples/09_cricket_umpire/frontend/src/index.cssexamples/09_cricket_umpire/frontend/src/main.jsxexamples/09_cricket_umpire/frontend/vite.config.jsexamples/09_cricket_umpire/pyproject.tomlexamples/09_cricket_umpire/requirements.txtexamples/09_cricket_umpire/run.shexamples/09_cricket_umpire/token_server.py
| if __name__ == "__main__": | ||
| import threading | ||
| import uvicorn | ||
|
|
||
| def run_api(): | ||
| uvicorn.run(review_app, host="0.0.0.0", port=8002, log_level="warning") | ||
|
|
||
| api_thread = threading.Thread(target=run_api, daemon=True) | ||
| api_thread.start() | ||
| logger.info("🌐 Review API running on http://localhost:8002") | ||
|
|
||
| launcher = AgentLauncher(create_agent=create_agent, join_call=join_call) | ||
| Runner(launcher=launcher).cli() No newline at end of file |
There was a problem hiding this comment.
Running uvicorn in a daemon thread may swallow startup errors silently.
If uvicorn.run() fails (port conflict, etc.), the daemon thread dies without feedback. The logger.info on line 77 fires immediately after start(), not after the server is actually listening. Consider adding a brief health-check or catching startup failures.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/cricket_umpire.py` around lines 68 - 80, The
current pattern starts uvicorn in a daemon thread (run_api -> uvicorn.run) and
logs the server as running immediately, which can hide startup errors; modify
run_api to wrap uvicorn.run in a try/except that logs any exception via
logger.error and sets a threading.Event on success, create a threading.Event
(e.g., server_started_event) before starting api_thread, start the thread
non-daemon (api_thread = threading.Thread(..., daemon=False)) or keep daemon but
wait on the event, and only call logger.info after the event is set (or perform
a short health-check loop against http://localhost:8002 to confirm the server is
listening) so startup failures are caught and reported before launching
AgentLauncher/Runner.
| const sendScenario = async (scenario) => { | ||
| setSending(scenario.id); | ||
| setTranscript((prev) => [...prev, { | ||
| id: Date.now(), role: "viewer", | ||
| text: scenario.label, | ||
| time: new Date().toLocaleTimeString() | ||
| }]); | ||
|
|
||
| // Trigger real Gemini analysis via backend HTTP endpoint | ||
| try { | ||
| await fetch("http://localhost:8002/review/" + scenario.id, { method: "POST" }); | ||
| } catch (e) { | ||
| console.error("Review trigger failed:", e); | ||
| } | ||
|
|
||
| // Show fallback decision after agent has time to analyze | ||
| setTimeout(() => { | ||
| setTranscript((prev) => [...prev, { | ||
| id: Date.now() + 1, role: "umpire", | ||
| text: scenario.decision, | ||
| time: new Date().toLocaleTimeString() | ||
| }]); | ||
| onDecision?.(scenario.decision); | ||
| setSending(null); | ||
| }, 6000); | ||
| }; |
There was a problem hiding this comment.
Potential state update after unmount; review trigger failure not surfaced to user.
The setTimeout callback (line 65) may fire after the component unmounts, causing a React warning. Additionally, the catch block silently logs the error but still shows the fallback decision—user sees success when the backend call actually failed.
🛡️ Proposed fix
+ import { useState, useEffect, useRef, useCallback } from "react";
...
const [sending, setSending] = useState(null);
+ const [reviewError, setReviewError] = useState(null);
const transcriptRef = useRef(null);
+ const timeoutRef = useRef(null);
+
+ useEffect(() => {
+ return () => {
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
+ };
+ }, []);
const sendScenario = async (scenario) => {
setSending(scenario.id);
+ setReviewError(null);
setTranscript((prev) => [...prev, {
id: Date.now(), role: "viewer",
text: scenario.label,
time: new Date().toLocaleTimeString()
}]);
try {
- await fetch("http://localhost:8002/review/" + scenario.id, { method: "POST" });
+ const res = await fetch("http://localhost:8002/review/" + scenario.id, { method: "POST" });
+ if (!res.ok) throw new Error("Review request failed");
} catch (e) {
console.error("Review trigger failed:", e);
+ setReviewError("Review trigger failed");
}
- setTimeout(() => {
+ timeoutRef.current = setTimeout(() => {
setTranscript((prev) => [...prev, {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/frontend/src/App.jsx` around lines 49 - 74,
sendScenario currently starts a timeout that may run after unmount and it also
swallows fetch failures while still showing the fallback decision; update
sendScenario to store the timeout id (and any in-flight fetch controller) in a
ref, only schedule the fallback decision if the POST succeeded, and in the catch
branch push an error message to the transcript and clear sending instead of
showing the fallback decision; also add a cleanup useEffect that clears the
timeout and aborts the request on unmount to avoid setState after unmount.
Ensure you modify the logic around fetch, setTimeout, setTranscript, setSending
and call onDecision only when appropriate.
| const disconnect = async () => { | ||
| if (call) await call.leave(); | ||
| if (client) await client.disconnectUser(); | ||
| setCall(null); | ||
| setClient(null); | ||
| setStatus("idle"); | ||
| setLastDecision(null); | ||
| }; |
There was a problem hiding this comment.
Add error handling to disconnect.
Both call.leave() and client.disconnectUser() can throw. Wrap in try/catch to avoid unhandled rejections.
🛡️ Proposed fix
const disconnect = async () => {
- if (call) await call.leave();
- if (client) await client.disconnectUser();
+ try {
+ if (call) await call.leave();
+ if (client) await client.disconnectUser();
+ } catch (err) {
+ console.error("Disconnect error:", err);
+ }
setCall(null);
setClient(null);
setStatus("idle");
setLastDecision(null);
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const disconnect = async () => { | |
| if (call) await call.leave(); | |
| if (client) await client.disconnectUser(); | |
| setCall(null); | |
| setClient(null); | |
| setStatus("idle"); | |
| setLastDecision(null); | |
| }; | |
| const disconnect = async () => { | |
| try { | |
| if (call) await call.leave(); | |
| if (client) await client.disconnectUser(); | |
| } catch (err) { | |
| console.error("Disconnect error:", err); | |
| } | |
| setCall(null); | |
| setClient(null); | |
| setStatus("idle"); | |
| setLastDecision(null); | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/frontend/src/App.jsx` around lines 211 - 218, The
disconnect function can throw from call.leave() or client.disconnectUser(); wrap
the await calls inside a try/catch and handle errors (e.g., log them) to prevent
unhandled rejections, and move state cleanup (setCall(null), setClient(null),
setStatus("idle"), setLastDecision(null)) into a finally block so state is reset
regardless of errors; update the disconnect function and reference the existing
call.leave(), client.disconnectUser(), setCall, setClient, setStatus and
setLastDecision identifiers.
| name = "cricket-umpire" | ||
| version = "0.1.0" | ||
| description = "AI-powered Third Umpire agent for real-time women's cricket decision making" | ||
| requires-python = ">=3.12" |
There was a problem hiding this comment.
Python version requirement conflicts with README documentation.
The pyproject.toml requires Python >=3.12, but the README states "Python 3.10+". Align these to avoid confusion.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/pyproject.toml` at line 5, The pyproject.toml's
requires-python = ">=3.12" conflicts with the README's "Python 3.10+"; update
one to match the other so they are consistent—either change pyproject.toml's
requires-python to ">=3.10" or update the README to state "Python 3.12+"; edit
the requires-python key in pyproject.toml (and/or the Python version text in
README.md) so both files reference the same minimum Python version.
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents&subdirectory=agents-core | ||
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_gemini&subdirectory=plugins\gemini | ||
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_getstream&subdirectory=plugins\getstream | ||
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_ultralytics&subdirectory=plugins\ultralytics |
There was a problem hiding this comment.
Git dependencies point to a personal fork and use Windows-only path separators.
These editable installs reference jaya6400/Vision-Agents rather than GetStream/Vision-Agents. Additionally, lines 137-138 use backslashes (plugins\gemini) which will fail on Unix/macOS systems.
🛠️ Proposed fix
--e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents&subdirectory=agents-core
--e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_gemini&subdirectory=plugins\gemini
--e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_getstream&subdirectory=plugins\getstream
--e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_ultralytics&subdirectory=plugins\ultralytics
+-e git+https://github.com/GetStream/Vision-Agents.git#egg=vision_agents&subdirectory=agents-core
+-e git+https://github.com/GetStream/Vision-Agents.git#egg=vision_agents_plugins_gemini&subdirectory=plugins/gemini
+-e git+https://github.com/GetStream/Vision-Agents.git#egg=vision_agents_plugins_getstream&subdirectory=plugins/getstream
+-e git+https://github.com/GetStream/Vision-Agents.git#egg=vision_agents_plugins_ultralytics&subdirectory=plugins/ultralytics🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/requirements.txt` around lines 136 - 139, Update
the git dependency URLs in requirements.txt to point to the official GetStream
repository and use POSIX path separators; specifically replace occurrences of
"git+https://github.com/jaya6400/Vision-Agents.git@..." with
"git+https://github.com/GetStream/Vision-Agents.git@..." and change any
backslashes in subdirectory fragments (e.g., "plugins\gemini" or
"plugins\ultralytics") to forward slashes ("plugins/gemini",
"plugins/ultralytics"), keeping the same `#egg` names (vision_agents,
vision_agents_plugins_gemini, vision_agents_plugins_getstream,
vision_agents_plugins_ultralytics) so pip can resolve the editable git
subpackages correctly.
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| cd "$SCRIPT_DIR" |
There was a problem hiding this comment.
Guard cd commands against failure.
If cd fails, the script continues with unexpected working directory—potentially running commands in the wrong location.
🛡️ Proposed fix
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
-cd "$SCRIPT_DIR"
+cd "$SCRIPT_DIR" || exit 1📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| cd "$SCRIPT_DIR" | |
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| cd "$SCRIPT_DIR" || exit 1 |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 7-7: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.
(SC2164)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/run.sh` around lines 6 - 7, The script sets
SCRIPT_DIR and then runs cd "$SCRIPT_DIR" without checking for failure; change
the cd invocation (the line using SCRIPT_DIR and the cd command) to guard
against failure by testing its exit status and aborting (or returning a non-zero
exit) with an error message if cd fails (e.g., use a conditional or "|| exit 1"
style) so the script never continues in the wrong working directory.
| trap "kill $TOKEN_PID $AGENT_PID 2>/dev/null" EXIT | ||
|
|
||
| cd frontend | ||
| npm run dev No newline at end of file |
There was a problem hiding this comment.
Guard the second cd and consider trap quoting.
The cd frontend should also handle failure. Shellcheck also flags the trap expansion—while the current behavior (capturing PIDs at definition time) is intentional here, explicit quoting makes intent clearer.
🛡️ Proposed fix
-trap "kill $TOKEN_PID $AGENT_PID 2>/dev/null" EXIT
+trap 'kill '"$TOKEN_PID"' '"$AGENT_PID"' 2>/dev/null' EXIT
-cd frontend
+cd frontend || exit 1
npm run devAlternatively, if you want expansion at trap-set time (as currently intended), you can silence the warning with a comment or keep as-is—it functions correctly for this use case.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| trap "kill $TOKEN_PID $AGENT_PID 2>/dev/null" EXIT | |
| cd frontend | |
| npm run dev | |
| trap 'kill '"$TOKEN_PID"' '"$AGENT_PID"' 2>/dev/null' EXIT | |
| cd frontend || exit 1 | |
| npm run dev |
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 28-28: Use single quotes, otherwise this expands now rather than when signalled.
(SC2064)
[warning] 28-28: Use single quotes, otherwise this expands now rather than when signalled.
(SC2064)
[warning] 30-30: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.
(SC2164)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/run.sh` around lines 28 - 31, The trap and
directory change need two small fixes: quote the trap body to make intent
explicit (e.g., use single quotes so the kill command is not expanded at trap
definition: trap 'kill "$TOKEN_PID" "$AGENT_PID" 2>/dev/null' EXIT) and guard
the cd frontend by failing early if it cannot change directories (e.g., change
the cd frontend line in run.sh to cd frontend || exit 1 or similar error
handling) so npm run dev is not executed in the wrong directory; update
references to TOKEN_PID and AGENT_PID in the trap as shown.
| app.add_middleware( | ||
| CORSMiddleware, | ||
| allow_origins=["*"], | ||
| allow_credentials=True, | ||
| allow_methods=["*"], | ||
| allow_headers=["*"], | ||
| ) |
There was a problem hiding this comment.
CORS configuration allows credentials with wildcard origin—a security risk.
Setting allow_origins=["*"] with allow_credentials=True is insecure. Browsers block this combination, and it signals overly permissive intent. For local development, specify the frontend origin explicitly.
🛠️ Proposed fix
app.add_middleware(
CORSMiddleware,
- allow_origins=["*"],
+ allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/token_server.py` around lines 18 - 24, The CORS
setup in app.add_middleware using CORSMiddleware currently sets
allow_origins=["*"] together with allow_credentials=True which is insecure and
blocked by browsers; update the CORSMiddleware configuration in token_server.py
(the app.add_middleware call) to either set allow_credentials=False or replace
the wildcard origin with an explicit list (e.g., "http://localhost:3000" or your
frontend URL) — alternatively use allow_origin_regex to match trusted origins —
and ensure allow_methods/allow_headers remain as intended.
| except Exception as e: | ||
| return JSONResponse({"error": str(e)}, status_code=500) |
There was a problem hiding this comment.
Avoid catching bare Exception; catch specific exceptions instead.
Per coding guidelines, except Exception as e should be replaced with specific exception handling. The likely exceptions here are KeyError (missing env vars) and SDK-specific errors.
🛠️ Proposed fix
`@app.get`("/token")
-async def get_token(user_id: str):
+async def get_token(user_id: str) -> JSONResponse:
+ """Generate a Stream token for the given user_id."""
try:
client = StreamClient(
api_key=os.environ["STREAM_API_KEY"],
api_secret=os.environ["STREAM_API_SECRET"],
)
token = client.create_token(user_id)
return JSONResponse({"token": token, "user_id": user_id})
- except Exception as e:
- return JSONResponse({"error": str(e)}, status_code=500)
+ except KeyError as e:
+ return JSONResponse({"error": f"Missing environment variable: {e}"}, status_code=500)As per coding guidelines: "Never write except Exception as e; catch specific exceptions instead."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/09_cricket_umpire/token_server.py` around lines 36 - 37, Replace the
bare except in token_server.py that currently returns JSONResponse({"error":
str(e)}, status_code=500) with explicit exception handlers: catch KeyError for
missing environment variables and return a JSONResponse with a clear message and
400/500 as appropriate, and catch the SDK-specific error type used by the token
creation call (import and reference the actual SDK exception class instead of a
generic name) to return a JSONResponse with that error and a 500 status; keep a
final generic fallback only if you re-raise or log it, and ensure you still use
JSONResponse for the handled cases (reference: JSONResponse and the existing
except block).
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Free Tier Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| logger.info("🌐 Review API running on http://localhost:8002") | ||
|
|
||
| launcher = AgentLauncher(create_agent=create_agent, join_call=join_call) | ||
| Runner(launcher=launcher).cli() No newline at end of file |
There was a problem hiding this comment.
Cross-event-loop async call causes runtime failure
High Severity
The review_app runs in a separate thread via uvicorn.run(), which creates its own asyncio event loop. The trigger_review endpoint awaits active_agent.llm.simple_response(text=prompt), but the agent's Gemini AsyncSession (a WebSocket connection) was created in the main thread's event loop. Awaiting this cross-loop async operation will fail because the underlying WebSocket transport is bound to the main loop. The fix is to use asyncio.run_coroutine_threadsafe() to schedule the coroutine on the main event loop, or run the review API within the same event loop.
Additional Locations (1)
| prompt = "The on-field umpire has referred a Run Out decision. Analyze what you can see in the current video feed. Check: 1) Was the bat grounded before the stumps were broken? 2) Was any part of the body behind the crease? Give your verdict in the required format: DECISION / REVIEW TYPE / REASON / CONFIDENCE" | ||
|
|
||
| await active_agent.llm.simple_response(text=prompt) | ||
| return {"status": "review triggered"} |
There was a problem hiding this comment.
Missing CORS middleware on review API endpoint
Medium Severity
The review_app FastAPI instance lacks CORS middleware, but the frontend at localhost:5173 makes cross-origin fetch POST requests to localhost:8002. The browser will block the response due to missing Access-Control-Allow-Origin headers, causing the fetch promise to reject and the catch block to fire on every review trigger. Contrast this with token_server.py, which correctly adds CORSMiddleware.
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents&subdirectory=agents-core | ||
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_gemini&subdirectory=plugins\gemini | ||
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_getstream&subdirectory=plugins\getstream | ||
| -e git+https://github.com/jaya6400/Vision-Agents.git@d20061faf73877b11d0efa87b67f55b996d71b15#egg=vision_agents_plugins_ultralytics&subdirectory=plugins\ultralytics |
There was a problem hiding this comment.
Windows backslash paths break installs on Linux/macOS
Medium Severity
The -e git+ entries use Windows-style backslashes in the subdirectory parameter (e.g., subdirectory=plugins\gemini). On Linux/macOS, \ is not a path separator, so pip treats plugins\gemini as a literal single directory name which doesn't exist, causing installation to fail. The project's run.sh is a bash script targeting Unix, confirming Linux/macOS is a target platform. These paths need forward slashes (plugins/gemini) to work cross-platform.
| <div className="last-decision"> | ||
| {lastDecision.includes("NOT OUT") ? "🟢 NOT OUT" : lastDecision.includes("OUT") ? "🔴 OUT" : "⚪ REVIEW"} | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
Decision badge never displays OUT or NOT OUT
Low Severity
The header decision badge checks lastDecision for "NOT OUT" and "OUT" substrings, but lastDecision is only ever set via onDecision(scenario.decision), and scenario.decision is hardcoded to "Awaiting Third Umpire verdict..." for all scenarios. This string contains neither substring, so the badge always shows "⚪ REVIEW" — the "🟢 NOT OUT" and "🔴 OUT" branches are unreachable dead code.
Additional Locations (1)
|
Hi Vision Agents team 👋 |


AI-powered Third Umpire that reduces DRS review time from minutes to seconds using Gemini Live vision, YOLO pose detection,
and Stream's Voice Agents SDK.
What's added
examples/09_cricket_umpire/— full working exampleDemo
Watch Here
Blog
Medium link
Note
Medium Risk
Adds a full new runnable example (backend agent, FastAPI endpoints, token server, and React UI) plus large dependency lockfiles; main risk is integration/runtime issues from WebRTC/Gemini websocket requirements and new service credentials handling.
Overview
Adds a new
examples/09_cricket_umpireend-to-end demo: a Vision AgentsAgentwired to Gemini Live (2fps) plusYOLOPoseProcessor(256px) to deliver LBW/Run Out decisions via voice.Introduces a lightweight FastAPI review trigger service (
POST /review/{review_type}) that prompts the active agent, a separate FastAPI token server for Stream JWTs (/token), and a one-commandrun.shto start token server, agent, and the Vite-based React UI.Includes comprehensive documentation/instructions (
README.md,cricket_umpire.md) and pins Python/Node dependencies (newrequirements.txt,pyproject.toml, and frontendpackage-lock.json).Written by Cursor Bugbot for commit c35a7a7. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Documentation