Skip to content

Conversation

@premiumjibles
Copy link
Contributor

@premiumjibles premiumjibles commented Nov 26, 2025

Summary by CodeRabbit

  • New Features

    • Unified portfolio view aggregating assets and allocations across connected networks.
    • System prompts now include current date/time and connected wallet info for more contextual AI responses.
    • Portfolio queries can target multiple networks or default to all connected wallets.
  • Behavior Changes

    • Portfolio now shows per-asset allocation and consolidated 24h delta; failures yield a safe empty portfolio state.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 26, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
shapeshift-agentic Ready Ready Preview Comment Nov 26, 2025 0:28am

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

📝 Walkthrough

Walkthrough

Consolidates portfolio fetching into an aggregated, single POST-based flow that returns network-tagged results; chat system prompt becomes dynamic and wallet-aware; server portfolio tool and route now accept an optional networks array (or derive connected networks) and return per-network portfolio items.

Changes

Cohort / File(s) Summary
Client portfolio service
apps/agentic-chat/src/services/portfolioService.ts
Replaced per-network PortfolioResponse with PortfolioNetworkResult (adds network). Removed parallel per-network fetches and fetchNetworkPortfolio; fetchFullPortfolio now POSTs both addresses to /api/portfolio, parses aggregated array, builds allAssets, computes totalBalance, per-asset allocation, delta24h, and returns default empty PortfolioData on error. Removed loadingChains/errorChains.
Types
apps/agentic-chat/src/types/portfolio.ts
Removed loadingChains: Set<ChainId> and errorChains: Set<ChainId> from PortfolioData. Remaining fields unchanged.
Server chat route
apps/agentic-server/src/routes/chat.ts
Added buildConnectedWalletsPrompt and buildSystemPrompt(evmAddress?, solanaAddress?); replaced static SYSTEM_PROMPT with dynamic prompt including connected wallets, current date/time and timestamp, expanded rules/tool guidance, and wallet-aware portfolio instructions.
Server portfolio route
apps/agentic-server/src/routes/portfolio.ts
Request schema now accepts optional networks array (z.array(z.enum(EVM_SOLANA_NETWORKS)).optional()); uses getConnectedNetworks when networks omitted; guards against empty networks with 400; calls getPortfolioData({ networks }, walletContext).
Server portfolio tool & logic
apps/agentic-server/src/tools/portfolio.ts
PortfolioInput now supports optional networks array. Added getConnectedNetworks(walletContext?). Introduced internal getPortfolioDataSingle(network, walletContext?) and public getPortfolioData({ networks }, walletContext?) returning PortfolioDataFull[] with network field. executeGetPortfolio derives networks from input or connected wallets, validates non-empty, and returns network-tagged results. Updated portfolioTool description.

Sequence Diagram

sequenceDiagram
    participant User
    participant ChatRoute as Chat Route
    participant PortfolioTool as Portfolio Tool
    participant PortfolioRoute as Portfolio Route
    participant Service as Portfolio Service
    participant API as /api/portfolio

    User->>ChatRoute: sends portfolio request
    ChatRoute->>ChatRoute: buildSystemPrompt(evm, solana) (wallets + date/time)
    ChatRoute->>PortfolioTool: invoke portfolio tool

    alt networks provided
        PortfolioTool->>PortfolioTool: use explicit networks
    else networks omitted
        PortfolioTool->>PortfolioTool: call getConnectedNetworks()
    end

    PortfolioTool->>PortfolioRoute: request portfolio for networks
    PortfolioRoute->>PortfolioRoute: validate networksToFetch (error if empty)
    PortfolioRoute->>Service: fetchFullPortfolio(evmAddress?, solanaAddress?)
    Service->>API: POST /api/portfolio { evmAddress?, solanaAddress? }
    API-->>Service: aggregated PortfolioNetworkResult[] (per-network)
    Service->>Service: aggregate allAssets, totalBalance, allocations, delta24h
    Service-->>PortfolioRoute: PortfolioData (aggregated)
    PortfolioRoute-->>PortfolioTool: network-tagged PortfolioDataFull[]
    PortfolioTool-->>ChatRoute: respond with per-network portfolio items
    ChatRoute-->>User: chat reply with portfolio info
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Attention areas:
    • Verify aggregation logic in fetchFullPortfolio correctly merges per-network balances, computes allocations and delta24h.
    • Ensure new PortfolioNetworkResult/PortfolioDataFull network field is handled across all consumers and serialization boundaries.
    • Confirm getConnectedNetworks consistently derives networks from wallet context for all wallet states.
    • Validate route/tool input schema changes and 400 guard logic in routes/portfolio.ts and error paths.
    • Check system prompt construction for correctness and that sensitive wallet data is formatted/truncated as intended.

Possibly related PRs

Poem

🐇 I hopped through chains both near and far,
Bundled wallets now shine like a star.
One POST to gather every clover leaf,
Balances summed—no more per-network grief.
A rabbit nods: aggregated and neat, hopping on happy feet.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: consolidating portfolio fetches into a single request and enhancing the LLM's awareness of connected accounts.
✨ 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 portfolio-fetch

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: 1

🧹 Nitpick comments (5)
apps/agentic-server/src/routes/portfolio.ts (2)

57-62: Helper correctly derives EVM/Solana networks but duplicates logic from tools layer

getConnectedNetworks cleanly filters connected wallets down to valid EvmSolanaNetwork values using chainIdToNetwork and EVM_SOLANA_NETWORKS, which is exactly what you want for constraining to portfolio-capable networks.

The same logic now exists in apps/agentic-server/src/tools/portfolio.ts; consider centralizing this (e.g., a shared helper in walletContextSimple or exporting it from one module) to avoid future drift if supported networks change.


20-27: Clarify intended behavior when networks is provided as an empty array

networksToFetch is computed as networks || getConnectedNetworks(walletContext). Because [] is truthy, an explicit networks: [] will result in networksToFetch.length === 0 and a 400 "No networks available..." response, instead of falling back to the connected wallets.

If the API is never supposed to receive networks: [], this is fine; otherwise, and if you’d like [] to behave like “omit networks and use connected ones,” you could guard explicitly on length:

-    const networksToFetch = networks || getConnectedNetworks(walletContext)
+    const networksToFetch =
+      networks && networks.length > 0 ? networks : getConnectedNetworks(walletContext)

Also applies to: 68-75, 77-78

apps/agentic-server/src/routes/chat.ts (1)

171-181: Dynamic system prompt wiring is correct; consider reusing a single Date instance

The new buildSystemPrompt correctly injects the connected-wallet summary, current date/time, and updated portfolio rule (“fetches all connected networks by default”) and is wired into streamText via system: buildSystemPrompt(evmAddress, solanaAddress).

If you care about consistency and micro-efficiency, you could create one const now = new Date() and reuse it for the formatted date and Unix timestamp instead of calling new Date() three times.

Also applies to: 242-244, 268-268

apps/agentic-chat/src/services/portfolioService.ts (1)

22-27: Consolidated fetch and aggregation logic are consistent with server shape

The client now expects PortfolioNetworkResult[] (network + balances) and correctly flattens all balances into PortfolioAsset[], recomputes totalBalance, per-asset allocation, and delta24h from the combined view. Error and non-OK responses both return a clean, empty PortfolioData object, which is a reasonable fallback.

You might consider extracting the repeated “empty portfolio” object into a small helper (e.g., makeEmptyPortfolio()) to avoid duplication across the early-return, non-OK, and catch paths, but that’s purely a cleanliness tweak.

Also applies to: 44-61, 63-98

apps/agentic-server/src/tools/portfolio.ts (1)

13-21: Schema and output types correctly model multi-network portfolios; helper duplicates route logic

The updated portfolioSchema and PortfolioOutput now encode multiple EvmSolanaNetwork entries with per-network balances, which matches the new client-side expectations.

getConnectedNetworks here mirrors the implementation in routes/portfolio.ts (filtering connected wallets down to EVM/Solana networks via chainIdToNetwork + EVM_SOLANA_NETWORKS), which is correct but duplicated; consider moving this helper to a shared module to keep supported-network logic in one place.

Also applies to: 41-53, 54-59

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f220730 and 068fd7e.

📒 Files selected for processing (4)
  • apps/agentic-chat/src/services/portfolioService.ts (2 hunks)
  • apps/agentic-server/src/routes/chat.ts (3 hunks)
  • apps/agentic-server/src/routes/portfolio.ts (3 hunks)
  • apps/agentic-server/src/tools/portfolio.ts (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/agentic-chat/src/services/portfolioService.ts (4)
packages/types/src/network.ts (1)
  • EvmSolanaNetwork (61-61)
apps/agentic-chat/src/types/portfolio.ts (1)
  • PortfolioAsset (3-17)
apps/agentic-chat/src/lib/bignumber.ts (2)
  • bnOrZero (5-13)
  • bn (3-3)
apps/agentic-chat/src/lib/portfolio.ts (1)
  • calculate24hDelta (7-39)
apps/agentic-server/src/routes/chat.ts (1)
apps/agentic-server/src/context.ts (1)
  • supportedChainsContext (1-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: main
🔇 Additional comments (2)
apps/agentic-server/src/routes/chat.ts (1)

161-169: Connected wallets prompt helper looks solid

Nicely encapsulates wallet display logic and cleanly handles the “no wallets” case while abbreviating addresses for readability; slicing will behave safely even if the input address is shorter than expected.

apps/agentic-server/src/tools/portfolio.ts (1)

61-118: Single-network fetch and caching flow are coherent

getPortfolioDataSingle cleanly maps a logical network to its chainId, derives the account from walletContext, pulls balances via executeGetAccount, enriches them with asset metadata from executeGetAssetsBasic, and computes cryptoAmount/usdAmount. The cache is keyed by (account, network), and cached entries are safely normalized to include network when returned.

Only thing to watch: if getAddressForNetwork(walletContext, network) can ever return undefined (e.g., networks passed without a corresponding connected wallet), this will bubble up as an error from executeGetAccount. Make sure all call sites either (a) only pass networks that exist in the wallet context or (b) handle such errors and surface a clear “no wallet for this network” message.

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

♻️ Duplicate comments (1)
apps/agentic-server/src/tools/portfolio.ts (1)

131-135: Consider a structured error for better orchestration handling.

As noted in previous review, when no networks are specified and no wallets are connected, this throws a generic Error. The chat orchestration layer should catch this and return a user-friendly message. Consider using a custom error type or code to make this easier to identify upstream.

+class NoWalletsConnectedError extends Error {
+  code = 'NO_CONNECTED_WALLETS'
+  constructor() {
+    super('No networks specified and no connected wallets found')
+  }
+}

   if (networks.length === 0) {
-    throw new Error('No networks specified and no connected wallets found')
+    throw new NoWalletsConnectedError()
   }
🧹 Nitpick comments (2)
apps/agentic-chat/src/services/portfolioService.ts (1)

42-57: Consider logging the error response body for better debugging.

When the response is not OK, you're logging response.statusText but the server may return a JSON body with more details (e.g., validation errors). Consider parsing and logging the response body for richer diagnostics.

     if (!response.ok) {
-      console.error('[Portfolio] Failed to fetch:', response.statusText)
+      const errorBody = await response.text().catch(() => 'Unable to read body')
+      console.error('[Portfolio] Failed to fetch:', response.statusText, errorBody)
       return {
         assets: [],
apps/agentic-server/src/tools/portfolio.ts (1)

120-125: Consider adding error handling for partial failures.

Promise.all will reject immediately if any single network fails, losing successful results from other networks. Depending on requirements, you may want to use Promise.allSettled to return partial results and surface per-network errors gracefully.

 export async function getPortfolioData(
   input: { networks: EvmSolanaNetwork[] },
   walletContext?: WalletContext
 ): Promise<PortfolioDataFull[]> {
-  return Promise.all(input.networks.map(network => getPortfolioDataSingle(network, walletContext)))
+  const results = await Promise.allSettled(
+    input.networks.map(network => getPortfolioDataSingle(network, walletContext))
+  )
+  return results
+    .filter((r): r is PromiseFulfilledResult<PortfolioDataFull> => r.status === 'fulfilled')
+    .map(r => r.value)
 }

Alternatively, if fail-fast is intentional for consistency, add a comment clarifying that behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 068fd7e and 509f925.

📒 Files selected for processing (5)
  • apps/agentic-chat/src/services/portfolioService.ts (1 hunks)
  • apps/agentic-chat/src/types/portfolio.ts (0 hunks)
  • apps/agentic-server/src/routes/chat.ts (3 hunks)
  • apps/agentic-server/src/routes/portfolio.ts (2 hunks)
  • apps/agentic-server/src/tools/portfolio.ts (6 hunks)
💤 Files with no reviewable changes (1)
  • apps/agentic-chat/src/types/portfolio.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/agentic-server/src/routes/chat.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: main
🔇 Additional comments (10)
apps/agentic-chat/src/services/portfolioService.ts (4)

22-27: LGTM! Type aligns with server response structure.

The PortfolioNetworkResult type correctly models the aggregated response from the server, including the network field for per-network context.


59-74: LGTM! Consolidation logic is correct.

The flatMap approach correctly aggregates balances from all networks, and the asset mapping properly extracts fields from the nested structure. The fallback to '0' for missing priceChange24h is appropriate.


76-81: Allocation calculation is correct.

The BigNumber-based calculation properly handles division-by-zero by checking totalBalance.gt(0) before computing percentages.


93-100: Consider logging the full error for debugging.

The catch block logs error directly, which is good. However, if error is not an Error instance, the log may be less informative. The current approach is acceptable, but you could add more context.

apps/agentic-server/src/routes/portfolio.ts (2)

19-27: Schema validation looks correct.

The schema properly allows optional networks array with enum validation and maintains the refinement requiring at least one address. This aligns with the multi-network API design.


60-69: LGTM! Multi-network flow is well-structured.

The logic correctly:

  1. Extracts optional networks from the validated request
  2. Falls back to getConnectedNetworks(walletContext) when not provided
  3. Guards against empty networks with a clear 400 response

This provides good flexibility for clients to either specify networks explicitly or rely on connected wallet derivation.

apps/agentic-server/src/tools/portfolio.ts (4)

13-18: LGTM! Schema correctly defines multi-network input.

Using z.enum(EVM_SOLANA_NETWORKS) ensures only valid network values are accepted, and the optional array with descriptive .describe() clearly communicates the API contract.


54-59: LGTM! Network derivation logic is correct.

The function properly:

  1. Guards against missing wallet context
  2. Maps chain IDs to networks using the lookup table
  3. Filters to ensure only valid EvmSolanaNetwork values are returned

The type guard (n): n is EvmSolanaNetwork correctly narrows the type.


139-150: LGTM! Output mapping is clean and correct.

The mapping correctly transforms PortfolioDataFull[] to PortfolioOutput by extracting only the necessary fields and including the network field in each entry for client-side disambiguation.


153-158: Tool description is clear and accurate.

The updated description correctly indicates that omitting networks will fetch all connected wallets, aligning with the implementation behavior.

@premiumjibles premiumjibles merged commit 239cc0e into main Nov 26, 2025
4 checks passed
@premiumjibles premiumjibles deleted the portfolio-fetch branch November 26, 2025 00:30
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.

2 participants