Conversation
…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)
WalkthroughAdds 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
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
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 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:useMcpis undefined here as well.The condition on line 153 uses the undefined
useMcpvariable. 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:useMcpis undefined — will cause ReferenceError at runtime.The variable
useMcpis used on lines 112 and 153 but is never declared anywhere in this file. Line 90 definesuseA2A, which appears to be the relevant flag for this context.This will throw a
ReferenceErrorwhenconfig.autonomousTradingistrue.Define
useMcpor 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,
sessionTokenis now never assigned, makingisAuthenticated()always returnfalseand theAuthorizationheader logic inmakeRequest()(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:useMcpcontrols A2A service usage.When
useMcpistrue, the code usesa2aServicemethods. 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 inexecuteTrade.The parameter is named
useA2Ahere butuseMcpin the calling methodexecuteTrades. Additionally, line 270 logs "MCP service not connected" but checksa2aService.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)._registrationCacheIntervalbypasses 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
tokenIdcontains non-numeric characters,parseInt(tokenId)will returnNaN, 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 unusedcleanLinevariable.
cleanLineis computed but never used. Thepadfunction 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 viaas 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 toBabylonA2AServicefor 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 }); }
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
src/services/evm/babylon-identity.ts
Outdated
| 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)`); |
There was a problem hiding this comment.
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.
| 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)`); |
src/services/a2a.ts
Outdated
| * e.g., createPost -> create_post, getBalance -> get_balance | ||
| */ | ||
| private methodNameToMcpTool(methodName: string): string { | ||
| return methodName.replace(/([A-Z])/g, '_$1').toLowerCase(); |
There was a problem hiding this comment.
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()'.
| return methodName.replace(/([A-Z])/g, '_$1').toLowerCase(); | |
| return methodName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(); |
src/services/a2a.ts
Outdated
| 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'; |
There was a problem hiding this comment.
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.
| capabilityDescription = 'Babylon MCP and A2A Protocol service with ERC-8004 authentication'; | |
| capabilityDescription = 'Babylon A2A protocol service with ERC-8004 authentication'; |
| // Determine which backends are working based on configuration | ||
| const mcpWorks = status.mcpEndpointWorking; | ||
| const a2aWorks = status.a2aEndpointWorking; | ||
| const anyBackendWorks = mcpWorks || a2aWorks; |
There was a problem hiding this comment.
Unused variable anyBackendWorks.
| const anyBackendWorks = mcpWorks || a2aWorks; |
src/routes/agent-card.ts
Outdated
|
|
||
| import type { Route, IAgentRuntime } from '@elizaos/core'; | ||
| import { BabylonEnvironment } from '../environment'; | ||
| import { BABYLON_A2A_SERVICE_NAME, BABYLON_EVM_SERVICE_NAME } from '../constants'; |
There was a problem hiding this comment.
Unused import BABYLON_A2A_SERVICE_NAME.
| import { BABYLON_A2A_SERVICE_NAME, BABYLON_EVM_SERVICE_NAME } from '../constants'; | |
| import { BABYLON_EVM_SERVICE_NAME } from '../constants'; |
src/utils/plugin-banner.ts
Outdated
| */ | ||
| function pad(str: string, length: number, align: 'left' | 'center' | 'right' = 'left'): string { | ||
| const cleanStr = stripAnsi(str); | ||
| const ansiExtra = str.length - cleanStr.length; |
There was a problem hiding this comment.
Unused variable ansiExtra.
| const ansiExtra = str.length - cleanStr.length; |
src/utils/plugin-banner.ts
Outdated
| */ | ||
| export function displayPluginBanner(runtime: IAgentRuntime, config: PluginBannerConfig): void { | ||
| const border = `+${'-'.repeat(78)}+`; | ||
| const emptyLine = `|${' '.repeat(78)}|`; |
There was a problem hiding this comment.
Unused variable emptyLine.
| const emptyLine = `|${' '.repeat(78)}|`; |
src/utils/plugin-banner.ts
Outdated
| // Settings table | ||
| const tableLines = generateSettingsTable(runtime, config.settings); | ||
| for (const line of tableLines) { | ||
| const cleanLine = stripAnsi(line); |
There was a problem hiding this comment.
Unused variable cleanLine.
| const cleanLine = stripAnsi(line); |
There was a problem hiding this comment.
Additional Comments (3)
-
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.sessionTokenwill always be null. Should the session token logic be removed entirely since authentication is now handled by the A2A SDK? -
src/services/client.ts, line 217-227 (link)logic: These methods (
getSessionToken()andisAuthenticated()) will always return null/false since session token creation was removed but the methods weren't updated. -
src/autonomous/AutonomousTradingService.ts, line 118-124 (link)logic: Logic inconsistency: when
useMcpis true, code checks A2A service connection but error message says 'A2A service not connected' - confusing for debugging
17 files reviewed, 12 comments
src/routes/agent-card.ts
Outdated
|
|
||
| // ERC-8004 identity (if registered) | ||
| ...(walletAddress && { address: walletAddress }), | ||
| ...(tokenId && { tokenId: parseInt(tokenId) }), |
There was a problem hiding this comment.
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.
src/services/evm.ts
Outdated
| if ((this as any)._registrationCacheInterval) { | ||
| clearInterval((this as any)._registrationCacheInterval); | ||
| (this as any)._registrationCacheInterval = null; | ||
| } |
There was a problem hiding this comment.
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.
src/services/a2a.ts
Outdated
| 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; |
There was a problem hiding this comment.
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.| const apiKey = this.environment.getApiKey(); | ||
| if (!apiKey || !apiKey.trim()) { | ||
| throw new Error('BABYLON_API_KEY is required for MCP requests'); | ||
| } |
There was a problem hiding this 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?
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.- 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
There was a problem hiding this comment.
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
useA2Abut the actual parameter was renamed touseMcp.📝 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.marketIdaspositionIdforsellShares, but these are semantically different identifiers.TradingDecisionlacks apositionIdfield, andbuySharesresults are not captured to track the actual position ID returned by the backend. Without a position tracking mechanism, thesellSharescall 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.
IfgetCachedRegistrationStatus()returnsnullon 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: Ensureruntimeis always initialized before usingruntime.logger.
runtimeis optional in the constructor, butthis.runtime.loggeris used unguarded during construction inlogWalletConfigandsetupPluginDetection. Unlike other services (e.g.,BabylonUsersService),super()is called without passingruntime, andthis.runtimemay not be properly initialized by the parentServiceclass. Makeruntimerequired and pass it tosuper(runtime)to ensurethis.runtimeis 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:useA2Ashould beuseMcp.This method uses
useA2A(lines 255, 261, 264) while all other methods in this class useuseMcp. 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 isa2aService.🔧 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: Renameauthenticate()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:executeViaA2AignoresagentUrl, so calls may hit the wrong endpoint.The method signature accepts
agentUrlbut 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 MCPisErrorresponses 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.loggerappears to be based on the pattern ina2a.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
runtimeas a parameter toparseTradingDecision.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 fallbackThe 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 calculationWhen 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 responsesThe regex
/COMMENT:\s*(.+)/iuses.+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.
There was a problem hiding this comment.
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(orplain) 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
textfor 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; |
There was a problem hiding this comment.
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.
|
|
||
| async sendChatMessage(chatId: string, content: string): Promise<any> { | ||
| return this.executeViaSDK('sendChatMessage', { chatId, content }); | ||
| return this.execute('sendChatMessage', { chatId, content }); |
There was a problem hiding this comment.
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)
| callback?: HandlerCallback | ||
| ): Promise<ActionResult> => { | ||
| const a2aService = runtime.getService<BabylonA2AService>(BABYLON_A2A_SERVICE_NAME); | ||
| const evmService = runtime.getService<BabylonEvmService>(BABYLON_EVM_SERVICE_NAME); |
There was a problem hiding this comment.
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.
src/autonomous/prompts.ts
Outdated
| 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", | ||
| }, |
There was a problem hiding this comment.
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)
…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>
There was a problem hiding this comment.
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}`; | ||
| } |
There was a problem hiding this comment.
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.
| return true; | ||
| } | ||
| runtime.logger.warn('Position closing requires a position ID'); | ||
| return false; |
There was a problem hiding this comment.
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.
| decision.marketId!, // Using marketId as positionId | ||
| decision.amount || 10 | ||
| ); | ||
| return true; |
There was a problem hiding this comment.
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.
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'
There was a problem hiding this comment.
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/ | |||
There was a problem hiding this comment.
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.
- 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'.


…te docs
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
.gitignoreto exclude common build outputs (e.g.dist/,.turbo/), dependencies (node_modules), local env files, and IDE/OS artifacts from version control.Adds
.gitignore.turboas 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
Refactor
Documentation
Chores
Greptile Summary
BABYLON_BACKENDconfiguration allowing 'mcp', 'a2a', or 'both' protocols, routing all 70+ API methods through unifiedexecute()function/.well-known/agent-card), and new authentication testing actionCHANGELOG.mdImportant Files Changed
useMcpis undefined but passed to methods; should useuseA2Avariable insteaduseMcpbut logic still uses A2A serviceConfidence score: 2/5
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"