Skip to content

feat(plugin-babylon): add backend abstraction (MCP/A2A) and consolida…#1

Open
odilitime wants to merge 129 commits into1.xfrom
odi-dev
Open

feat(plugin-babylon): add backend abstraction (MCP/A2A) and consolida…#1
odilitime wants to merge 129 commits into1.xfrom
odi-dev

Conversation

@odilitime
Copy link
Member

@odilitime odilitime commented Jan 20, 2026

…te docs

  • Add BABYLON_BACKEND config: 'mcp', 'a2a', or 'both' (default)
  • Implement execute() routing with MCP primary, A2A fallback
  • Add full A2A JSON-RPC 2.0 protocol support
  • Add TEST_BABYLON_AUTH action for auth verification
  • Update all 70+ wrapper methods to use execute()
  • Consolidate 6 architecture docs into CHANGELOG.md
  • Add sendA2AMessage with operation mapping (social., stats., etc)

Note

Low Risk
Only adds ignore rules for build artifacts, dependencies, env files, and editor/OS metadata; no runtime code changes. Low risk aside from potentially hiding newly-generated files from git status.

Overview
Adds a new .gitignore to exclude common build outputs (e.g. dist/, .turbo/), dependencies (node_modules), local env files, and IDE/OS artifacts from version control.

Adds .gitignore.turbo as a dedicated ignore snippet for Turbo build artifacts (.turbo/).

Written by Cursor Bugbot for commit ec78a0b. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Backend selection (mcp / a2a / both), API key/backend accessors, auth/config test action, agent‑card discovery routes.
    • Autonomous: two‑mode pipeline, trading safety bounds, enhanced trading decisions, position tracking, position monitor, feed poll worker.
    • Social & user: share/unshare posts, daily login rewards, get-activity, join‑group, close‑position via protocol, feed/leaderboard/futures CSV providers.
    • Protocol & client: MCP/A2A JSON‑RPC flows, large MCP tool catalog, robust JSON‑RPC client, whoami/portfolio helpers.
  • Refactor

    • Unified protocol service and execute routing, runtime‑scoped logging, wallet‑centric client, graceful backend fallbacks.
  • Documentation

    • New API reference and expanded README pipeline/architecture.
  • Chores

    • Added changelog, .gitignore and PRR lessons document.

Greptile Summary

  • Introduces backend abstraction layer with BABYLON_BACKEND configuration allowing 'mcp', 'a2a', or 'both' protocols, routing all 70+ API methods through unified execute() function
  • Implements full A2A JSON-RPC 2.0 protocol support with operation mapping, agent discovery routes (/.well-known/agent-card), and new authentication testing action
  • Optimizes performance with EVM service registration status caching (5-minute TTL with background refresh) and consolidates documentation into CHANGELOG.md

Important Files Changed

Filename Overview
src/services/a2a.ts Major refactor removing @a2a-js/sdk dependency, implementing unified execute() routing between MCP/A2A protocols with JSON-RPC 2.0 support
src/autonomous/AutonomousCoordinator.ts Variable naming bug where useMcp is undefined but passed to methods; should use useA2A variable instead
src/autonomous/AutonomousTradingService.ts Incomplete refactor mixing MCP/A2A terminology with parameter renamed to useMcp but logic still uses A2A service
src/actions/identity/test-babylon-auth.ts New diagnostic action using type assertions to access private A2A service properties, needs proper public API
src/services/client.ts Removes complex HTTP session auth flow but still references session tokens in makeRequest, creating potential inconsistency

Confidence score: 2/5

  • This PR introduces significant architectural changes but contains multiple variable naming bugs and incomplete refactoring that will cause runtime errors
  • Score reflects critical issues in autonomous services where undefined variables are passed to methods, mixed terminology between MCP/A2A protocols, and type assertion usage for private property access
  • Pay close attention to autonomous coordinator and trading service files which have undefined variable references that will break functionality

Sequence Diagram

sequenceDiagram
    participant User
    participant Action
    participant A2AService
    participant MCP as "MCP Endpoint"
    participant A2A as "A2A Protocol"

    User->>Action: "Buy shares in market ABC"
    Action->>A2AService: "execute('buyShares', {marketId: 'ABC', outcome: 'YES', amount: 100})"
    
    Note over A2AService: Check BABYLON_BACKEND setting
    
    alt backend === 'mcp'
        A2AService->>A2AService: "executeViaMcpInternal()"
        A2AService->>A2AService: "methodNameToMcpTool('buyShares') → 'buy_shares'"
        A2AService->>MCP: "callMcpTool('buy_shares', params)"
        MCP-->>A2AService: "Trade result"
        A2AService-->>Action: "Return result"
    else backend === 'a2a'
        A2AService->>A2AService: "executeViaA2AInternal()"
        A2AService->>A2AService: "methodNameToA2AOperation('buyShares') → 'trading.buy_shares'"
        A2AService->>A2A: "sendA2AMessage('trading.buy_shares', params)"
        A2A-->>A2AService: "A2A task response"
        A2AService->>A2AService: "extractA2AResult()"
        A2AService-->>Action: "Return result"
    else backend === 'both'
        A2AService->>A2AService: "Try MCP first"
        A2AService->>MCP: "callMcpTool('buy_shares', params)"
        alt MCP succeeds
            MCP-->>A2AService: "Trade result"
            A2AService-->>Action: "Return result"
        else MCP fails
            Note over A2AService: "Log MCP failure, fallback to A2A"
            A2AService->>A2A: "sendA2AMessage('trading.buy_shares', params)"
            A2A-->>A2AService: "A2A task response"
            A2AService-->>Action: "Return result"
        end
    end
    
    Action-->>User: "Successfully bought 100 YES shares at 0.65"
Loading

…te docs

- Add BABYLON_BACKEND config: 'mcp', 'a2a', or 'both' (default)
- Implement execute() routing with MCP primary, A2A fallback
- Add full A2A JSON-RPC 2.0 protocol support
- Add TEST_BABYLON_AUTH action for auth verification
- Update all 70+ wrapper methods to use execute()
- Consolidate 6 architecture docs into CHANGELOG.md
- Add sendA2AMessage with operation mapping (social.*, stats.*, etc)
Copilot AI review requested due to automatic review settings January 20, 2026 03:10
@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

Walkthrough

Adds BABYLON_BACKEND (mcp|a2a|both), BabylonProtocolService with unified execute routing and MCP/A2A JSON‑RPC helpers, ERC‑8004 agent‑card routes, autonomous trading safety/exit rules with position tracking, a feed‑poll worker, many providers/actions/docs, and a reshaped public export surface. (50 words)

Changes

Cohort / File(s) Summary
Docs & Changelog
CHANGELOG.md, README.md, docs/API_REFERENCE.md
Large new/updated docs: unreleased changelog entries, trading pipeline and architecture updates (duplicated in README), and a full API_REFERENCE covering MCP/REST endpoints, examples, and auth details.
Environment & Flags / Permissions
src/environment.ts, src/config/permissions.ts, src/autonomous/config.ts
Adds BABYLON_BACKEND and BABYLON_API_KEY; exposes getBackend()/getApiKey(); introduces TradingSafetyConfig/DEFAULT_TRADING_SAFETY and attaches safety to agent configs; permission checks use autonomous mode.
Protocol Core & JSON‑RPC
src/services/a2a.ts, src/client/json-rpc.ts
Reworks A2A into BabylonProtocolService (alias BabylonA2AService), adds unified execute() routing (mcp/a2a/both), endpoint/agent‑card discovery, MCP helpers, and a robust JSON‑RPC client (makeJsonRpcRequest/makeGetRequest).
EVM / Identity
src/services/evm.ts, src/services/evm/babylon-identity.ts
Adds in‑memory ERC‑8004 registration cache with TTL and periodic refresh (getCachedRegistrationStatus), moves logs to runtime.logger, and softens identity contract errors.
Client & Coordinator
src/services/client.ts, src/autonomous/AutonomousCoordinator.ts
Replaces BabylonClientService with lightweight BabylonClient (wallet-focused); coordinator updated to use runtime.logger and new trading execute signature (removed useA2A flag).
Autonomous Trading & Prompts
src/autonomous/AutonomousTradingService.ts, src/autonomous/prompts.ts, src/trading/types.ts
Migrates trading flows to MCP/A2A, introduces EnhancedTradingDecision, enforces required exitConditions for opens, adds DEFAULT_EXIT_CONDITIONS, updated parsing/validation and signatures.
Position Tracking & Trading Utilities
src/trading/position-tracker.ts, src/trading/types.ts
New position tracker and BabylonPosition model: create/update/close, persistence to runtime cache, event hooks, deterministic exit checks, price helpers, and position stats APIs.
Autonomous Tasks / Feed Poll
src/tasks/feed-poll.ts, related autonomous modules
Adds feed poll worker with rate‑limit backoff, LLM engagement decisioning (LIKE/COMMENT/SKIP), dedupe/memory tracking, A2A action execution, and init/registration helpers.
Providers & Data Formatters
src/providers/market-overview.ts, src/providers/futures.ts, src/providers/feed.ts, src/providers/leaderboard.ts
Refactors market overview to factory; adds multi‑resolution CSV providers for futures, feed, and leaderboard with normalization and formatters.
Actions: Identity, Social, Users, A2A, Futures
src/actions/identity/*, src/actions/social/*, src/actions/users/*, src/actions/a2a/*, src/actions/futures/*
Adds testBabylonAuthAction, tighter registration parsing, migrates actions to protocol/A2A service, and new actions: share‑post, daily‑login, get‑activity; futures close uses MCP/A2A results.
Routes & Agent Card
src/routes/agent-card.ts
Adds /.well-known/agent-card (and aliases) and agentCardRoutes, building cached agent cards with optional ERC‑8004 identity and discovery.
Index / Public Exports & Tasks
src/index.ts, src/tasks/*, src/pipeline/*
Removes legacy service exports, exposes BabylonProtocolService/A2A, agentCard routes, pipeline/trading modules, tasks and utils; reshapes public API surface.
Repo & Misc
.gitignore, .prr/lessons.md
Adds .gitignore and autogenerated PRR lessons document.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Agent/Client
  participant Runtime as IAgentRuntime
  participant Protocol as BabylonProtocolService
  participant EVM as BabylonEvmService
  participant MCP as MCP Endpoint
  participant A2A as A2A Endpoint

  Client->>Runtime: request operation (e.g., getMarketData / sharePost)
  Runtime->>Protocol: execute(operation, params)
  Protocol->>EVM: initializeCredentials()/fetchAgentCard
  alt backend = mcp
    Protocol->>MCP: mcpRequest(method, params)
    MCP-->>Protocol: result
  else backend = a2a
    Protocol->>A2A: sendA2AMessage(operation, params, contextId)
    A2A-->>Protocol: task/result
  else backend = both
    Protocol->>MCP: try mcpRequest(method, params)
    alt MCP fails
      Protocol->>A2A: sendA2AMessage(operation, params, contextId)
      A2A-->>Protocol: task/result
    else
      MCP-->>Protocol: result
    end
  end
  Protocol-->>Runtime: normalized result
  Runtime-->>Client: response
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I sniff the card, two backends hum,
MCP or A2A — choose which will come.
Trades get exits, positions kept track,
Feed polls hop in, no post shall lack.
A joyful rabbit nods — services stitched, done!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and accurately summarizes the main changes: adding backend abstraction (MCP/A2A) and consolidating documentation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch odi-dev

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 and usage tips.

Copy link

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/autonomous/AutonomousCoordinator.ts (2)

152-163: Same issue: useMcp is undefined here as well.

The condition on line 153 uses the undefined useMcp variable. This needs the same fix as line 112.

🐛 Proposed fix (assuming useA2A is correct)
-      if (config.autonomousTrading && useMcp && a2aService) {
+      if (config.autonomousTrading && useA2A && a2aService) {

110-122: Critical: useMcp is undefined — will cause ReferenceError at runtime.

The variable useMcp is used on lines 112 and 153 but is never declared anywhere in this file. Line 90 defines useA2A, which appears to be the relevant flag for this context.

This will throw a ReferenceError when config.autonomousTrading is true.

Define useMcp or replace it with the appropriate variable:

Suggested fix
-          const tradeResult = await autonomousTradingService.executeTrades(runtime, agentConfig, useMcp);
+          const tradeResult = await autonomousTradingService.executeTrades(runtime, agentConfig, useA2A);
-      if (config.autonomousTrading && useMcp && a2aService) {
+      if (config.autonomousTrading && useA2A && a2aService) {
🤖 Fix all issues with AI agents
In `@src/environment.ts`:
- Around line 39-44: The fallback logic is inconsistent with the comment: when
runtime.getSetting('BABYLON_BACKEND') yields an invalid value backendSetting,
the code assigns 'mcp' but the comment says default is 'both'. Update the
fallback to match the comment by ensuring the variable backend (typed
BabylonBackend) falls back to 'both' for invalid values; adjust the conditional
that computes backend (referencing backendSetting, backend, BabylonBackend, and
runtime.getSetting('BABYLON_BACKEND')) so the default behavior is 'both' instead
of 'mcp'.

In `@src/services/a2a.ts`:
- Around line 696-705: The fallback in callMcpTool currently returns `{ text }
as T` when JSON.parse fails, which is type-unsafe; either change the function
signature to explicitly allow a plain-text result (e.g., Promise<T | { text:
string }>) or stop returning a mismatched type and instead throw a descriptive
Error when parsing fails. Locate the callMcpTool implementation and replace the
catch block so it either rethrows a new Error including the raw text and
toolName (so callers must handle parse failures) or update the generic return
type to include `{ text: string }` and return that explicitly without casting.
- Around line 453-460: The extractA2AResult<T> helper currently returns the
entire A2ATask cast to T when no data part is found, which can silently produce
invalid shapes; change extractA2AResult to either throw a descriptive Error
(e.g., "Missing data part in A2ATask") or change its signature to return T |
undefined and return undefined when no data found, and then update all callers
to handle the error/undefined case; locate the function by name extractA2AResult
and references to task.artifacts/parts in A2ATask to implement the chosen
approach and ensure callers validate the result before use.

In `@src/services/evm.ts`:
- Around line 326-332: agentInfo.reputation may be null/undefined so calling
.toString() can throw; update the object construction (the ternary that returns
{ name: agentInfo.name, domain: agentInfo.domain, active: agentInfo.active,
reputation: agentInfo.reputation.toString() }) to guard the reputation access —
e.g., set reputation to agentInfo.reputation != null ?
String(agentInfo.reputation) : null (or a default like '0') so you never call
.toString() on null/undefined.

In `@src/types.ts`:
- Line 270: Update the inline comment for the backend property on the
BabylonBackend type to reflect the actual default value used elsewhere: change
the comment that currently says "'mcp' (default)" to "'both' (default)" so the
backend: BabylonBackend; comment matches the real default; modify the comment
text next to the backend field in the BabylonBackend/type declaration.
🧹 Nitpick comments (13)
src/services/client.ts (2)

8-18: Stale documentation: class comment describes removed authentication flow.

The class-level comment still describes the old authentication flow (sign message → send to /api/a2a/auth → receive session token → include in requests), but this logic has been removed. The comment should be updated to reflect that the A2A SDK now handles authentication via the agent card.

📝 Suggested documentation update
 /**
  * Babylon Client Service
  * 
  * Manages HTTP client, authentication, rate limiting, and request queuing.
  * 
- * Authentication Flow (for autonomous mode):
- * 1. Sign authentication message with agent wallet
- * 2. Send signature to /api/a2a/auth
- * 3. Receive session token
- * 4. Include token in all subsequent requests
+ * Authentication (for autonomous mode):
+ * The A2A SDK handles authentication internally via the agent card.
+ * This service initializes the wallet for signing A2A messages and on-chain operations.
  */

152-170: Approve the simplified authentication, but note dead code remains.

The change to wallet-only initialization with A2A SDK handling auth is clean. However, sessionToken is now never assigned, making isAuthenticated() always return false and the Authorization header logic in makeRequest() (lines 203-209) unreachable.

Consider removing or deprecating these dead code paths if HTTP session auth is no longer supported.

src/autonomous/AutonomousCoordinator.ts (1)

7-10: Comment may be stale - PR describes MCP as primary, not A2A.

The comment states "Prefer A2A when connected (better protocol compliance)" but the PR objectives indicate "MCP as primary and A2A as fallback." Consider updating this strategy comment to reflect the new routing priority.

src/autonomous/AutonomousTradingService.ts (2)

116-124: Confusing naming: useMcp controls A2A service usage.

When useMcp is true, the code uses a2aService methods. This naming is counterintuitive - consider if the semantics are correct or if the variable/condition should be inverted for clarity.


260-274: Inconsistent parameter naming in executeTrade.

The parameter is named useA2A here but useMcp in the calling method executeTrades. Additionally, line 270 logs "MCP service not connected" but checks a2aService.isConnected(), which is confusing. Consider aligning the naming throughout the class.

