Skip to content

fix(a2a): route message/send to Ava instead of protoBot (#471)#3548

Merged
mabry1985 merged 1 commit intodevfrom
fix/a2a-messagesend-on-avaproto-labsai-routes-to-8sg399r
Apr 21, 2026
Merged

fix(a2a): route message/send to Ava instead of protoBot (#471)#3548
mabry1985 merged 1 commit intodevfrom
fix/a2a-messagesend-on-avaproto-labsai-routes-to-8sg399r

Conversation

@mabry1985
Copy link
Copy Markdown
Contributor

@mabry1985 mabry1985 commented Apr 21, 2026

Summary

  • Root cause: buildAgentCard() advertised http://automaker-server:3008/a2a (Docker internal hostname) — unreachable by Workstacean externally. Workstacean fell back to agents.yaml, where Ava only had one skill (onboard_project), so bare message/send requests fell through to protoBot.
  • agents.yaml: Added all 10 DECLARED_SKILLS to Ava's fallback entry (chat, sitrep, manage_feature, auto_mode, board_health, bug_triage, onboard_project, provision_discord, plan, plan_resume) so the fallback table matches the live agent card.
  • buildAgentCard(): Default protocol is now 'https' in production so Tailscale/HOSTNAME-derived URLs are externally routable. Added logger.warn when the resolved URL is localhost.
  • docker-compose.staging.yml: Exposed PUBLIC_CALLBACK_URL env var so operators can set https://ava.proto-labs.ai without rebuilding the image.

Deployment note

After deploying, set PUBLIC_CALLBACK_URL=https://ava.proto-labs.ai in the staging .env (or Docker env). This overrides any Tailscale/hostname heuristic and ensures the agent card always advertises the correct public URL. The localhost warning in logs will confirm if this is missing.

Test plan

  • Deploy staging with PUBLIC_CALLBACK_URL=https://ava.proto-labs.ai
  • curl https://ava.proto-labs.ai/.well-known/agent.json — verify url field is https://ava.proto-labs.ai/a2a
  • Repro curl from issue feat(api): antagonistic review flow Express endpoints #471: curl -X POST https://ava.proto-labs.ai/a2a -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"message/send","params":{"message":{"parts":[{"text":"ping"}]}}}' — verify response identifies as Ava, not protoBot
  • Verify no localhost warning appears in server logs after deployment with PUBLIC_CALLBACK_URL set

Closes #471. Unblocks protoVoice F7.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Registered 9 new skills: chat, sitrep, manage_feature, auto_mode, board_health, bug_triage, provision_discord, plan, and plan_resume with A2A and Discord DM triggering support.
  • Improvements

    • Enhanced callback URL handling with automatic HTTPS/HTTP protocol selection based on environment.
    • Added diagnostic logging to identify configuration issues affecting external peer connectivity.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

Configuration updates to the AVA agent with nine new skills (chat, sitrep, manage_feature, auto_mode, board_health, bug_triage, provision_discord, plan, plan_resume), environment-aware callback URL protocol selection (https in production, http otherwise), and PUBLIC_CALLBACK_URL environment variable support for external A2A peer routing.

Changes

Cohort / File(s) Summary
AVA Agent Skills Configuration
agents.yaml
Added 9 new skills entries to agents.ava.skills with A2A and Discord DM triggers; included API key environment variable and callback URL configuration guidance comments.
Callback URL Protocol Resolution
apps/server/src/routes/a2a/index.ts
Updated buildAgentCard() to dynamically select protocol based on NODE_ENV (https in production, http otherwise) and pass protocol to resolveCallbackUrl; added warning log for localhost/127.0.0.1 callback URLs.
Environment Variable Configuration
docker-compose.staging.yml
Added PUBLIC_CALLBACK_URL environment variable to the server service with empty string default for external A2A agent card advertising.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • protoLabsAI/protoContent#4 — The addition of 9 agent skills entries and the callback URL resolution fixes directly address issues with empty agent card skills arrays and incorrect A2A peer callback routing.

Poem

🐰 Nine skills now bloom where once was bare,
The AVA agent hops with care!
Callbacks dance in https delight,
Production-safe and staging-bright. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title references routing message/send to Ava, but the actual changes focus on A2A callback URL configuration, agent card protocol handling, and Ava skill registration—not message routing implementation. Update title to reflect the actual changes, such as 'fix(a2a): configure external callback URL and register Ava skills for A2A agent card' or similar.
Linked Issues check ⚠️ Warning The linked issue #471 requires antagonistic review flow Express endpoints (/api/flows/antagonistic-review/execute and /resume), but the PR changes only address A2A callback URL configuration and agent skill registration with no antagonistic review flow implementation. Implement the antagonistic review flow endpoints specified in issue #471 or verify the correct issue is linked to this PR.
Out of Scope Changes check ⚠️ Warning All changes (agents.yaml skill registration, A2A callback URL handling, docker-compose environment variable) are out of scope relative to issue #471 which requires antagonistic review flow API endpoints. Either link this PR to appropriate A2A infrastructure issues or add the required antagonistic review flow endpoint implementations.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/a2a-messagesend-on-avaproto-labsai-routes-to-8sg399r

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

…labs.ai

Root cause: Workstacean couldn't reach the live agent card because the
card URL advertised http://automaker-server:3008/a2a (Docker internal
hostname). It fell back to agents.yaml where Ava only had one skill
(onboard_project), so bare "chat" message/sends fell through to protoBot.

Three-part fix:
1. agents.yaml — add all 10 DECLARED_SKILLS (chat, sitrep, manage_feature,
   auto_mode, board_health, bug_triage, onboard_project, provision_discord,
   plan, plan_resume) to Ava's entry so the fallback table is correct.
2. buildAgentCard() — use protocol:'https' in production so the card URL
   is externally routable; add logger.warn when resolved URL is localhost.
3. docker-compose.staging.yml — expose PUBLIC_CALLBACK_URL env var so
   operators can set https://ava.proto-labs.ai without rebuilding the image.

Closes #471. Unblocks protoVoice F7 (Ava A2A delegate).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mabry1985 mabry1985 force-pushed the fix/a2a-messagesend-on-avaproto-labsai-routes-to-8sg399r branch from e358534 to 8977528 Compare April 21, 2026 17:17
@mabry1985 mabry1985 enabled auto-merge (squash) April 21, 2026 17:17
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/server/src/routes/a2a/index.ts (1)

241-242: Replace hardcoded host example in runtime warning.

Use a generic placeholder (or config-derived value) instead of embedding https://ava.proto-labs.ai in business-logic logging text.

Proposed tweak
-        'Set PUBLIC_CALLBACK_URL to an externally-routable URL (e.g. https://ava.proto-labs.ai).'
+        'Set PUBLIC_CALLBACK_URL to an externally-routable URL (e.g. https://your-public-host).'

As per coding guidelines: "Never hardcode workflow-specific values (file paths, branch names, CI check names, channel IDs, hosting providers) in business logic — these must come from settings or configuration files."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/routes/a2a/index.ts` around lines 241 - 242, The runtime
warning string contains a hardcoded example URL ("https://ava.proto-labs.ai");
replace that literal with a config-driven value or a generic placeholder and
interpolate it into the message instead of embedding it. Read the external
callback value (e.g. process.env.PUBLIC_CALLBACK_URL or your app config entry
PUBLIC_CALLBACK_URL) and fall back to a neutral placeholder like
"https://your-public-callback-url.example" if not set, then update the
log/emission that currently contains the "A2A agent card URL resolved to
localhost..." text to use the interpolated value in place of the hardcoded URL.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/server/src/routes/a2a/index.ts`:
- Line 238: The code unconditionally passes port into resolveCallbackUrl,
causing resolveCallbackUrl({ port, protocol }) to append a port even when
PUBLIC_CALLBACK_URL is explicitly set; change the call to only include port when
PUBLIC_CALLBACK_URL is not configured (e.g., call resolveCallbackUrl({ protocol
}) or omit the port argument if process.env.PUBLIC_CALLBACK_URL is truthy), and
adjust any logic that builds callbackBase to prefer the explicit
PUBLIC_CALLBACK_URL raw value without modification; also update the related
warning log (the hardcoded example URL) to avoid embedding a provider-specific
URL—use the actual configured PUBLIC_CALLBACK_URL or a generic placeholder in
the log message.

---

Nitpick comments:
In `@apps/server/src/routes/a2a/index.ts`:
- Around line 241-242: The runtime warning string contains a hardcoded example
URL ("https://ava.proto-labs.ai"); replace that literal with a config-driven
value or a generic placeholder and interpolate it into the message instead of
embedding it. Read the external callback value (e.g.
process.env.PUBLIC_CALLBACK_URL or your app config entry PUBLIC_CALLBACK_URL)
and fall back to a neutral placeholder like
"https://your-public-callback-url.example" if not set, then update the
log/emission that currently contains the "A2A agent card URL resolved to
localhost..." text to use the interpolated value in place of the hardcoded URL.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3c3d4abc-1102-4b24-b71b-a45e419d549e

📥 Commits

Reviewing files that changed from the base of the PR and between 0c36166 and 8977528.

📒 Files selected for processing (3)
  • agents.yaml
  • apps/server/src/routes/a2a/index.ts
  • docker-compose.staging.yml

// correct scheme); otherwise we default to https in production.
const isProduction = process.env['NODE_ENV'] === 'production';
const protocol = isProduction ? 'https' : 'http';
const callbackBase = resolveCallbackUrl({ port, protocol });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Verify call site in buildAgentCard:"
sed -n '222,246p' apps/server/src/routes/a2a/index.ts

echo
echo "2) Verify resolver behavior for explicitPublicUrl + port:"
fd "callback-url.ts" libs --exec sed -n '161,229p' {}

Repository: protoLabsAI/protoMaker

Length of output: 4222


Do not unconditionally pass PORT to resolveCallbackUrl() when PUBLIC_CALLBACK_URL is explicitly configured.

When PUBLIC_CALLBACK_URL is set (e.g., https://ava.proto-labs.ai), the resolver appends the port suffix if the explicit URL has no port. This results in advertising an incorrect external URL like https://ava.proto-labs.ai:3008 instead of the configured public endpoint.

Proposed fix
-  const callbackBase = resolveCallbackUrl({ port, protocol });
+  const publicCallbackUrl = process.env['PUBLIC_CALLBACK_URL']?.trim();
+  const callbackBase = publicCallbackUrl
+    ? resolveCallbackUrl({ publicCallbackUrl, protocol })
+    : resolveCallbackUrl({ port, protocol });

Additionally, the warning log message hardcodes https://ava.proto-labs.ai as an example—hosting provider URLs should not be hardcoded in runtime messages.

📝 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.

Suggested change
const callbackBase = resolveCallbackUrl({ port, protocol });
const publicCallbackUrl = process.env['PUBLIC_CALLBACK_URL']?.trim();
const callbackBase = publicCallbackUrl
? resolveCallbackUrl({ publicCallbackUrl, protocol })
: resolveCallbackUrl({ port, protocol });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/routes/a2a/index.ts` at line 238, The code unconditionally
passes port into resolveCallbackUrl, causing resolveCallbackUrl({ port, protocol
}) to append a port even when PUBLIC_CALLBACK_URL is explicitly set; change the
call to only include port when PUBLIC_CALLBACK_URL is not configured (e.g., call
resolveCallbackUrl({ protocol }) or omit the port argument if
process.env.PUBLIC_CALLBACK_URL is truthy), and adjust any logic that builds
callbackBase to prefer the explicit PUBLIC_CALLBACK_URL raw value without
modification; also update the related warning log (the hardcoded example URL) to
avoid embedding a provider-specific URL—use the actual configured
PUBLIC_CALLBACK_URL or a generic placeholder in the log message.

@mabry1985 mabry1985 merged commit d282ff0 into dev Apr 21, 2026
5 of 6 checks passed
@mabry1985 mabry1985 deleted the fix/a2a-messagesend-on-avaproto-labsai-routes-to-8sg399r branch April 21, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant