feat(agent): mine Hangar agent path, ROS singleton, topology docs & probe scripts - #157
Conversation
…docs, and probe scripts from PR #152
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
Warning Review limit reached
Next review available in: 45 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (15)
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 |
| import { useChat } from '@ai-sdk/react'; | ||
| import { | ||
| DefaultChatTransport, | ||
| lastAssistantMessageIsCompleteWithApprovalResponses, | ||
| isToolUIPart, | ||
| getToolName, | ||
| type UIMessage, | ||
| } from 'ai'; |
There was a problem hiding this comment.
Suggestion: The new client imports @ai-sdk/react and ai, but neither package is declared in package.json or the lockfile. A clean install will fail to resolve this module and the agent page cannot build or run; add the required AI SDK dependencies and lockfile entries. [import error]
Severity Level: Critical 🚨
- ❌ Clean-install production builds fail resolving AI SDK imports.
- ❌ `/agent` page cannot compile or run.
- ❌ `/api/agent/chat` cannot compile or run.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/app/agent/AgentClient.tsx
**Line:** 3:10
**Comment:**
*Import Error: The new client imports `@ai-sdk/react` and `ai`, but neither package is declared in `package.json` or the lockfile. A clean install will fail to resolve this module and the agent page cannot build or run; add the required AI SDK dependencies and lockfile entries.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const status = await bridge.getStatus(); | ||
| const gated = gateMotionIntent(status); | ||
| if (gated) return gated; | ||
| return bridge.driveOnHeading(input); |
There was a problem hiding this comment.
Suggestion: The safety check and action dispatch are separate awaited operations, so allowMotion can become false or the bridge can disconnect after getStatus() returns but before driveOnHeading() runs. This allows a motion intent to be sent after the last verified safe state. Make the safety check and dispatch atomic in the bridge, or revalidate the motion lock immediately within the dispatch operation. [race condition]
Severity Level: Major ⚠️
- ⚠️ Approved agent goals can dispatch after motion lock changes.
- ⚠️ Nav2 action state may outlive the verified safety snapshot.
- ⚠️ Robot-side gating limits immediate movement but not stale goals.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/server/beast/tools.ts
**Line:** 46:49
**Comment:**
*Race Condition: The safety check and action dispatch are separate awaited operations, so `allowMotion` can become false or the bridge can disconnect after `getStatus()` returns but before `driveOnHeading()` runs. This allows a motion intent to be sent after the last verified safe state. Make the safety check and dispatch atomic in the bridge, or revalidate the motion lock immediately within the dispatch operation.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| import { | ||
| convertToModelMessages, | ||
| createUIMessageStreamResponse, | ||
| isStepCount, | ||
| streamText, | ||
| toUIMessageStream, | ||
| type UIMessage, | ||
| } from 'ai'; |
There was a problem hiding this comment.
Suggestion: The route now imports the ai package, while the repository's package.json does not declare it. A clean install will fail to resolve this module before the endpoint can run; the new server-side model and ROS modules likewise introduce undeclared @ai-sdk/openai-compatible and roslib imports. Add the required runtime dependencies and lockfile entries. [import error]
Severity Level: Critical 🚨
- ❌ Clean installs cannot build the agent route.
- ❌ `/api/agent/chat` is unavailable.
- ❌ Agent UI requests fail during deployment.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/app/api/agent/chat/route.ts
**Line:** 1:8
**Comment:**
*Import Error: The route now imports the `ai` package, while the repository's `package.json` does not declare it. A clean install will fail to resolve this module before the endpoint can run; the new server-side model and ROS modules likewise introduce undeclared `@ai-sdk/openai-compatible` and `roslib` imports. Add the required runtime dependencies and lockfile entries.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| private onConnection = () => { | ||
| this.state = 'connected'; | ||
| this.lastError = null; | ||
| this.subscribeStatusTopics(); | ||
| this.ensureActions(); | ||
| }; |
There was a problem hiding this comment.
Suggestion: Telemetry values, including allowMotion, are not invalidated when the connection drops or reconnects. A previous allow_motion: true therefore remains cached after reconnect, and motion tools can see a connected bridge and dispatch a goal before the new connection has published fresh safety status. Reset safety telemetry on disconnect or require a fresh status update before allowing motion. [stale reference]
Severity Level: Major ⚠️
- ❌ Motion can be authorized using stale safety telemetry.
- ⚠️ Reconnect status falsely reports motion readiness.
- ⚠️ Safety state is not invalidated on bridge loss.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/server/beast/ros-singleton.ts
**Line:** 138:143
**Comment:**
*Stale Reference: Telemetry values, including `allowMotion`, are not invalidated when the connection drops or reconnects. A previous `allow_motion: true` therefore remains cached after reconnect, and motion tools can see a connected bridge and dispatch a goal before the new connection has published fresh safety status. Reset safety telemetry on disconnect or require a fresh status update before allowing motion.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| } | ||
| if (this.ros?.isConnected) { | ||
| this.state = 'connected'; | ||
| return; | ||
| } | ||
| await this.ensureRoslib(); | ||
| this.openSocket(); | ||
| } |
There was a problem hiding this comment.
Suggestion: start() has no in-flight or connecting guard. Concurrent callers can both await ensureRoslib() and then call openSocket(), causing the second call to close and replace the socket created by the first while both callers still observe the same connection lifecycle. Serialize startup or return an existing connection promise when a connection attempt is already underway. [race condition]
Severity Level: Major ⚠️
- ⚠️ Concurrent agent requests replace active ROS sockets.
- ❌ Initial status or motion operations may race connection setup.
- ⚠️ Reconnect listeners can be detached unexpectedly.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/server/beast/ros-singleton.ts
**Line:** 191:198
**Comment:**
*Race Condition: `start()` has no in-flight or connecting guard. Concurrent callers can both await `ensureRoslib()` and then call `openSocket()`, causing the second call to close and replace the socket created by the first while both callers still observe the same connection lifecycle. Serialize startup or return an existing connection promise when a connection attempt is already underway.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (this.ros) { | ||
| this.detachRosListeners(this.ros); | ||
| try { | ||
| this.ros.close(); | ||
| } catch { | ||
| /* ignore */ | ||
| } | ||
| this.ros = null; | ||
| } |
There was a problem hiding this comment.
Suggestion: Reconnects retain the existing actions entries, so ensureActions() does not create clients bound to the newly opened ROS connection. After the first disconnect, motion and cancellation calls continue using action handles constructed with the closed Ros instance and can fail or send nothing. Clear this.actions when replacing the ROS socket, before creating the new action clients. [stale reference]
Severity Level: Major ⚠️
- ❌ Motion commands can fail after bridge recovery.
- ❌ Stop cancellation can target closed action clients.
- ⚠️ Recovered status may mask unusable action handles.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** src/server/beast/ros-singleton.ts
**Line:** 329:337
**Comment:**
*Stale Reference: Reconnects retain the existing `actions` entries, so `ensureActions()` does not create clients bound to the newly opened ROS connection. After the first disconnect, motion and cancellation calls continue using action handles constructed with the closed Ros instance and can fail or send nothing. Clear `this.actions` when replacing the ROS socket, before creating the new action clients.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fixThere was a problem hiding this comment.
Pull request overview
Adds an operator-facing Hangar /agent chat surface and the supporting server-side BEAST ROS bridge/tooling so the planner can read status, request bounded motion intents, and require human approval before dispatching motion over rosbridge.
Changes:
- Introduces a server-side BEAST agent stack (model/env config, system prompt, Zod tool schemas, motion gate, and a process-wide rosbridge singleton implementing
BeastRobotBridge). - Adds the
/agentUI and streaming/api/agent/chatroute, plus Shell navigation to the new surface. - Adds unit tests covering model env gating, tool approval/motion refusal, and ros singleton lifecycle.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/server/beast/types.ts | Adds shared BEAST status/tool/result types plus bounded motion constants. |
| src/server/beast/schemas.ts | Defines Zod schemas enforcing conservative motion limits (distance/speed/spin). |
| src/server/beast/motion-gate.ts | Implements UX-level refusal of motion intents unless allow_motion is explicitly true. |
| src/server/beast/tools.ts | Defines AI SDK tools (get_status, stop, motion tools) and approval metadata. |
| src/server/beast/ros-singleton.ts | Adds server-side rosbridge client singleton with topic subscriptions and nav2 action dispatch. |
| src/server/beast/model.ts | Reads planner model env and creates an OpenAI-compatible chat model provider. |
| src/server/beast/prompts.ts | Adds a BEAST operator system prompt emphasizing honesty and gating. |
| src/app/api/agent/chat/route.ts | Implements streaming agent chat route that wires model + tools + ros singleton. |
| src/app/agent/page.tsx | Adds server-rendered /agent page that passes configuration/degraded flags to the client. |
| src/app/agent/AgentClient.tsx | Adds client chat UI with tool rendering and approve/deny controls for motion intents. |
| src/components/Shell.tsx | Adds /agent to the main navigation. |
| src/tests/agent-model.test.ts | Tests env gating for agent enablement and planner config. |
| src/tests/agent-tools.test.ts | Tests tool schemas, approval metadata, and motion gating behavior. |
| src/tests/ros-singleton.test.ts | Tests ros singleton lifecycle, status ingestion, and action dispatch refusal/dispatch. |
| docs/beast-control-topology.md | Adds documentation describing BEAST control authority/topology and related references. |
Suppressed comments (2)
docs/beast-control-topology.md:14
- This section states
ugv_wsis outside RobotOverview and points to a separateColdaine/ugv_wsfork/worktrees, but the repo’s own AGENTS.md and docs/plans/2026-08-02-control-plane-architecture.md describe the robot brain as living underrobot/beast/ros2_wsin this monorepo. As written, the rest of this doc (tables/diagrams/“never” section) will mislead readers about where robot code lives and how it is synced.
**`ugv_ws` is not inside RobotOverview.** Opening this Hangar folder will never show
the robot brain source tree. Two sibling clones on the Windows PC, one GitHub fork,
one checkout on the Jetson:
docs/beast-control-topology.md:198
- These “Related” bullets link to plan/pointer files that don’t exist in the repository (
2026-08-02-beast-agent-architecture.md,2026-08-02-beast-immobile-execution.md, andbeast-cockpit-future-roadmap.md). Replace them with links to the existing plans so readers don’t hit 404s.
- Master plan + PR sets: [`docs/plans/2026-08-02-beast-agent-architecture.md`](plans/2026-08-02-beast-agent-architecture.md)
- Immobile session work order: [`docs/plans/2026-08-02-beast-immobile-execution.md`](plans/2026-08-02-beast-immobile-execution.md)
- Advanced cockpit idea bank (not a live plan): Datacore
[`/datacore/briefing/beast-cockpit-future-roadmap`](/datacore/briefing/beast-cockpit-future-roadmap)
· thin pointer [`docs/beast-cockpit-future-roadmap.md`](beast-cockpit-future-roadmap.md)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return { | ||
| ...status, | ||
| motionGated: status.allowMotion !== true, | ||
| lockReason: statusLockReason(status), | ||
| }; |
| export async function POST(req: Request) { | ||
| if (!isHangarAgentEnabled()) { | ||
| return Response.json( |
| function durationFromSeconds(seconds: number): { sec: number; nanosec: number } { | ||
| const sec = Math.floor(seconds); | ||
| const nanosec = Math.round((seconds - sec) * 1e9); | ||
| return { sec, nanosec }; | ||
| } |
| Stable map of how Hangar (this repo) and the robot brain (`ugv_ws`) share authority | ||
| over BEAST-01. Architecture decisions live in the | ||
| [master plan](plans/2026-08-02-beast-agent-architecture.md). **Volatile live facts** | ||
| (SSH paths, pack voltage, boot args, HEAD SHAs, bridge presence) live only in |
…estop, globs authored - Agent path merged on main: ros-singleton + motion-gate both anchor on /ugv/allow_motion - Main's cockpit estop is a one-shot volatile publish (no heartbeat) — the silent-failure pattern - rosbridge globs already authored; Phase 0.4 is verification, not authoring - beast-cockpit.service unit + cutover mechanics documented on main - PR #152 mined by #157: close it
* chore(agent): de-ship Hangar agent surface to unblock clean build The agent surface from PR #157 imports ai, @ai-sdk/react, @ai-sdk/openai-compatible, and roslib, but those packages were never declared in package.json. That breaks npm run check and the clean image build with missing-module errors. Agent work is out of scope for the cockpit-parity plan, which is the human-driven command deck. Remove the agent web surface, server modules, and their tests while keeping the mined docs and probe tooling. The cockpit remains unaffected because it uses a raw WebSocket client. * ci(image): publish to MooseGooseConsulting GHCR namespace after org move The repo migrated from the Coldaine namespace to the MooseGooseConsulting organization; the old ghcr.io/coldaine/robot-overview package path no longer authorizes the repo's GITHUB_TOKEN (permission_denied: installation does not exist), which was failing the image build+push on every PR. * ci: re-trigger required checks after org move --------- Co-authored-by: AI Assistant <ai@example.com>
The agent surface (PR #157) imports ai, @ai-sdk/react, @ai-sdk/openai-compatible, and roslib, but those packages were never declared in package.json. That broke npm run check and the clean image build with missing-module errors, which the de-ship PR #161 worked around by deleting the agent. Restore the agent surface instead and declare the four missing deps (versions from 1c7b75b): ai ^7.0.48, @ai-sdk/react ^4.0.51, @ai-sdk/openai-compatible ^3.0.20, roslib ^2.1.0. Clean npm ci + full npm run check (lint, typecheck, vitest, next build) now passes. Co-authored-by: AI Assistant <ai@example.com>
User description
Mines the Hangar /agent UI, server-side ROS singleton, agent tools, unit tests, control topology docs, PowerShell probes, and UPS wiring assets from PR #152 into main.
CodeAnt-AI Description
Add a safety-gated Hangar agent for BEAST-01 robot commands
What Changed
allow_motionis explicitly enabled.Impact
✅ Human approval before robot motion✅ Fewer unsafe or unverifiable motion commands✅ Clearer bridge, planner, and safety-lock status💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.