♻️ Suggested fix
   private async executeTrade(
     runtime: IAgentRuntime,
     decision: TradingDecision,
-    useA2A: boolean
+    useMcp: boolean
   ): Promise<boolean> {
     try {
-      if (useA2A) {
+      if (useMcp) {
         const a2aService = runtime.getService<BabylonA2AService>(BABYLON_A2A_SERVICE_NAME);

         if (!a2aService?.isConnected()) {
-          logger.warn('MCP service not connected');
+          logger.warn('A2A service not connected for MCP backend');
           return false;
         }

-        // Execute via MCP
+        // Execute via MCP (using A2A service)
         switch (decision.action) {
src/services/evm.ts (1)

86-93: Type-unsafe interval storage pattern.

Using (this as any)._registrationCacheInterval bypasses TypeScript's type checking. Consider declaring the property on the class for type safety.

♻️ Suggested fix

Add the property declaration to the class:

   private readonly REGISTRATION_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
+  private _registrationCacheInterval: ReturnType<typeof setInterval> | null = null;

Then update the usages:

   async stop(): Promise<void> {
     // Clear periodic cache refresh interval
-    if ((this as any)._registrationCacheInterval) {
-      clearInterval((this as any)._registrationCacheInterval);
-      (this as any)._registrationCacheInterval = null;
-    }
+    if (this._registrationCacheInterval) {
+      clearInterval(this._registrationCacheInterval);
+      this._registrationCacheInterval = null;
+    }
     logger.info('Babylon EVM Service stopped');
   }
   private setupPeriodicCacheRefresh(): void {
     // Refresh cache every 5 minutes
     const interval = setInterval(() => {
       this.refreshRegistrationCache().catch((error) => {
         logger.debug({ error }, 'Periodic registration cache refresh failed');
       });
     }, this.REGISTRATION_CACHE_TTL_MS);

     // Store interval ID for cleanup in stop()
-    (this as any)._registrationCacheInterval = interval;
+    this._registrationCacheInterval = interval;
   }

Also applies to: 363-376

src/routes/agent-card.ts (2)

59-61: Consider handling non-numeric tokenId gracefully.

If tokenId contains non-numeric characters, parseInt(tokenId) will return NaN, which will be included in the response. Consider adding validation or keeping it as a string.

💡 Suggested fix
         // ERC-8004 identity (if registered)
         ...(walletAddress && { address: walletAddress }),
-        ...(tokenId && { tokenId: parseInt(tokenId) }),
+        ...(tokenId && { tokenId: /^\d+$/.test(tokenId) ? parseInt(tokenId, 10) : tokenId }),

148-157: Consider limiting error details in production.

The error response includes the full error message, which could expose internal implementation details. For a public endpoint, consider providing a generic message while logging the full error.

💡 Suggested fix
         } catch (error) {
             runtime.logger.error({
                 error: error instanceof Error ? error.message : String(error),
+                stack: error instanceof Error ? error.stack : undefined,
             }, 'Error generating agent card');

             res.status(500).json({
                 error: 'Failed to generate agent card',
-                message: error instanceof Error ? error.message : String(error),
             });
         }
src/utils/plugin-banner.ts (2)

238-242: Remove unused cleanLine variable.

cleanLine is computed but never used. The pad function already handles ANSI stripping internally.

🧹 Suggested fix
     for (const line of tableLines) {
-        const cleanLine = stripAnsi(line);
         const paddedLine = pad(line, 78);
         output.push(`${ANSI.gray}|${ANSI.reset}${paddedLine}${ANSI.gray}|${ANSI.reset}`);
     }

104-109: Edge case: 4-character values are not masked.

When value.length === 4, the function returns the full value with zero asterisks appended. Consider whether this is the intended behavior for short secrets.

💡 Suggested fix
 function maskValue(value: string): string {
-    if (!value || value.length < 4) {
+    if (!value || value.length <= 4) {
         return '***';
     }
     return value.substring(0, 4) + '*'.repeat(Math.min(value.length - 4, 8));
 }
src/actions/identity/test-babylon-auth.ts (1)

97-121: Fragile access to private service properties via as any.

Accessing internal service properties (wallet, tokenId, agentId) through type casting bypasses encapsulation and will silently break if the service implementation changes. Consider adding public getter methods to BabylonA2AService for these properties.

The service already exposes getBackend(). Consider adding similar getters:

// In BabylonA2AService
getWalletAddress(): string | null { return this.wallet?.address ?? null; }
getTokenId(): string | null { return this.tokenId; }
getAgentId(): string | null { return this.agentId; }

Then use them here instead of (a2aService as any).wallet.

src/services/a2a.ts (2)

330-338: Endpoint discovery returns untested URL.

The method constructs multiple possible A2A endpoint patterns but returns the first one without verifying availability. This is noted as "most common" but may fail at runtime. Consider documenting this behavior or adding optional validation.


726-750: Consider adding return types to high-level API methods.

All high-level methods return Promise<any>, which loses type safety. As a future improvement, consider adding proper return types or using generics tied to the operation name.

Example with explicit types:

async getMarketData(marketId: string): Promise<MarketData> {
    return this.execute<MarketData>('getMarketData', { marketId });
}

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds backend abstraction to the Babylon plugin, enabling flexible routing between MCP (Model Context Protocol) and A2A (Agent-to-Agent) protocols. The implementation introduces a configurable BABYLON_BACKEND setting that supports MCP-only, A2A-only, or both (with graceful fallback) modes.

Changes:

  • Added backend abstraction with configurable routing (MCP, A2A, or both)
  • Implemented full A2A JSON-RPC 2.0 protocol support with operation mapping
  • Added TEST_BABYLON_AUTH action for authentication verification
  • Enhanced EVM service with registration status caching and periodic refresh
  • Consolidated architecture documentation into CHANGELOG.md

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
src/utils/plugin-banner.ts New utility for displaying plugin initialization banners with ANSI formatting
src/ascii-art.ts Babylon plugin ASCII art for console output
src/types.ts Added BabylonBackend type and apiKey field to BabylonConfig
src/services/evm/babylon-identity.ts Changed error logging to debug level for expected contract method absence
src/services/evm.ts Added registration status caching with periodic refresh and fast lookup methods
src/services/client.ts Removed HTTP session authentication, simplified to wallet initialization
src/services/a2a.ts Major refactor: added MCP/A2A routing, execute() method, and JSON-RPC 2.0 support
src/routes/index.ts New route exports for agent card endpoints
src/routes/agent-card.ts Agent card route for A2A protocol discovery at /.well-known/agent-card
src/providers/registration-status.ts Updated to use cached registration status for performance
src/plugin.ts Added agent card routes and TEST_BABYLON_AUTH action
src/index.ts Added route exports
src/environment.ts Added backend config parsing and apiKey support
src/autonomous/AutonomousTradingService.ts Updated parameter names (useMcp) to reflect backend usage
src/autonomous/AutonomousCoordinator.ts Updated to use new backend variable naming
src/actions/identity/test-babylon-auth.ts New action to verify authentication and backend connectivity
CHANGELOG.md Consolidated architecture documentation with version history

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

src/types.ts Outdated
apiKey?: string; // API key for A2A authentication (BABYLON_API_KEY)
agentId: string; // Agent ID (defaults to 'babylon-agent-alice' in dev)
cronSecret?: string; // CRON secret for A2A authentication
cronSecret?: string; // CRON secret for A2A authentication (deprecated, use apiKey)
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The deprecated config field 'cronSecret' has a comment saying it's deprecated in favor of 'apiKey', but there's no deprecation warning logged when it's used. Consider adding a runtime warning when cronSecret is set to guide users toward using the new apiKey field.

Copilot uses AI. Check for mistakes.
this.runtime.logger.error(`Error fetching agent info: ${JSON.stringify({ error: error instanceof Error ? error.message : String(error) })}`);
// This is expected if the contract doesn't have getAgentInfo or has a different signature
// Registration is still detected correctly via wallet NFT balance
this.runtime.logger.debug(`Babylon: getAgentInfo not available on this contract (this is normal - registration still detected via NFT)`);
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The error handling logs a debug message saying "this is normal" when getAgentInfo is not available on the contract. However, the original code logged this as an error. While the new approach is more appropriate (since this is expected behavior), consider whether debug level is visible enough for users troubleshooting registration issues. An info-level message might be more discoverable.

Suggested change
this.runtime.logger.debug(`Babylon: getAgentInfo not available on this contract (this is normal - registration still detected via NFT)`);
this.runtime.logger.info(`Babylon: getAgentInfo not available on this contract (this is normal - registration still detected via NFT)`);

Copilot uses AI. Check for mistakes.
* e.g., createPost -> create_post, getBalance -> get_balance
*/
private methodNameToMcpTool(methodName: string): string {
return methodName.replace(/([A-Z])/g, '_$1').toLowerCase();
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The methodNameToMcpTool function uses the same camelCase to snake_case conversion as methodNameToA2AOperation, which has the same potential issue with leading underscores if a method name starts with uppercase. Consider using a more robust conversion that handles edge cases like 'replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase()'.

Suggested change
return methodName.replace(/([A-Z])/g, '_$1').toLowerCase();
return methodName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();

Copilot uses AI. Check for mistakes.
export class BabylonA2AService extends Service {
static serviceType = BABYLON_A2A_SERVICE_NAME;
capabilityDescription = 'Babylon A2A Protocol service using official @a2a-js/sdk';
capabilityDescription = 'Babylon MCP and A2A Protocol service with ERC-8004 authentication';
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The class is named 'BabylonA2AService' but its description states it's a 'Babylon MCP and A2A Protocol service'. This creates confusion about the service's purpose. Consider renaming the class to 'BabylonBackendService' or 'BabylonProtocolService' to better reflect that it handles both MCP and A2A protocols, not just A2A.

Suggested change
capabilityDescription = 'Babylon MCP and A2A Protocol service with ERC-8004 authentication';
capabilityDescription = 'Babylon A2A protocol service with ERC-8004 authentication';

Copilot uses AI. Check for mistakes.
// Determine which backends are working based on configuration
const mcpWorks = status.mcpEndpointWorking;
const a2aWorks = status.a2aEndpointWorking;
const anyBackendWorks = mcpWorks || a2aWorks;
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

Unused variable anyBackendWorks.

Suggested change
const anyBackendWorks = mcpWorks || a2aWorks;

Copilot uses AI. Check for mistakes.

import type { Route, IAgentRuntime } from '@elizaos/core';
import { BabylonEnvironment } from '../environment';
import { BABYLON_A2A_SERVICE_NAME, BABYLON_EVM_SERVICE_NAME } from '../constants';
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

Unused import BABYLON_A2A_SERVICE_NAME.

Suggested change
import { BABYLON_A2A_SERVICE_NAME, BABYLON_EVM_SERVICE_NAME } from '../constants';
import { BABYLON_EVM_SERVICE_NAME } from '../constants';

Copilot uses AI. Check for mistakes.
*/
function pad(str: string, length: number, align: 'left' | 'center' | 'right' = 'left'): string {
const cleanStr = stripAnsi(str);
const ansiExtra = str.length - cleanStr.length;
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

Unused variable ansiExtra.

Suggested change
const ansiExtra = str.length - cleanStr.length;

Copilot uses AI. Check for mistakes.
*/
export function displayPluginBanner(runtime: IAgentRuntime, config: PluginBannerConfig): void {
const border = `+${'-'.repeat(78)}+`;
const emptyLine = `|${' '.repeat(78)}|`;
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

Unused variable emptyLine.

Suggested change
const emptyLine = `|${' '.repeat(78)}|`;

Copilot uses AI. Check for mistakes.
// Settings table
const tableLines = generateSettingsTable(runtime, config.settings);
for (const line of tableLines) {
const cleanLine = stripAnsi(line);
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

Unused variable cleanLine.

Suggested change
const cleanLine = stripAnsi(line);

Copilot uses AI. Check for mistakes.
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (3)

  1. src/services/client.ts, line 202-209 (link)

    logic: Session token logic remains but token creation was removed. This could cause requests to never include auth headers since this.sessionToken will always be null. Should the session token logic be removed entirely since authentication is now handled by the A2A SDK?

  2. src/services/client.ts, line 217-227 (link)

    logic: These methods (getSessionToken() and isAuthenticated()) will always return null/false since session token creation was removed but the methods weren't updated.

  3. src/autonomous/AutonomousTradingService.ts, line 118-124 (link)

    logic: Logic inconsistency: when useMcp is true, code checks A2A service connection but error message says 'A2A service not connected' - confusing for debugging

17 files reviewed, 12 comments

Edit Code Review Agent Settings | Greptile


// ERC-8004 identity (if registered)
...(walletAddress && { address: walletAddress }),
...(tokenId && { tokenId: parseInt(tokenId) }),
Copy link

Choose a reason for hiding this comment

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

logic: parseInt could fail silently if tokenId is not a valid number string

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/routes/agent-card.ts
Line: 61:61

Comment:
**logic:** parseInt could fail silently if tokenId is not a valid number string

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 88 to 91
if ((this as any)._registrationCacheInterval) {
clearInterval((this as any)._registrationCacheInterval);
(this as any)._registrationCacheInterval = null;
}
Copy link

Choose a reason for hiding this comment

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

style: Using type assertion (this as any) to store interval ID - consider adding a proper typed field to the class for cleaner code

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/evm.ts
Line: 88:91

Comment:
**style:** Using type assertion (this as any) to store interval ID - consider adding a proper typed field to the class for cleaner code

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 138 to 141
const evmService = await Promise.race([
this.runtime.getServiceLoadPromise(BABYLON_EVM_SERVICE_NAME as any),
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 10000))
]) as BabylonEvmService | undefined;
Copy link

Choose a reason for hiding this comment

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

style: Promise.race with timeout could leave hanging promises and potential memory leaks

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/a2a.ts
Line: 138:141

Comment:
**style:** Promise.race with timeout could leave hanging promises and potential memory leaks

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 615 to 618
const apiKey = this.environment.getApiKey();
if (!apiKey || !apiKey.trim()) {
throw new Error('BABYLON_API_KEY is required for MCP requests');
}
Copy link

Choose a reason for hiding this comment

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

logic: API key requirement for MCP could break existing configurations that don't have BABYLON_API_KEY set. Is BABYLON_API_KEY always available when MCP backend is used, or should this have a fallback?

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/services/a2a.ts
Line: 615:618

Comment:
**logic:** API key requirement for MCP could break existing configurations that don't have BABYLON_API_KEY set. Is BABYLON_API_KEY always available when MCP backend is used, or should this have a fallback?

How can I resolve this? If you propose a fix, please make it concise.

cursor[bot]

This comment was marked as outdated.

- Fix backend default fallback: 'both' instead of 'mcp' (environment.ts)
- Fix extractA2AResult: throw Error instead of unsafe cast when no data
- Fix callMcpTool: throw descriptive Error on JSON parse failure
- Fix reputation access: guard against null/undefined before toString()
- Update types.ts comment to reflect 'both' as default backend
…untime.logger migration

- Add feed poll task system with last-seen tracking and rate limit backoff
- Add multi-resolution providers (overview/default/full) for feed, markets, portfolio, futures, profile, leaderboard, notifications
- Migrate all services and autonomous modules to use runtime.logger instead of global logger
- Fix this.runtime binding issues in async callbacks (base-8004, base, evm services)
- Add optional chaining for safety in catch handlers
- Add all Babylon settings to spartan character configuration
cursor[bot]

This comment was marked as outdated.

Copy link

@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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/autonomous/AutonomousTradingService.ts (2)

31-35: Documentation example uses outdated parameter name.

The usage example references useA2A but the actual parameter was renamed to useMcp.

📝 Proposed fix
 * Usage:
 * ```typescript
 * const service = new AutonomousTradingService();
-* const result = await service.executeTrades(runtime, useA2A);
+* const result = await service.executeTrades(runtime, config, useMcp);
 * console.log(`Executed ${result.tradesExecuted} trades`);
 * ```

282-287: Fix position tracking for sell operations.

The code uses decision.marketId as positionId for sellShares, but these are semantically different identifiers. TradingDecision lacks a positionId field, and buyShares results are not captured to track the actual position ID returned by the backend. Without a position tracking mechanism, the sellShares call will likely fail at runtime. Either capture position IDs when buying shares and include them in the decision, or redesign the trading workflow to properly track position lifecycle.

src/providers/registration-status.ts (1)

34-47: Avoid reporting “No” when cache isn’t populated yet.
If getCachedRegistrationStatus() returns null on startup, the provider now reports “not registered,” which can be a false negative. Consider returning an “Unknown” state (or a fallback check) until the cache is warm.

💡 Suggested adjustment
-            const cached = service.getCachedRegistrationStatus();
-            const isRegistered = cached?.isRegistered ?? false;
+            const cached = service.getCachedRegistrationStatus();
+            if (!cached) {
+                return {
+                    text: 'Babylon ERC-8004 Registration Status: Unknown (cache not ready)',
+                    values: { registered: false },
+                    data: { registered: false, status: 'unknown' },
+                };
+            }
+            const isRegistered = cached.isRegistered;
src/services/evm/base.ts (1)

56-166: Ensure runtime is always initialized before using runtime.logger.

runtime is optional in the constructor, but this.runtime.logger is used unguarded during construction in logWalletConfig and setupPluginDetection. Unlike other services (e.g., BabylonUsersService), super() is called without passing runtime, and this.runtime may not be properly initialized by the parent Service class. Make runtime required and pass it to super(runtime) to ensure this.runtime is always available.

Suggested fix
-  constructor(rpcUrl: string, privateKey: string, runtime?: IAgentRuntime) {
-    super();
+  constructor(rpcUrl: string, privateKey: string, runtime: IAgentRuntime) {
+    super(runtime);
     this.provider = new ethers.JsonRpcProvider(rpcUrl);
     this.wallet = new ethers.Wallet(privateKey, this.provider);
🤖 Fix all issues with AI agents
In `@src/providers/feed.ts`:
- Around line 43-47: The reduce computations for totalLikes and totalComments
(and the comment/reply fallback) can misbehave if likes/comments/replies arrive
as strings; update the reducers in totalLikes and totalComments to coerce values
to numbers (e.g., using Number(...) or unary + with a fallback to 0) before
summing so concatenation is avoided, and ensure the same numeric coercion is
applied when computing avgEngagement from (totalLikes + totalComments) /
posts.length; reference the totalLikes, totalComments, avgEngagement, and the
posts.reduce callbacks to locate and change the logic.

In `@src/providers/futures.ts`:
- Around line 33-41: The numeric reductions and formatting in totalExposure,
totalPnL, longCount and shortCount assume numeric inputs and may break if API
fields are strings; coerce values to numbers (e.g., use Number(...) or
parseFloat(...) with a fallback 0) before summing, comparing (p.size,
p.notional, p.unrealizedPnl, p.pnl) and before calling toLocaleString() /
toFixed(), and apply the same coercion pattern to the other similar calculation
blocks in this file that compute exposures, PnL and position counts so
arithmetic and formatting never receive strings or undefined.
- Around line 1-9: The docblock in src/providers/futures.ts advertises "funding
rates" for the _OVERVIEW resolution but no funding-rate computation exists;
either implement funding-rate logic (e.g., add computeFundingRates and call it
from the function handling the _OVERVIEW suffix such as any
getFuturesOverview/getOverview handler) or more simply remove the "funding
rates" wording from the table/description and any duplicate mention on line 21
so documentation matches actual outputs; update the _OVERVIEW row to reflect
"Position count, total exposure" (or similar) and ensure comments reference only
implemented fields.

In `@src/providers/leaderboard.ts`:
- Around line 27-28: The leaderboard call is passing the wrong parameter
name—change the object passed to (service as any).getLeaderboard from { limit:
10 } and { limit: 20 } to use the expected pageSize key (e.g., { pageSize: 10 }
and { pageSize: 20 }) so getLeaderboard in the A2A service receives the
pagination size; update both places where getLeaderboard is invoked in this
module.

In `@src/providers/market-overview.ts`:
- Around line 44-56: Normalize the markets response by ensuring items is always
an array (e.g., set items = Array.isArray(markets) ? markets : markets?.items ||
markets?.markets || []), then coerce numeric fields when computing aggregates:
use Number(m.volume || 0) for totalVolume and Number(m.yesPrice ?? 0.5) for
avgYesPrice (guarding against NaN), and compute avgYesPrice as the sum of
coerced yesPrice values divided by items.length only when items.length > 0;
update references to items, totalVolume, and avgYesPrice accordingly.

In `@src/providers/portfolio.ts`:
- Around line 23-58: The fallback to the Futures service is triggered by the
condition !positions.length, which doesn't distinguish between an intentional
empty array returned by A2A and positions never being retrieved. This causes
valid empty results from A2A to be overwritten. To fix this, introduce a boolean
flag to track whether positions were successfully retrieved from A2A (set it to
true after successfully calling getFuturesPositions). Then modify the condition
for falling back to the Futures service to check this flag instead of just
checking if the positions array is empty, ensuring that a valid empty result
from A2A is not overwritten by the futuresService.getPositions fallback.

In `@src/providers/profile.ts`:
- Around line 82-90: The template building code uses numeric formatting methods
directly on profile fields which may be strings; coerce numeric-like fields
first (e.g., Number(profile.balance) || 0, Number(profile.reputation) || 0,
Number(profile.followers) || 0, Number(profile.following) || 0,
Number(profile.postCount) || 0, Number(profile.tradeCount) || 0, and
Number(profile.winRate) || 0) before calling toLocaleString() or toFixed(), then
use those coerced values in the `text` template (same approach for the other
block referenced around the `profile` output later in the file).

In `@src/tasks/feed-poll.ts`:
- Around line 372-377: The code updates lastSeenPostId using newestPostId
(allPosts[0]?.id) before processing, risking data loss if processing crashes;
change logic in feed-poll to only call setLastSeenPostId(newestPostId) after
each post in allPosts has been successfully processed (or update per-post after
each successful process) instead of before processing, or alternatively track
processed IDs with isPostProcessed and only advance lastSeenPostId to the
highest contiguous successfully processed post at the end of the processing
loop; locate references to allPosts, newestPostId, setLastSeenPostId, and
isPostProcessed in the feed processing block and move the update to after
successful processing completion (or implement per-post
update/contiguous-advance logic).
♻️ Duplicate comments (6)
src/autonomous/AutonomousTradingService.ts (1)

255-272: Parameter naming inconsistency: useA2A should be useMcp.

This method uses useA2A (lines 255, 261, 264) while all other methods in this class use useMcp. This inconsistency was flagged in previous reviews but remains unfixed. Additionally, line 268's log message says "MCP service not connected" but the variable being checked is a2aService.

🔧 Proposed fix
   /**
    * Execute trade based on decision
    * 
    * `@param` runtime - Agent runtime
    * `@param` decision - Trading decision
-   * `@param` useA2A - Whether to use A2A protocol
+   * `@param` useMcp - Whether to use MCP/A2A backend service
    * `@returns` True if trade was successful
    */
   private async executeTrade(
     runtime: IAgentRuntime,
     decision: TradingDecision,
-    useA2A: boolean
+    useMcp: boolean
   ): Promise<boolean> {
     try {
-      if (useA2A) {
+      if (useMcp) {
         const a2aService = runtime.getService<BabylonA2AService>(BABYLON_A2A_SERVICE_NAME);

         if (!a2aService?.isConnected()) {
-          runtime.logger.warn('MCP service not connected');
+          runtime.logger.warn('Backend service not connected');
           return false;
         }

-        // Execute via MCP
+        // Execute via backend service (MCP/A2A)
src/services/evm.ts (1)

86-91: Prefer a typed interval handle over (this as any) storage.
This keeps type safety and IDE help consistent with the rest of the class.

♻️ Suggested refactor
   private registrationCache: {
     isRegistered: boolean;
     tokenId: bigint | null;
     agentInfo: any | null;
     lastChecked: number;
   } | null = null;
+  private registrationCacheInterval: ReturnType<typeof setInterval> | null = null;
   private readonly REGISTRATION_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
-    if ((this as any)._registrationCacheInterval) {
-      clearInterval((this as any)._registrationCacheInterval);
-      (this as any)._registrationCacheInterval = null;
-    }
+    if (this.registrationCacheInterval) {
+      clearInterval(this.registrationCacheInterval);
+      this.registrationCacheInterval = null;
+    }
-    (this as any)._registrationCacheInterval = interval;
+    this.registrationCacheInterval = interval;

Also applies to: 366-375

src/services/client.ts (1)

152-170: Rename authenticate() to reflect that it only initializes wallet state.

The method no longer performs HTTP auth, so a clearer name reduces confusion.

♻️ Suggested refactor
-  private async authenticate(): Promise<void> {
+  private async initializeWallet(): Promise<void> {
     if (!this.wallet) {
       throw new Error('Wallet not initialized');
     }
@@
-    this.runtime.logger.info({
+    this.runtime.logger.info({
       agentId,
       address: this.wallet.address,
     }, '✅ Babylon wallet ready - A2A SDK will use this wallet for signing');
   }
-      await this.authenticate();
+      await this.initializeWallet();
src/services/a2a.ts (3)

8-53: Default backend should be 'both' to preserve MCP→A2A fallback.

The field initializes to 'mcp', which disables A2A fallback when config is missing, contradicting the stated default behavior.

🐛 Proposed fix
-  private backend: BabylonBackend = 'mcp';
+  private backend: BabylonBackend = 'both';

366-448: executeViaA2A ignores agentUrl, so calls may hit the wrong endpoint.

The method signature accepts agentUrl but never uses it, which silently routes to the configured default instead of the target agent.

🐛 Proposed fix (endpoint override)
-  async sendA2AMessage(
+  async sendA2AMessage(
     operation: string,
     params: Record<string, unknown> = {},
-    contextId?: string
+    contextId?: string,
+    endpointOverride?: string
   ): Promise<{ task?: A2ATask; error?: unknown }> {
-    if (!this.a2aEndpoint) {
+    const endpoint = endpointOverride || this.a2aEndpoint;
+    if (!endpoint) {
       throw new Error('A2A endpoint not configured');
     }
@@
-    this.runtime.logger.debug({
-      endpoint: this.a2aEndpoint,
+    this.runtime.logger.debug({
+      endpoint,
       operation,
       contextId: effectiveContextId,
       messageId,
     }, 'Sending A2A message');
@@
-    const response = await fetch(this.a2aEndpoint, {
+    const response = await fetch(endpoint, {
       method: 'POST',
       headers,
       body: JSON.stringify(requestBody),
     });
-    const response = await this.sendA2AMessage(a2aOperation, params);
+    const endpoint = await this.discoverA2AEndpoint(agentUrl);
+    const response = await this.sendA2AMessage(a2aOperation, params, undefined, endpoint);

Also applies to: 470-493


685-706: Handle MCP isError responses before parsing content.

Otherwise tool failures can be treated as successful results.

🐛 Proposed fix
   const result = await this.mcpRequest<{
     content: Array<{ type: 'text'; text: string }>;
     isError: boolean;
   }>('tools/call', {
     name: toolName,
     arguments: args,
   });
 
+  if (result.isError) {
+    const text = result.content?.[0]?.text;
+    throw new Error(`MCP tool '${toolName}' failed: ${text ?? 'Unknown error'}`);
+  }
+
   if (result.content && result.content.length > 0 && result.content[0]) {
     const text = result.content[0].text;
     try {
       return JSON.parse(text) as T;
🧹 Nitpick comments (7)
src/autonomous/AutonomousPostingService.ts (2)

69-72: Verify error logging argument order for structured logging.

In pino-style loggers (which runtime.logger appears to be based on the pattern in a2a.ts), the error object should be the first argument to properly serialize error properties in structured logs. The current pattern may result in the error being coerced to a string.

♻️ Suggested fix for structured error logging
     } catch (error) {
-      runtime.logger.error('Failed to create autonomous post:', error);
+      runtime.logger.error(error, 'Failed to create autonomous post');
       return { success: false };
     }

102-105: Same error logging pattern as above.

Apply the same fix here for consistent structured error logging.

♻️ Suggested fix
     } catch (error) {
-      runtime.logger.error('Failed to generate post content:', error);
+      runtime.logger.error(error, 'Failed to generate post content');
       return null;
     }
src/autonomous/AutonomousTradingService.ts (1)

243-245: Consider debug-level logging for parse failures.

Silent catch blocks can make debugging difficult. A debug-level log would help troubleshoot malformed LLM responses without cluttering normal output.

💡 Optional improvement
-    } catch {
-      // JSON parsing failed - return null
+    } catch (e) {
+      runtime.logger.debug('Failed to parse trading decision JSON:', e);
     }

Note: This would require passing runtime as a parameter to parseTradingDecision.

src/providers/feed.ts (1)

97-104: Clarify that only a subset of posts is displayed.

The header reports the full count but only shows 15 posts. Consider signaling the truncation.

♻️ Suggested tweak
-      const text = `BABYLON FEED (${posts.length} posts):
-${lines.join('\n')}`;
+      const text = `BABYLON FEED (showing ${lines.length} of ${posts.length} posts):
+${lines.join('\n')}`;
src/providers/leaderboard.ts (1)

45-47: Consider logging errors before returning fallback

The catch block silently swallows errors. Consider logging the error for debugging while still returning the graceful fallback:

     } catch (error) {
+      runtime.logger.debug?.(`Leaderboard overview error: ${error instanceof Error ? error.message : String(error)}`);
       return { text: 'Leaderboard overview unavailable', data: {}, values: {} };
     }

This applies to both providers (lines 45-47 and 84-86).

src/providers/markets.ts (1)

43-44: Default price of 0.5 may skew average calculation

When a market lacks a yesPrice, defaulting to 0.5 could skew the average. Consider filtering out markets without prices from the average calculation:

-      const avgYesPrice = items.reduce((sum: number, m: any) => sum + (m.yesPrice || 0.5), 0) / items.length;
+      const marketsWithPrice = items.filter((m: any) => m.yesPrice != null);
+      const avgYesPrice = marketsWithPrice.length > 0
+        ? marketsWithPrice.reduce((sum: number, m: any) => sum + m.yesPrice, 0) / marketsWithPrice.length
+        : 0.5;
src/tasks/feed-poll.ts (1)

219-227: Comment regex may not capture multi-line responses

The regex /COMMENT:\s*(.+)/i uses .+ which doesn't match newlines. If the LLM generates a multi-line comment, only the first line will be captured.

Consider using a more permissive pattern:

-  const commentMatch = response.match(/COMMENT:\s*(.+)/i);
+  const commentMatch = response.match(/COMMENT:\s*([\s\S]+?)(?=\n(?:ACTION|REASON):|$)/i);

Or since COMMENT is the last field in the template, capture everything after it:

-  const commentMatch = response.match(/COMMENT:\s*(.+)/i);
+  const commentMatch = response.match(/COMMENT:\s*([\s\S]+)/i);

Then trim the result to remove trailing whitespace.

…g order

- feed.ts: Coerce likes/comments/replies to numbers before summing
- futures.ts: Coerce all numeric fields, fix documentation (remove funding rates)
- leaderboard.ts: Change 'limit' to 'pageSize' parameter
- market-overview.ts: Normalize array response, coerce volume/yesPrice
- portfolio.ts: Use flag to track A2A success, prevent valid empty overwrite
- profile.ts: Coerce all numeric profile fields before formatting
- feed-poll.ts: Move lastSeenPostId update to after successful processing
- Add secondary check in isPostProcessed that searches messages by metadata
- Add retry logic to markPostProcessed (3 attempts with backoff)
- Handle race conditions where memory already exists
- Add detailed debug logging for memory operations
- Truncate post content to avoid oversized memories
- Check isError flag before parsing MCP tool response

Prevents replying to same posts repeatedly by using more robust memory tracking,
similar to plugin-twitter's approach.
Copy link

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
README.md (1)

654-658: Remove the duplicated “Available Archetypes” label.

The header appears twice back‑to‑back; drop one to avoid noise.

🧹 Nitpick comments (2)
README.md (1)

1012-1049: Add a language tag to the diagram fence.

Markdownlint flags untyped fences; use text (or plain) for the ASCII diagram.

♻️ Suggested tweak
-```
+```text
 ┌─────────────────────────────────────────────────────────────────┐
 │                    PRE-PHASE 1: Context Gathering               │
 ...
 └───────────────────────────┘   └───────────────────────────────┘
docs/API_REFERENCE.md (1)

28-31: Add language tags to the untyped fences.

Using text for these blocks will satisfy markdownlint and keep formatting consistent.

♻️ Suggested tweak
-```
+```text
 Production: https://babylon.game
 Development: http://localhost:3000

```diff
-```
+```text
 GET  /mcp  - Get MCP server info and available tools (for discovery)
 POST /mcp  - Execute MCP JSON-RPC 2.0 requests

```diff
-```
+```text
 score = likes + (comments * 2) + (shares * 3) - (hours_old * 0.5)
</details>


Also applies to: 59-62, 300-302

</blockquote></details>

</blockquote></details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

// Determine which backends are working based on configuration
const mcpWorks = status.mcpEndpointWorking;
const a2aWorks = status.a2aEndpointWorking;
const anyBackendWorks = mcpWorks || a2aWorks;
Copy link

Choose a reason for hiding this comment

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

Unused variable anyBackendWorks defined but never used

Low Severity

The variable anyBackendWorks is defined as mcpWorks || a2aWorks but is never used anywhere in the function. The code instead uses configuredBackendWorks which has the same logic embedded within it (for the backend === 'both' case). This is dead code that adds confusion without providing value.

Fix in Cursor Fix in Web


async sendChatMessage(chatId: string, content: string): Promise<any> {
return this.executeViaSDK('sendChatMessage', { chatId, content });
return this.execute('sendChatMessage', { chatId, content });
Copy link

Choose a reason for hiding this comment

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

Missing MCP tool mapping for sendChatMessage method

Medium Severity

The sendChatMessage method calls execute('sendChatMessage', ...) but the methodNameToMcpTool mapping only contains 'sendMessage': 'send_message'. Since sendChatMessage is not in the mapping, it falls back to camelCase→snake_case conversion producing send_chat_message, which doesn't match the actual MCP tool name send_message. This causes chat message sending to fail when using MCP backend.

Additional Locations (1)

Fix in Cursor Fix in Web

callback?: HandlerCallback
): Promise<ActionResult> => {
const a2aService = runtime.getService<BabylonA2AService>(BABYLON_A2A_SERVICE_NAME);
const evmService = runtime.getService<BabylonEvmService>(BABYLON_EVM_SERVICE_NAME);
Copy link

Choose a reason for hiding this comment

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

Unused evmService variable in test-babylon-auth action

Low Severity

The evmService variable is declared by calling runtime.getService() but is never used anywhere in the handler function. This is dead code that adds unnecessary overhead (the service lookup) and reduces code clarity. The variable should either be removed or used for something meaningful in the authentication test.

Fix in Cursor Fix in Web

stopLossPercent: 0.0-1.0 (e.g., 0.10 = exit if down 10%),
takeProfitPercent: 0.0-1.0 (e.g., 0.25 = exit if up 25%),
reasoning: "why these specific exit levels for this trade",
},
Copy link

Choose a reason for hiding this comment

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

Prompt requests JSON5 but parser uses standard JSON.parse

Medium Severity

The trading prompt instructs the LLM to respond with "JSON5 (unquoted keys OK, trailing commas OK)" but parseTradingDecision uses JSON.parse() which only handles strict JSON. If the LLM follows the prompt and uses unquoted keys or trailing commas, parsing will fail silently and return null, causing valid trading decisions to be ignored. The same issue exists in the registration template change.

Additional Locations (1)

Fix in Cursor Fix in Web

odilitime and others added 2 commits February 4, 2026 01:31
…amic providers

## Major Features

### Two-Phase Batch Processing Pipeline
- Phase 1: Single LLM call (TEXT_SMALL) routes posts + makes action decisions
- Phase 2a: Batched comment drafting for COMMENT actions
- Phase 2b: Batched trading analysis for signal=yes posts
- LIKEs execute immediately after Phase 1 (no LLM needed)

### Sentiment-Based Position Management
- Keyword-based sentiment extraction (NO LLM calls)
- EMA (exponential moving average) for sentiment scoring
- Positions track currentSentiment, sentimentExitThreshold
- Position monitor checks sentiment exits alongside price exits

### Token Efficiency
- CSV format prompts (~60% token savings vs JSON)
- Compact agent criteria in Phase 1
- Symbol-based market references (BTC, ETH, PD_123456)
- Smart truncation at word boundaries for all text

### New Providers
- babylon_plugin_settings (dynamic) - shows current config
- babylon_plugin_usage (dynamic) - usage instructions
- babylon_platform_info (static, optional) - customer service/marketing

## Improvements

### Memory Management
- processedPostIds size limit (1000) with auto-clear
- clearAnalysisRecords() on agent unregister
- Smart deduplication with cooldowns for held positions

### Risk Management
- Position limit validation (blocks new opens when at max)
- Held positions use lower odds threshold (0.8x) for exit signals
- Exposure checks before trading

### Bug Fixes
- Fixed preferredMarkets.join() when undefined
- Added error detail logging for Phase 2b
- Removed build artifacts from git tracking (601 files)
…form content

Updated with official Babylon messaging:
- How Babylon works (agents, feed, DMs, NPCs)
- The game loop (prompt → intel → analyze → trade → refine)
- Intel sources (feed narratives, NPC group chats)
- Getting started (create agent, fund, activate, iterate)
- Accurate mission and positioning

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@src/actions/identity/test-babylon-auth.ts`:
- Around line 198-211: The code marks the A2A endpoint working if result.task
exists but doesn't verify the task state; update the check around
a2aService.sendA2AMessage so you only set status.a2aEndpointWorking = true (and
log success) when result.task exists and result.task.status?.state ===
'succeeded' (otherwise leave it false and log the failure state), referencing
result.task, result.task.status?.state, status.a2aEndpointTested and
status.a2aEndpointWorking to locate and fix the logic in the A2A test block
around a2aService.sendA2AMessage('stats.system', {}).

In `@src/autonomous/AutonomousTradingService.ts`:
- Around line 154-173: The formatMarketData function treats legitimate zeros as
missing because it uses || for numeric fields; update numeric fallbacks to use
nullish coalescing (??) or explicit checks so 0 is preserved: change
balance.balance || balance.available || 0 to balance.balance ??
balance.available ?? 0, change positionsArray assignment to use
positions?.positions ?? (Array.isArray(positions) ? positions : []), replace
pos.shares || pos.size with pos.shares ?? pos.size, pos.pnl || pos.unrealizedPnl
|| 0 with pos.pnl ?? pos.unrealizedPnl ?? 0, change marketsArray assembly to
predictions?.markets ?? predictions?.questions ?? (Array.isArray(predictions) ?
predictions : []), replace market.yesPrice || market.yesProbability and
market.noPrice || market.noProbability with market.yesPrice ??
market.yesProbability and market.noPrice ?? market.noProbability, and compute
volume via Number(market.volume ?? 0) to preserve zero values.

In `@src/services/a2a.ts`:
- Around line 326-357: The current execute method falls back from MCP to A2A
unconditionally (in the backend === 'both' branch), which can duplicate
non‑idempotent actions; modify execute to only attempt executeViaA2AInternal
when the operation is safe to retry (e.g., read‑only or idempotent). Add or call
a helper like isReadOnlyOperation(operation: string) or
isIdempotentOperation(operation: string) and use it in the catch(mcpError)
block: if the helper returns true, proceed to try
executeViaA2AInternal(operation, params) and log the fallback; otherwise rethrow
the original mcpError (or wrap it without calling A2A). Keep references to
execute, executeViaMcpInternal, executeViaA2AInternal and the backend === 'both'
fallback logic when making the change.

…proved descriptions

Updated all dynamic providers to use CSV format (~60% token savings):

## Markets (babylon_markets, babylon_markets_overview, babylon_markets_full)
- Overview: Count, volume, avg odds, categories
- Medium: Top 20 markets with question, odds, volume
- Full: Top 15 with descriptions and resolution criteria

## Feed (babylon_feed, babylon_feed_overview, babylon_feed_full)
- Overview: Post count, engagement stats, top authors
- Medium: Recent 30 posts with previews
- Full: Recent 20 with complete content

## Portfolio (babylon_portfolio, babylon_portfolio_overview, babylon_portfolio_full)
- Overview: Balance, exposure, position count
- Medium: Balance + position list with P&L
- Full: Complete positions with entry/exit conditions

## Perpetuals (babylon_perpetuals, babylon_perpetuals_overview, babylon_perpetuals_full)
- Overview: Ticker count, volume, funding rates
- Medium: Top 25 tickers with price, volume, funding
- Full: Top 20 with leverage, liquidation, 24h change

## Profile (babylon_profile, babylon_profile_overview, babylon_profile_full)
- Overview: Username, points, reputation, level
- Medium: Profile + basic stats (trades, posts, win rate)
- Full: Complete stats, badges, preferences

## Leaderboard (babylon_leaderboard, babylon_leaderboard_full)
- Medium: Top 15 with rank, points, trades, win rate
- Full: Top 25 with ROI, best trade, reputation

## Positions (babylon_positions) - Single Resolution
- Agent's own positions with exit conditions (CSV format)

All providers marked dynamic: true for explicit opt-in usage.

Co-authored-by: Cursor <cursoragent@cursor.com>
};

return categoryMap[snakeCase] || `misc.${snakeCase}`;
}
Copy link

Choose a reason for hiding this comment

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

A2A operation mapping missing get_markets entry

Medium Severity

The methodNameToA2AOperation function is missing get_markets in the categoryMap. When getMarkets() is called with backend='a2a', it converts to get_markets but doesn't find it in the mapping, falling back to misc.get_markets instead of a proper A2A operation like market.get_markets or trading.get_markets. This may cause A2A requests to fail when not using MCP fallback.

Fix in Cursor Fix in Web

return true;
}
runtime.logger.warn('Position closing requires a position ID');
return false;
Copy link

Choose a reason for hiding this comment

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

Close action uses marketId instead of positionId

Medium Severity

The 'close' action case checks decision.marketId and passes it to closePosition(), but according to the EnhancedTradingDecision type definition, the positionId field is explicitly documented as "for add/modify_exits/close actions on existing positions". The code should use decision.positionId instead of decision.marketId for close operations.

Fix in Cursor Fix in Web

decision.marketId!, // Using marketId as positionId
decision.amount || 10
);
return true;
Copy link

Choose a reason for hiding this comment

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

Sell action incorrectly uses marketId as position identifier

Medium Severity

The 'sell' action passes decision.marketId to sellShares() which expects a positionId parameter. The comment acknowledges this mismatch ("Using marketId as positionId") but market IDs and position IDs are different identifiers. Sell operations will fail when the backend expects a valid position ID but receives a market ID.

Fix in Cursor Fix in Web

odilitime and others added 3 commits February 4, 2026 02:03
Fixed type errors and iterator compatibility issues:

- Map/Set iterators: Wrapped with Array.from() for ES2015 compatibility
- Provider return types: All providers return ProviderResult (not string)
- Unknown types: Cast to 'any' where API responses are dynamic
- Regex flags: Removed /s flag that requires ES2018
- Service methods: Fixed sendMessage -> sendA2AMessage
- Number to string: Convert error codes properly

All providers now type-safe and building without errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
Moved src/providers/factory.ts -> src/utils/provider-factory.ts

WHY:
- Keeps providers/ directory focused on actual providers only
- factory is a utility for building providers, fits better in utils/
- Updated all imports across provider files

Co-authored-by: Cursor <cursoragent@cursor.com>
…tilities

Created new utility modules to eliminate code duplication:

## New Utilities

### csv-helpers.ts
- sanitizeForCSV() - Replace commas/newlines (10+ duplicate instances)
- truncateAtWord() - Smart word-boundary truncation (5+ duplicates)
- prepareForCSV() - Combined sanitize + truncate
- formatPercent() - Format 0-1 values as percentages
- formatPnL() - Format P&L with +/- sign

### data-extractors.ts
- extractBalance() - Handle available/total field variants (3+ duplicates)
- extractMarketPrices() - Handle yesPrice/yesProbability variants (8+ duplicates)
- extractPerpPrice() - Handle multiple price field names
- extractVolume() - Handle volume/volume24h variants
- extractEngagement() - Handle likes/comments field variants
- extractProfileStats() - Extract profile fields consistently
- sortByVolume() - Sort by volume descending (5+ duplicates)

## Files Updated
- All provider files now use centralized helpers
- Pipeline files (phase1-router, phase2-draft, phase2-trading)
- Reduced ~200+ lines of duplicate code

Build and TypeScript checks pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
Change the fallback value for invalid BABYLON_BACKEND settings from 'mcp' to 'both' to match the documented behavior in the comment. When an unrecognized backend value is provided, gracefully default to 'both' (MCP primary, A2A fallback) instead of 'mcp'.

fix(a2a): throw on missing data artifact in extractA2AResult

Replace unsafe type cast fallback with explicit error when A2A task contains no data artifact. Prevents silent type mismatches by throwing 'A2A task completed but returned no data artifact' instead of casting the entire task object to the expected type.

fix(a2a): throw on JSON parse failure in callMcpTool

Replace type-unsafe fallback with error when MCP tool response cannot be parsed as JSON. Prevents returning { text } as T when parsing fails, which could cause runtime errors in callers expecting the declared return type.

fix(evm): add null check for agentInfo.reputation conversion

Guard against null/undefined reputation values using optional chaining and nullish coalescing operator. Changes agentInfo.reputation.toString() to agentInfo.reputation?.toString() ?? '0' to prevent runtime errors.

docs(types): update backend property comment to reflect actual default

Correct inline documentation for BabylonBackend type to indicate 'both' is the default value, not 'mcp', matching the implementation in environment.ts.
- Change invalid backend setting fallback from 'mcp' to 'both' to match comment
- Update types.ts comment to reflect 'both' as actual default value
- Add null check for agentInfo.reputation in evm.ts before calling toString()
- Replace unsafe type cast in extractA2AResult with explicit error throw
- Replace type-unsafe JSON parse fallback with descriptive error in callMcpTool
Changed the invalid backend setting fallback from 'mcp' to 'both' to match
the documented default behavior in the comment. The fallback now consistently
defaults to 'both' (MCP primary with A2A fallback) when an invalid value is
provided via BABYLON_BACKEND setting.

Also updated the types.ts comment to reflect that 'both' is the actual
default backend mode, not 'mcp'.
Changed the fallback value in backend validation from 'mcp' to 'both' to match
the documented default behavior. When an invalid BABYLON_BACKEND setting is
provided, the system now correctly defaults to 'both' (MCP primary with A2A
fallback) instead of 'mcp', ensuring consistency with the comment and intended
graceful fallback behavior.

fix(a2a): throw error when A2A task missing data artifact

Replaced unsafe type cast fallback in extractA2AResult that returned the entire
task object when no data part was found. Now throws a descriptive error to
prevent type mismatches and silent failures in callers expecting a properly
shaped data artifact.

fix(a2a): throw error on JSON parse failure in callMcpTool

Replaced type-unsafe fallback that returned { text } as T when JSON.parse
failed. Now throws a descriptive error with context when tool response cannot
be parsed, preventing runtime errors from type mismatches in callers.

fix(evm): add null check for agentInfo.reputation

Added optional chaining and default value when accessing agentInfo.reputation
to prevent null reference errors. Uses '0' as fallback when reputation is null
or undefined.

fix(types): correct backend default value in comment

Updated BabylonBackend type comment to accurately reflect 'both' as the default
instead of 'mcp', matching the actual implementation in environment.ts.
Iteration 1

prr-fix:prrc_kwdoqz480c6hlgqu
prr-fix:prrc_kwdoqz480c6koewd
prr-fix:prrc_kwdoqz480c6kojvm
prr-fix:prrc_kwdoqz480c6krrkl
prr-fix:prrc_kwdoqz480c6ksvu9
- environment.ts: change invalid backend setting fallback from 'mcp' to 'both' to match documented default behavior
- a2a.ts: throw descriptive error in extractA2AResult when data artifact is missing instead of returning unsafe type cast
- a2a.ts: throw descriptive error in callMcpTool when JSON parsing fails instead of returning mistyped fallback
- evm.ts: add null coalescing for agentInfo.reputation to prevent calling toString() on null/undefined
Iteration 1

prr-fix:prrc_kwdoqz480c6hu5ne
prr-fix:prrc_kwdoqz480c6hu5og
prr-fix:prrc_kwdoqz480c6knv74
prr-fix:prrc_kwdoqz480c6kn9d6
The fallback value for an invalid BABYLON_BACKEND setting was 'mcp',
but the comment and intended behavior specify 'both' as the default for
graceful fallback with MCP primary and A2A fallback. Updated the fallback
to match the documented default behavior.

Also apply type-safety improvements in a2a.ts and evm.ts, and update
type documentation to reflect actual defaults.
Iteration 1

prr-fix:prrc_kwdoqz480c6hu5mp
prr-fix:prrc_kwdoqz480c6hu5n_
prr-fix:prrc_kwdoqz480c6hu5og
prr-fix:prrc_kwdoqz480c6hu55v
prr-fix:prrc_kwdoqz480c6hu557
prr-fix:prrc_kwdoqz480c6hu6rx
prr-fix:prrc_kwdoqz480c6knkp0
prr-fix:prrc_kwdoqz480c6ko_3b
prr-fix:prrc_kwdoqz480c6kp2cc
prr-fix:prrc_kwdoqz480c6krgmy
- Change backend fallback from 'mcp' to 'both' in environment.ts to match documented default behavior
- Replace unsafe type cast with error throw in extractA2AResult when data artifact is missing
- Replace unsafe type cast with error throw in callMcpTool JSON parse fallback to prevent silent type mismatches
- Add null-safe optional chaining for agentInfo.reputation access in evm.ts to prevent runtime errors
- Update backend type comment in types.ts to correctly reflect 'both' as the default value
Iteration 1

prr-fix:prrc_kwdoqz480c6hu5yi
prr-fix:prrc_kwdoqz480c6hu5yt
Iteration 2

prr-fix:prrc_kwdoqz480c6knhqr
prr-fix:prrc_kwdoqz480c6knhqu
prr-fix:prrc_kwdoqz480c6knnwi
Iteration 3

prr-fix:prrc_kwdoqz480c6knggi
prr-fix:prrc_kwdoqz480c6ko7g3
Iteration 4

prr-fix:prrc_kwdoqz480c6koewd
- environment.ts: change invalid backend fallback from 'mcp' to 'both' to match documented default behavior
- a2a.ts: throw error in extractA2AResult when data artifact is missing instead of unsafely casting entire task
- a2a.ts: throw error in callMcpTool when JSON parsing fails instead of returning mismatched type
- evm.ts: add null-coalescing operator to agentInfo.reputation access to prevent null reference error
Iteration 1

prr-fix:prrc_kwdoqz480c6knb3s
Iteration 2

prr-fix:prrc_kwdoqz480c6ko_3b
prr-fix:prrc_kwdoqz480c6kp2ca
Change invalid backend setting fallback from 'mcp' to 'both' to match the
comment and documented behavior. When BABYLON_BACKEND environment variable
contains an invalid value, now correctly defaults to 'both' (MCP primary with
A2A fallback) instead of 'mcp'.

fix(a2a): throw error when A2A task has no data artifact

Replace unsafe type cast fallback in extractA2AResult with explicit error
throw when data part is missing. Prevents silent type mismatches where callers
would receive an invalid A2ATask object instead of the expected data shape.

fix(a2a): throw error when MCP tool response is not valid JSON

Replace unsafe fallback that cast plain text as T with explicit error throw
when JSON parsing fails. Callers now get clear feedback on parse failures
instead of receiving mistyped { text } objects.

fix(evm): add null safety check for agentInfo.reputation

Use optional chaining and nullish coalescing when converting reputation to
string. Prevents null reference exception if agentInfo.reputation is undefined.

docs(types): correct backend property default in comment

Update inline comment to reflect actual default value 'both' instead of 'mcp'.
Iteration 1

prr-fix:prrc_kwdoqz480c6hu5n_
- Change invalid backend setting fallback from 'mcp' to 'both' to match documented default
- Ensures graceful fallback behavior with MCP primary and A2A as secondary option
- Aligns implementation with inline comment stating "Default to 'both'"
```

---

**Alternative if you want to include all changes atomically:**

```
fix: align backend defaults, error handling, and type safety across config

- environment.ts: change invalid backend fallback from 'mcp' to 'both' to match docs
- a2a.ts: throw error in extractA2AResult when data artifact is missing instead of unsafe type cast
- a2a.ts: throw error in callMcpTool when JSON parsing fails instead of returning mismatched type
- evm.ts: add null check for agentInfo.reputation before calling toString()
- types.ts: update backend property comment to reflect 'both' as actual default, not 'mcp'
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

@@ -0,0 +1,3 @@

# Add to .gitignore - Turbo build artifacts
.turbo/
Copy link

Choose a reason for hiding this comment

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

Supplementary gitignore template file accidentally committed

Low Severity

The .gitignore.turbo file appears to be an instructional template that was accidentally committed. The comment "Add to .gitignore - Turbo build artifacts" indicates it was meant as a reminder to update the main .gitignore file, not to exist as a separate file. Git doesn't recognize .gitignore.turbo as an ignore file, so this file has no functional effect. The .turbo/ entry is already present in the main .gitignore, making this file redundant and unnecessary clutter.

Fix in Cursor Fix in Web

- Change invalid backend setting fallback from 'mcp' to 'both' to match documented default behavior
- Replace unsafe type cast in extractA2AResult with explicit error when data artifact is missing
- Throw descriptive error in callMcpTool JSON parse failure instead of returning mistyped object
- Add null coalescing for agentInfo.reputation to prevent .toString() on undefined values
Iteration 1

prr-fix:prrc_kwdoqz480c6hu5nb
prr-fix:prrc_kwdoqz480c6hu5on
prr-fix:prrc_kwdoqz480c6koly_
prr-fix:prrc_kwdoqz480c6ko7g3
Iteration 2

prr-fix:prrc_kwdoqz480c6hu5nq
prr-fix:prrc_kwdoqz480c6hu5n6
Iteration 3

prr-fix:prrc_kwdoqz480c6hu5mp
prr-fix:prrc_kwdoqz480c6koewd
Iteration 4

prr-fix:prrc_kwdoqz480c6knggi
Iteration 5

prr-fix:prrc_kwdoqz480c6knhqn
Iteration 6

prr-fix:prrc_kwdoqz480c6hu5oq
prr-fix:prrc_kwdoqz480c6hu5ov
prr-fix:prrc_kwdoqz480c6hu6rx
prr-fix:prrc_kwdoqz480c6hlgqu
Iteration 7

prr-fix:prrc_kwdoqz480c6hu53b
Changed the fallback value for invalid BABYLON_BACKEND setting from 'mcp'
to 'both' to match the documented behavior in the comment. When an invalid
backend setting is provided, the system now gracefully defaults to 'both'
(MCP primary with A2A fallback) instead of 'mcp' only.

Also updated the corresponding comment in types.ts to reflect that 'both'
is the actual default value.

fix(a2a): throw on missing data artifact in extractA2AResult

Replaced unsafe type cast fallback with explicit error thrown when A2A
task completes without a data artifact. This prevents silent type mismatches
and makes missing data failures explicit to callers.

fix(a2a): throw on JSON parse failure in callMcpTool

Replaced type-unsafe fallback that returned { text } as T when JSON parsing
failed. Now throws a descriptive error including the raw text and tool name,
requiring callers to handle parse failures explicitly.

fix(evm): add null check for agentInfo.reputation

Added optional chaining and nullish coalescing when converting reputation
to string. Prevents TypeError when reputation is null or undefined by
falling back to '0'.
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