Skip to content

feat(agent): mine Hangar agent path, ROS singleton, topology docs & probe scripts - #157

Merged
Coldaine merged 1 commit into
mainfrom
feat/mine-beast-agent-path
Aug 3, 2026
Merged

feat(agent): mine Hangar agent path, ROS singleton, topology docs & probe scripts#157
Coldaine merged 1 commit into
mainfrom
feat/mine-beast-agent-path

Conversation

@Coldaine

@Coldaine Coldaine commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

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

  • Adds an Agent page and navigation entry where operators can chat with a planner and view robot status.
  • Supports status checks, stop commands, and approved drive, spin, and reverse actions through the robot bridge.
  • Motion commands require operator approval, validate safe limits, and refuse to run unless the bridge is connected and allow_motion is explicitly enabled.
  • Shows clear disabled or degraded states when the agent, planner, or robot bridge is not configured.
  • Connects to ROS status topics, reports watchdog, voltage, scan, and motion-lock state, and retries after bridge disconnects.
  • Adds tests for configuration, connection recovery, telemetry, command gating, and tool validation, plus documentation of the control and safety topology.

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:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

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:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

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.

Copilot AI review requested due to automatic review settings August 3, 2026 07:53
@codeant-ai

codeant-ai Bot commented Aug 3, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 139b259 Aug 03, 2026 · 07:53 07:57

@codeant-ai

codeant-ai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Coldaine, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: be029b1b-eb51-46e9-b064-8a7cdaae2fee

📥 Commits

Reviewing files that changed from the base of the PR and between 60fc95d and 139b259.

⛔ Files ignored due to path filters (1)
  • BeastUPSElectricalDiagram.pdf is excluded by !**/*.pdf
📒 Files selected for processing (15)
  • docs/beast-control-topology.md
  • src/__tests__/agent-model.test.ts
  • src/__tests__/agent-tools.test.ts
  • src/__tests__/ros-singleton.test.ts
  • src/app/agent/AgentClient.tsx
  • src/app/agent/page.tsx
  • src/app/api/agent/chat/route.ts
  • src/components/Shell.tsx
  • src/server/beast/model.ts
  • src/server/beast/motion-gate.ts
  • src/server/beast/prompts.ts
  • src/server/beast/ros-singleton.ts
  • src/server/beast/schemas.ts
  • src/server/beast/tools.ts
  • src/server/beast/types.ts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 3, 2026
Comment on lines +3 to +10
import { useChat } from '@ai-sdk/react';
import {
DefaultChatTransport,
lastAssistantMessageIsCompleteWithApprovalResponses,
isToolUIPart,
getToolName,
type UIMessage,
} from 'ai';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in VSCode Claude

(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
👍 | 👎

Comment thread src/server/beast/tools.ts
Comment on lines +46 to +49
const status = await bridge.getStatus();
const gated = gateMotionIntent(status);
if (gated) return gated;
return bridge.driveOnHeading(input);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in VSCode Claude

(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
👍 | 👎

Comment on lines +1 to +8
import {
convertToModelMessages,
createUIMessageStreamResponse,
isStepCount,
streamText,
toUIMessageStream,
type UIMessage,
} from 'ai';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in VSCode Claude

(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
👍 | 👎

Comment on lines +138 to +143
private onConnection = () => {
this.state = 'connected';
this.lastError = null;
this.subscribeStatusTopics();
this.ensureActions();
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in VSCode Claude

(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
👍 | 👎

Comment on lines +191 to +198
}
if (this.ros?.isConnected) {
this.state = 'connected';
return;
}
await this.ensureRoslib();
this.openSocket();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in VSCode Claude

(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
👍 | 👎

Comment on lines +329 to +337
if (this.ros) {
this.detachRosListeners(this.ros);
try {
this.ros.close();
} catch {
/* ignore */
}
this.ros = null;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in VSCode Claude

(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 fix
👍 | 👎

@Coldaine
Coldaine merged commit 87062a7 into main Aug 3, 2026
3 of 5 checks passed
@Coldaine
Coldaine deleted the feat/mine-beast-agent-path branch August 3, 2026 07:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 /agent UI and streaming /api/agent/chat route, 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_ws is outside RobotOverview and points to a separate Coldaine/ugv_ws fork/worktrees, but the repo’s own AGENTS.md and docs/plans/2026-08-02-control-plane-architecture.md describe the robot brain as living under robot/beast/ros2_ws in 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, and beast-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.

Comment thread src/server/beast/tools.ts
Comment on lines +25 to +29
return {
...status,
motionGated: status.allowMotion !== true,
lockReason: statusLockReason(status),
};
Comment on lines +21 to +23
export async function POST(req: Request) {
if (!isHangarAgentEnabled()) {
return Response.json(
Comment on lines +101 to +105
function durationFromSeconds(seconds: number): { sec: number; nanosec: number } {
const sec = Math.floor(seconds);
const nanosec = Math.round((seconds - sec) * 1e9);
return { sec, nanosec };
}
Comment on lines +3 to +6
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
Coldaine pushed a commit that referenced this pull request Aug 3, 2026
…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
Coldaine added a commit that referenced this pull request Aug 3, 2026
* 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>
Coldaine added a commit that referenced this pull request Aug 3, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants