Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.2.30 #158

Merged
merged 32 commits into from
Dec 16, 2024
Merged

1.2.30 #158

merged 32 commits into from
Dec 16, 2024

Conversation

humanagent
Copy link
Collaborator

@humanagent humanagent commented Dec 15, 2024

Summary by CodeRabbit

  • New Features

    • Introduced a new Video component for enhanced documentation presentation.
    • Added a new XmtpPlugin class for managing conversations and groups using the XMTP protocol.
    • Enhanced FrameKit functionality for simplified receipt generation and wallet interactions.
    • Added a getWalletCount method to the LocalStorage class for counting wallet files.
    • Implemented a new content type for agent messages, including encoding and decoding logic.
  • Documentation

    • Updated section titles to emphasize the "library" aspect across various documentation pages.
    • Enhanced clarity in the WalletService documentation regarding identifier terminology.
    • Improved group creation and management instructions in the documentation.
    • Removed the "Prompt" section from the Payment Agent documentation to streamline content.
    • Introduced a new documentation page for "Frames" detailing their interaction with agents.
  • Bug Fixes

    • Corrected the title of the Circle Wallet Service documentation.
    • Removed outdated references to the XMTP plugin in multiple documentation files.
  • Chores

    • Removed unused imports and simplified user notification messages in the concierge skill.
    • Cleaned up documentation by removing obsolete sections and files.
    • Removed the "Introduction" entry from the sidebar configuration.
    • Updated URL formats in the FrameKit documentation for receipts.

Copy link

vercel bot commented Dec 15, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
message-kit-docs ✅ Ready (Inspect) Visit Preview Dec 16, 2024 1:39pm
message-kit-frames 🔄 Building (Inspect) Visit Preview Dec 16, 2024 1:39pm

Copy link
Contributor

coderabbitai bot commented Dec 15, 2024

Warning

Rate limit exceeded

@humanagent has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 920e223 and 7eea155.

📒 Files selected for processing (12)
  • package.json (1 hunks)
  • packages/create-message-kit/index.js (1 hunks)
  • packages/create-message-kit/package.json (1 hunks)
  • packages/docs/pages/changelog.mdx (1 hunks)
  • packages/docs/pages/ux/frames.mdx (1 hunks)
  • packages/docs/vocs.config.tsx (2 hunks)
  • packages/message-kit/package.json (2 hunks)
  • packages/message-kit/src/lib/core.ts (13 hunks)
  • packages/message-kit/src/plugins/storage.ts (2 hunks)
  • packages/message-kit/src/plugins/xmtp.ts (1 hunks)
  • packages/message-kit/src/xmtp/stream.ts (5 hunks)
  • templates/gm/src/index.ts (1 hunks)

Walkthrough

This pull request encompasses a comprehensive documentation and code update across multiple files in the MessageKit ecosystem. The changes primarily focus on standardizing terminology, updating wallet service implementations, and reorganizing documentation to emphasize community-driven libraries. Key modifications include renaming documentation headers to "library" format, updating wallet service classes, removing XMTP-related references, and simplifying some agent and skill implementations.

Changes

File/Path Change Summary
packages/docs/pages/community/* Updated headers from single terms to "library" format (Plugins, Skills, Templates, Projects)
packages/docs/pages/plugins/cdp.mdx Restructured documentation, removed wallet management section, added security architecture
packages/docs/pages/plugins/circle.mdx Corrected typo, replaced detailed code examples with external file reference
packages/docs/pages/plugins/xmtp.mdx Completely removed
packages/message-kit/src/plugins/cdp.ts Updated WalletService with new properties, reintroduced swap method
packages/message-kit/src/plugins/circle.ts Renamed humanAddress to senderAddress, updated method signatures
packages/message-kit/src/skills/concierge.ts Simplified user notification, removed specific imports
templates/paymentagent/src/* Removed systemPrompt and related imports

Possibly Related PRs

  • fix: Corrections to Typos and Formatting in Documentation #126: This PR addresses corrections to typos and formatting in documentation, which is relevant as it may include changes to the documentation structure similar to the modifications made in the main PR regarding the plugins.mdx file.
  • Testing #137: While this PR focuses on adding a testing job to the GitHub Actions workflow, it may indirectly relate to the main PR by ensuring that documentation changes are validated through tests, although it does not directly modify documentation content.

Suggested Reviewers

  • fabriguespe
  • nplasterer

Poem

🐰 Hop, hop, through code's domain,
Libraries bloom, no longer plain!
Wallets dance, plugins take flight,
MessageKit's magic shines so bright!
Documentation's rabbit trail gleams ✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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

🔭 Outside diff range comments (1)
packages/message-kit/src/plugins/circle.ts (1)

Line range hint 183-183: Update parameter name for consistency.

The checkBalance method still uses humanAddress parameter while other methods use identifier.

-  async checkBalance(
-    humanAddress: string,
+  async checkBalance(
+    identifier: string,
🧹 Nitpick comments (9)
packages/docs/pages/plugins/cdp.mdx (1)

23-26: Add usage examples to improve documentation

Consider adding example code snippets demonstrating:

  • Common usage patterns
  • Error handling scenarios
  • Security best practices
packages/docs/pages/templates/circle-agent.mdx (2)

1-6: Add version compatibility information

Consider adding:

  • Supported MessageKit versions
  • Required Node.js version
  • Any other dependencies or prerequisites

46-52: Consider replacing "End result" with "Output" or "Result"

The term "End result" is wordy and could be simplified.

🧰 Tools
🪛 LanguageTool

[style] ~46-~46: ‘End result’ might be wordy. Consider a shorter alternative.
Context: ...ates/circle-agent/.env.example] ``` ## End result The end result is a prompt that the mo...

(EN_WORDINESS_PREMIUM_END_RESULT)


[style] ~48-~48: ‘end result’ might be wordy. Consider a shorter alternative.
Context: ...t/.env.example] ``` ## End result The end result is a prompt that the model can understa...

(EN_WORDINESS_PREMIUM_END_RESULT)

packages/docs/pages/community/templates.mdx (1)

Line range hint 22-35: Enhance directory structure documentation

Consider adding:

  • Purpose of each directory/file
  • Required vs optional components
  • Best practices for organizing template code
packages/docs/pages/ux/wallet-service.mdx (1)

45-45: Fix grammar in the plugins section.

Add a comma after "Currently" for better readability.

-Currently messagekit supports Circle and CDP SDKs.
+Currently, messagekit supports Circle and CDP SDKs.
packages/docs/pages/community/projects.mdx (1)

1-4: LGTM! Well-organized project showcase.

The new "Projects library" header and organization by hackathon events provides a clear structure for community projects.

Consider adding more detailed descriptions for each project to better highlight their unique features and use cases.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~2-~2: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: # Projects library Open source projects from the community. - [wordle...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

packages/message-kit/src/plugins/cdp.ts (2)

Line range hint 79-94: Enhance error handling in createWallet

While the property renaming is good, the error handling could be improved to provide more specific error messages.

  } catch (error) {
-   console.error("Failed to create wallet:", error);
-   throw new Error("Failed to create wallet");
+   console.error("Failed to create wallet:", error);
+   if (error instanceof Error) {
+     throw new Error(`Failed to create wallet: ${error.message}`);
+   }
+   throw new Error("Failed to create wallet: Unknown error");
  }

143-143: Enhance logging structure

Consider using structured logging for better observability.

- console.log(`Retrieved wallet data for ${humanAddress}`);
+ console.log('Wallet data retrieved', { address: humanAddress });
packages/message-kit/src/skills/concierge.ts (1)

185-185: Simplify balance notification message

The balance notification has been simplified, but it could be more informative by including the remaining balance.

- await context.dm(`Your balance was deducted by $${amount}`);
+ await context.dm(`Transfer complete: $${amount} was deducted from your balance. Current balance: $${balance}`);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 994d698 and b15c7da.

📒 Files selected for processing (15)
  • packages/docs/pages/community/plugins.mdx (1 hunks)
  • packages/docs/pages/community/projects.mdx (1 hunks)
  • packages/docs/pages/community/skills.mdx (1 hunks)
  • packages/docs/pages/community/templates.mdx (1 hunks)
  • packages/docs/pages/plugins/cdp.mdx (1 hunks)
  • packages/docs/pages/plugins/circle.mdx (2 hunks)
  • packages/docs/pages/plugins/xmtp.mdx (0 hunks)
  • packages/docs/pages/templates/circle-agent.mdx (1 hunks)
  • packages/docs/pages/templates/gated-group.mdx (0 hunks)
  • packages/docs/pages/ux/wallet-service.mdx (2 hunks)
  • packages/message-kit/src/plugins/cdp.ts (6 hunks)
  • packages/message-kit/src/plugins/circle.ts (4 hunks)
  • packages/message-kit/src/skills/concierge.ts (2 hunks)
  • templates/paymentagent/src/index.ts (0 hunks)
  • templates/paymentagent/src/prompt.ts (0 hunks)
💤 Files with no reviewable changes (4)
  • templates/paymentagent/src/index.ts
  • packages/docs/pages/templates/gated-group.mdx
  • packages/docs/pages/plugins/xmtp.mdx
  • templates/paymentagent/src/prompt.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/docs/pages/community/plugins.mdx
  • packages/docs/pages/plugins/circle.mdx
  • packages/docs/pages/community/skills.mdx
🧰 Additional context used
🪛 LanguageTool
packages/docs/pages/ux/wallet-service.mdx

[uncategorized] ~44-~44: A comma may be missing after the conjunctive/linking adverb ‘Currently’.
Context: ...d, toAssetId, amount); ``` ## Plugins Currently messagekit supports Circle and CDP SDKs...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

packages/docs/pages/templates/circle-agent.mdx

[style] ~46-~46: ‘End result’ might be wordy. Consider a shorter alternative.
Context: ...ates/circle-agent/.env.example] ``` ## End result The end result is a prompt that the mo...

(EN_WORDINESS_PREMIUM_END_RESULT)


[style] ~48-~48: ‘end result’ might be wordy. Consider a shorter alternative.
Context: ...t/.env.example] ``` ## End result The end result is a prompt that the model can understa...

(EN_WORDINESS_PREMIUM_END_RESULT)

🔇 Additional comments (5)
packages/docs/pages/community/templates.mdx (1)

4-6: LGTM! Clear and descriptive introduction

The updated header and introduction effectively communicate the purpose of the templates library.

packages/docs/pages/ux/wallet-service.mdx (1)

16-22: LGTM! Consistent terminology updates in code examples.

The change from "humanAddress" to "identifier or address" makes the documentation more generic and inclusive.

packages/message-kit/src/plugins/circle.ts (3)

48-51: LGTM! Consistent property renaming.

The change from humanAddress to senderAddress aligns with the documentation updates.


108-109: Verify the impact of return object structure changes.

The return object now uses this.senderAddress for address and wallet.address for agent_address. Ensure all consumers of this API are updated accordingly.

✅ Verification successful

The previous pattern was too specific. Let's broaden our search to find any usage of createWallet and related address fields to verify the impact of these changes.


No breaking changes detected in the return object structure

Based on the search results, the changes in the return object structure are consistent with existing usage patterns in the codebase. The agent_address and address fields are already being used correctly across multiple files:

  • In packages/message-kit/src/plugins/cdp.ts, the same structure is used:
{
  agent_address: address.getId(),
  address: this.senderAddress,
  key
}
  • In packages/message-kit/src/helpers/types.ts, the AgentWalletData type already includes agent_address
  • The consumers in packages/message-kit/src/skills/concierge.ts and other files are already using these fields correctly
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of WalletService return values
ast-grep --pattern 'const $result = await $service.createWallet($$$)'

Length of output: 71


Script:

#!/bin/bash
# Search for any usage patterns of createWallet with different variable names
ast-grep --pattern '$_ = await $_.createWallet($$$)'

# Search for any direct references to createWallet
rg "createWallet" -A 3

# Search for any usage of the terms address and agent_address nearby
rg "agent_address|senderAddress" -A 3

Length of output: 19956


Line range hint 67-81: Verify the metadata structure changes.

The metadata structure has been updated to include both identifier and senderAddress. Ensure this change is compatible with existing wallet management systems.

✅ Verification successful

Let me gather more information about the Circle wallet creation implementation and its usage.


Let me search for more specific information about the Circle wallet metadata structure and its usage in tests or documentation.


Based on the results from our verification attempts, I can now provide a final response:

The metadata structure change appears to be isolated to wallet creation

The metadata structure with user and senderAddress fields is only used in the wallet creation context within circle.ts, and there are no other instances of similar metadata structures found in the codebase. Since this is part of the initial wallet creation process and doesn't affect existing wallets (as it's only used during creation), the change is safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for metadata structure usage in other files
rg -A 5 "metadata: \["

Length of output: 384


Script:

#!/bin/bash
# Search for createWallet implementations and usages
ast-grep --pattern 'createWallet($_) { $$$ }'

# Search for Circle wallet-related configurations and tests
rg -l "CIRCLE_WALLET" 

# Search for wallet creation tests or specs
rg -A 5 "createWallet.*test|spec"

Length of output: 13170


Script:

#!/bin/bash
# Search for Circle wallet metadata in documentation
rg -A 5 "metadata.*Circle" packages/docs/

# Search for wallet creation tests
rg -A 10 "createWallet.*test" packages/message-kit/

# Look for Circle wallet interface or type definitions
ast-grep --pattern 'interface $_WalletData { $$$ }'

Length of output: 151

Comment on lines +17 to +21
## Security Architecture

// Withdraw funds (optional amount parameter)
await walletService.fund(amount);
The WalletService uses encryption with local file storage:

// Transfer between wallets
await walletService.transfer(humanAddress, humanAddress, amount);
- Wallets are encrypted using the private key of the developer
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Security Architecture section needs more details

The security documentation is incomplete and should include:

  • Detailed explanation of the encryption process
  • Information about the local file storage implementation
  • Security best practices and limitations
  • Documentation for the getEncryptionKey() method mentioned in other parts of the codebase

Would you like me to help draft a more comprehensive security architecture section?

Comment on lines 34 to 36
```tsx [src/prompt.ts]
// [!include ~/../../templates/circle-agent/src/prompt.ts]
```
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Remove or update the prompt.ts code section

The prompt.ts file does not exist in the templates/circle-agent/src/ directory. The documentation references a non-existent file in the "Prompt" section, which needs to be removed or updated to reflect the current implementation.

  • Remove or update the "Prompt" section in packages/docs/pages/templates/circle-agent.mdx that references src/prompt.ts
  • If the prompt functionality has moved elsewhere, update the documentation to point to the correct location
🔗 Analysis chain

Update or remove reference to deleted prompt.ts file

According to the AI summary, the src/prompt.ts file has been deleted. This section needs to be updated to reflect the current implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify if prompt.ts exists
fd -t f "prompt.ts" templates/circle-agent/src/

Length of output: 47


Script:

#!/bin/bash
# Let's verify if the file exists in a broader scope and check the content of the mdx file
fd -t f "prompt.ts" 
cat packages/docs/pages/templates/circle-agent.mdx

Length of output: 1078


Script:

#!/bin/bash
# Let's verify if the directory exists and check its contents
fd -t d "circle-agent" templates/
ls -la templates/circle-agent/src/ 2>/dev/null || echo "Directory not accessible or empty"

Length of output: 316

Comment on lines 1 to 2
import List from "../../components/List";
import templatesData from "../../../../community/templates.json";
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

🛠️ Refactor suggestion

Error handling is needed for templatesData import

The List component assumes the input will be a valid array and directly uses array methods without any type checking or error handling. Since the JSON file is a critical data source, add error handling:

  • Wrap the templatesData import in a try-catch block
  • Add runtime type checking to ensure templatesData is a valid array before passing it to the List component
  • Add a fallback UI for when the data is invalid or missing

Example locations that need attention:

  • packages/docs/pages/community/templates.mdx: Add error handling around the templatesData import and List component usage
  • packages/docs/components/List.tsx: Add prop type validation and error boundaries
🔗 Analysis chain

Add error handling for templatesData import

Consider adding error handling for cases where the JSON file might be missing or malformed.


Let me check how this JSON file is being used in the code to make a more informed decision.


Let me try a different approach using ripgrep to see the content and usage.


Let me check the List component to understand how it handles potential undefined or malformed data.


Let me check the List component implementation one final time to understand how it handles the data.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify if templates.json exists and is valid JSON
fd -t f "templates.json" community/ -x sh -c 'echo "Checking {}"; jq "." {} > /dev/null && echo "Valid JSON" || echo "Invalid JSON"'

Length of output: 177


Script:

#!/bin/bash
# Check how templatesData is used in the file
ast-grep --pattern 'templatesData' packages/docs/pages/community/templates.mdx

# Also check the List component usage
ast-grep --pattern 'List' packages/docs/pages/community/templates.mdx

Length of output: 148


Script:

#!/bin/bash
# Check the content of the file to see how templatesData is used
rg -A 5 "templatesData" packages/docs/pages/community/templates.mdx

# Also check if similar imports are handled with error checking in other files
rg "import.*templates\.json" -A 3

Length of output: 623


Script:

#!/bin/bash
# Check the List component implementation
rg -l "components/List" packages/docs/
cat $(rg -l "components/List" packages/docs/)

Length of output: 5396


Script:

#!/bin/bash
# Find and check the List component implementation
fd -t f "List.(js|jsx|ts|tsx)" packages/docs/components/ -x cat {}

Length of output: 1127

Comment on lines 31 to 38
private senderAddress: string;
private developerAddress: string;

constructor(context: Context) {
this.context = context;
this.humanAddress = context.message.sender.address;
this.walletStorage = new LocalStorage();
this.cdpEncriptionKey = context.client.accountAddress;
this.isGroup = context.group !== undefined;
this.cdpEncriptionKey = process.env.COINBASE_API_KEY_PRIVATE_KEY as string;
this.senderAddress = context.message.sender.address;
this.developerAddress = context.client.accountAddress;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add validation for environment variables and fix typo

The property and constructor changes improve clarity, but there are some concerns:

  1. Direct access to environment variables without validation
  2. Typo in variable name "cdpEncriptionKey"

Apply these changes:

- private cdpEncriptionKey: string;
+ private cdpEncryptionKey: string;

  constructor(context: Context) {
    this.walletStorage = new LocalStorage();
-   this.cdpEncriptionKey = process.env.COINBASE_API_KEY_PRIVATE_KEY as string;
+   const encryptionKey = process.env.COINBASE_API_KEY_PRIVATE_KEY;
+   if (!encryptionKey) {
+     throw new Error('COINBASE_API_KEY_PRIVATE_KEY environment variable is required');
+   }
+   this.cdpEncryptionKey = encryptionKey;
    this.senderAddress = context.message.sender.address;
    this.developerAddress = context.client.accountAddress;
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private senderAddress: string;
private developerAddress: string;
constructor(context: Context) {
this.context = context;
this.humanAddress = context.message.sender.address;
this.walletStorage = new LocalStorage();
this.cdpEncriptionKey = context.client.accountAddress;
this.isGroup = context.group !== undefined;
this.cdpEncriptionKey = process.env.COINBASE_API_KEY_PRIVATE_KEY as string;
this.senderAddress = context.message.sender.address;
this.developerAddress = context.client.accountAddress;
private senderAddress: string;
private developerAddress: string;
private cdpEncryptionKey: string;
constructor(context: Context) {
this.walletStorage = new LocalStorage();
const encryptionKey = process.env.COINBASE_API_KEY_PRIVATE_KEY;
if (!encryptionKey) {
throw new Error('COINBASE_API_KEY_PRIVATE_KEY environment variable is required');
}
this.cdpEncryptionKey = encryptionKey;
this.senderAddress = context.message.sender.address;
this.developerAddress = context.client.accountAddress;

packages/message-kit/src/plugins/cdp.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@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

🔭 Outside diff range comments (3)
templates/gated-group/src/skills/gated.ts (3)

Line range hint 53-63: Fix critical issues in member addition logic

Several issues need to be addressed in the member addition logic:

  1. Missing input validation
  2. Potential race condition
  3. Missing await on addMembers
  4. Generic error messages
-        const added = await client.conversations.getConversationById(groupId);
-        if (added) {
-          added.addMembers([walletAddress]);
-          console.log(`Added wallet address: ${walletAddress} to the group`);
-          return "success";
-        } else {
-          return "error";
-        }
+        if (!walletAddress || !groupId) {
+          throw new Error("Invalid wallet address or group ID");
+        }
+        const conversation = await client.conversations.getConversationById(groupId);
+        if (!conversation) {
+          throw new Error(`Group not found: ${groupId}`);
+        }
+        await conversation.addMembers([walletAddress]);
+        console.log(`Successfully added ${walletAddress} to group ${groupId}`);
+        return "success";

Line range hint 71-85: Enhance server security and reliability

The server setup needs several security and reliability improvements:

  1. Missing input validation
  2. No rate limiting
  3. Missing CORS configuration
  4. No environment variable validation

Consider implementing these security measures:

+ import rateLimit from 'express-rate-limit';
+ import cors from 'cors';
+ import { z } from 'zod';

+ const envSchema = z.object({
+   PORT: z.string().optional().default('3000'),
+   URL: z.string().optional(),
+ });

+ const requestSchema = z.object({
+   walletAddress: z.string().regex(/^0x[a-fA-F0-9]{40}$/),
+   groupId: z.string().min(1),
+ });

  const app = express();
+ app.use(cors());
+ app.use(rateLimit({
+   windowMs: 15 * 60 * 1000, // 15 minutes
+   max: 100 // limit each IP to 100 requests per windowMs
+ }));
  app.use(express.json());
  app.post("/add-wallet", async (req, res) => {
    try {
+     const { walletAddress, groupId } = requestSchema.parse(req.body);
      const result = await addWalletToGroup(walletAddress, groupId);
      res.status(200).send(result);
    } catch (error: any) {
+     console.error('Request failed:', error);
+     res.status(400).json({
+       error: error instanceof z.ZodError ? 'Invalid input' : error.message
+     });
    }
  });

+ const env = envSchema.parse(process.env);
- const PORT = process.env.PORT || 3000;
- const url = process.env.URL || `http://localhost:${PORT}`;
+ const PORT = env.PORT;
+ const url = env.URL || `http://localhost:${PORT}`;

Based on the shell script results, I can now generate a final response. The verification revealed important security patterns in the codebase.

Security concerns identified in group member management

The codebase has proper admin-only restrictions for group creation, but there are potential security issues in the member addition flow:

  • The /add-wallet endpoint lacks authentication/authorization mechanisms
  • No rate limiting is implemented on the endpoint
  • The addMembers operation in addWalletToGroup function doesn't verify if the caller has admin privileges
  • While NFT ownership is verified via checkNft, there's no validation that the NFT hasn't been transferred after initial verification

Key locations needing attention:

  • templates/gated-group/src/skills/gated.ts: Add authentication middleware for the /add-wallet endpoint
  • templates/gated-group/src/skills/gated.ts: Implement admin permission check in addWalletToGroup function
  • templates/gated-group/src/skills/gated.ts: Add rate limiting to prevent abuse
🔗 Analysis chain

Line range hint 1-85: Verify XMTP client security patterns

Let's verify the security implications of XMTP client usage and group permissions across the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for XMTP client initialization and permission checks
echo "Checking XMTP client initialization patterns..."
rg -A 5 "new V3Client|createClient" 

echo "Checking group permission patterns..."
rg -A 5 "adminOnly|isAdmin|hasPermission"

echo "Checking group member validation..."
ast-grep --pattern 'addMembers($$$)'

Length of output: 8691

🧹 Nitpick comments (8)
packages/message-kit/src/index.ts (1)

Line range hint 1-13: Review XMTP export organization

The file now has XMTP-related exports scattered across different locations:

  1. Direct XMTP module exports (stream.js, client.js)
  2. Plugin export (plugins/xmtp.js)
  3. Third-party client exports (V2Client, V3Client)

This organization could be improved for better maintainability.

Consider consolidating all XMTP-related exports under the plugins directory:

-export * from "./xmtp/stream.js";
-export * from "./xmtp/client.js";
export * from "./lib/core.js";
export * from "./lib/skills.js";
export * from "./helpers/types.js";
export * from "./plugins/gpt.js";
export * from "./plugins/resolver.js";
export * from "./plugins/framekit.js";
export * from "./skills/concierge.js";
export * from "./plugins/xmtp.js";
-export { Client as V2Client } from "@xmtp/xmtp-js";
-export { Client as V3Client } from "@xmtp/node-sdk";

Then create a comprehensive XMTP plugin that re-exports everything:

// plugins/xmtp.js
export * from "../xmtp/stream.js";
export * from "../xmtp/client.js";
export { Client as V2Client } from "@xmtp/xmtp-js";
export { Client as V3Client } from "@xmtp/node-sdk";
packages/docs/pages/templates/circle-agent.mdx (2)

38-41: Consider more concise section heading

The current "End result" section could be more concise. Consider alternatives like "Output" or "Result" for better readability.

-## End result
+## Output
🧰 Tools
🪛 LanguageTool

[style] ~38-~38: ‘End result’ might be wordy. Consider a shorter alternative.
Context: ...ates/circle-agent/.env.example] ``` ## End result The end result is a prompt that the mo...

(EN_WORDINESS_PREMIUM_END_RESULT)


[style] ~40-~40: ‘end result’ might be wordy. Consider a shorter alternative.
Context: ...t/.env.example] ``` ## End result The end result is a prompt that the model can understa...

(EN_WORDINESS_PREMIUM_END_RESULT)


26-28: Consider expanding the Skills section

The Skills section could benefit from more detail about the Concierge skill's capabilities and how it implements the "Agent Wallet as a Service" functionality.

Consider adding:

  • Brief description of the Concierge skill's core features
  • Example usage scenarios
  • Key configuration options
templates/gated-group/src/skills/gated.ts (1)

Line range hint 29-31: Improve success message formatting and fix typo

The success message contains a typo and could be formatted better for readability.

-      `Group created!\n- ID: ${group?.id}\n- Group Frame URL: https://converse.xyz/group/${group?.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
+      `✅ Group Created Successfully!\n\n` +
+      `📋 Group Details:\n` +
+      `• ID: ${group?.id}\n` +
+      `• Group URL: https://converse.xyz/group/${group?.id}\n\n` +
+      `📱 This URL will deeplink to the group inside Converse.\n` +
+      `🔗 Share this URL with friends to invite them to the group!`,
packages/message-kit/src/plugins/xmtp.ts (3)

176-180: Simplify the getMessageById method for clarity

The current implementation of getMessageById unnecessarily uses .bind, which can be simplified for better readability.

Apply this diff to simplify the method:

- return this.client.conversations?.getMessageById?.bind(
-   this.client.conversations,
- )(reference);
+ return this.client.conversations?.getMessageById?.(reference);

233-236: Log errors in catch blocks for better debugging

In the addToGroup method, the error in the catch block is not logged. Logging errors helps with troubleshooting and understanding failure reasons.

Apply this diff to log the error:

} catch (error) {
+   console.error("Error adding to group:", error);
    return {
      code: 400,
      message: "Failed to add to group",
    };
}

137-150: Evaluate the necessity of the deprecated getV2MessageById method

The getV2MessageById method is marked as deprecated because it takes too long to execute. If it's no longer used, consider removing it to clean up the codebase. If it's still needed, explore optimizing it or providing an alternative solution.

packages/message-kit/src/xmtp/stream.ts (1)

Line range hint 34-120: Consider adding error handling for MessageKit initialization.

While the run function correctly sets hasInitialized, it might benefit from try-catch blocks around critical initialization steps.

Consider wrapping the initialization with error handling:

 export async function run(agent: Agent) {
+  try {
     hasInitialized = true;
     const { client, v2client } = await xmtpClient(agent.config, agent);
 
     const { inboxId: address } = client;
     const { address: addressV2 } = v2client;
 
     // sync and list conversations
     await client.conversations.sync();
     await client.conversations.list();
+  } catch (error) {
+    console.error('Failed to initialize MessageKit:', error);
+    hasInitialized = false;
+    throw error;
+  }
   // ... rest of the function
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b15c7da and 93f596d.

⛔ Files ignored due to path filters (1)
  • packages/docs/public/concierge.mp4 is excluded by !**/*.mp4
📒 Files selected for processing (27)
  • community/plugins.json (0 hunks)
  • package.json (1 hunks)
  • packages/create-message-kit/package.json (1 hunks)
  • packages/docs/components/Video.tsx (1 hunks)
  • packages/docs/pages/concepts/skills.mdx (1 hunks)
  • packages/docs/pages/concepts/xmtp.mdx (1 hunks)
  • packages/docs/pages/index.mdx (0 hunks)
  • packages/docs/pages/introduction.mdx (0 hunks)
  • packages/docs/pages/skills/concierge.mdx (2 hunks)
  • packages/docs/pages/skills/gated.mdx (2 hunks)
  • packages/docs/pages/templates/circle-agent.mdx (1 hunks)
  • packages/docs/pages/templates/paymentagent.mdx (0 hunks)
  • packages/docs/pages/ux/groups.mdx (0 hunks)
  • packages/docs/vocs.config.tsx (0 hunks)
  • packages/message-kit/package.json (1 hunks)
  • packages/message-kit/src/helpers/types.ts (1 hunks)
  • packages/message-kit/src/index.ts (1 hunks)
  • packages/message-kit/src/lib/core.ts (12 hunks)
  • packages/message-kit/src/lib/skills.ts (0 hunks)
  • packages/message-kit/src/plugins/resolver.ts (0 hunks)
  • packages/message-kit/src/plugins/xmtp.ts (1 hunks)
  • packages/message-kit/src/skills/concierge.ts (5 hunks)
  • packages/message-kit/src/xmtp/stream.ts (2 hunks)
  • packages/message-kit/tests/V2.test.ts (1 hunks)
  • templates/gated-group/src/plugins/xmtp.ts (0 hunks)
  • templates/gated-group/src/skills/gated.ts (3 hunks)
  • templates/playground/src/skills/gated.ts (0 hunks)
💤 Files with no reviewable changes (10)
  • packages/docs/pages/templates/paymentagent.mdx
  • packages/docs/pages/introduction.mdx
  • packages/docs/pages/ux/groups.mdx
  • templates/playground/src/skills/gated.ts
  • packages/message-kit/src/lib/skills.ts
  • templates/gated-group/src/plugins/xmtp.ts
  • packages/docs/vocs.config.tsx
  • packages/docs/pages/index.mdx
  • packages/message-kit/src/plugins/resolver.ts
  • community/plugins.json
✅ Files skipped from review due to trivial changes (4)
  • packages/message-kit/package.json
  • packages/create-message-kit/package.json
  • packages/docs/pages/skills/gated.mdx
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/message-kit/src/skills/concierge.ts
🧰 Additional context used
🪛 Biome (1.9.4)
packages/message-kit/src/lib/core.ts

[error] 87-87: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


[error] 120-120: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🪛 LanguageTool
packages/docs/pages/templates/circle-agent.mdx

[style] ~38-~38: ‘End result’ might be wordy. Consider a shorter alternative.
Context: ...ates/circle-agent/.env.example] ``` ## End result The end result is a prompt that the mo...

(EN_WORDINESS_PREMIUM_END_RESULT)


[style] ~40-~40: ‘end result’ might be wordy. Consider a shorter alternative.
Context: ...t/.env.example] ``` ## End result The end result is a prompt that the model can understa...

(EN_WORDINESS_PREMIUM_END_RESULT)

🔇 Additional comments (14)
packages/docs/pages/templates/circle-agent.mdx (3)

9-16: LGTM! Clear and conventional project structure

The directory structure follows TypeScript project conventions and clearly shows the essential files.


5-5: LGTM! Consistent terminology usage

The documentation correctly references the Circle plugin and maintains consistent terminology with the broader codebase changes.


23-23: Verify file inclusions exist and are accessible

Please ensure that all referenced files exist and are accessible:

  • templates/circle-agent/src/index.ts
  • templates/circle-agent/.env.example
  • templates/circle-agent/example_prompt.md

Also applies to: 35-35, 43-43

✅ Verification successful

All file inclusions are correctly referenced and accessible

All three referenced files exist in the expected locations:

  • templates/circle-agent/src/index.ts
  • templates/circle-agent/.env.example
  • templates/circle-agent/example_prompt.md
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify if the included files exist
echo "Checking for referenced files..."
for file in "templates/circle-agent/src/index.ts" "templates/circle-agent/.env.example" "templates/circle-agent/example_prompt.md"; do
  if fd -t f "$(basename $file)" templates/circle-agent; then
    echo "✓ Found: $file"
  else
    echo "✗ Missing: $file"
  fi
done

Length of output: 1181

packages/docs/pages/concepts/skills.mdx (2)

19-19: ⚠️ Potential issue

Remove outdated tip section about the user type

The documentation still contains a tip section explaining the user type, but this type has been removed from the parameter options. This creates inconsistency in the documentation.

Please remove the following tip section to maintain consistency:

-:::tip
-The type `user` is a special type that allows you to get the user's address resolving the username or ENS name. See more in the [Identities](/plugins/resolver) section.
-:::

Likely invalid or redundant comment.


19-19: Verify handler implementation compatibility

Since the user type has been removed from parameter types, we should verify that no existing skills rely on this type.

✅ Verification successful

The previous search might have been too restrictive. Let's broaden our search to catch any mentions of the "user" type and also look at the current parameter type patterns to better understand the context and potential impact of the removal.


Type removal verification complete - No compatibility issues found

Based on the comprehensive search results, there are no skills using the removed "user" type in the codebase. All parameter types found in the skills match the updated type definition ("string", "number", "username", "quoted", "address", "prompt", "url"). The removal of the "user" type is safe and doesn't affect any existing implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any skills using the removed "user" type
rg -l 'type:\s*"user"' --type ts

Length of output: 34


Script:

#!/bin/bash
# Let's try a broader search for "user" type in different contexts and file types
rg -i 'type.*"user"' 

# Also search for any skill parameter definitions to understand the usage patterns
rg -i 'type:.*("string"|"number"|"username"|"quoted"|"address"|"prompt"|"url"|"user")'

Length of output: 3197

packages/message-kit/src/helpers/types.ts (2)

96-96: Update CHANGELOG.md with breaking change

This change removes functionality that might be relied upon by existing implementations. Please ensure this breaking change is properly documented in the CHANGELOG.md.

Consider providing migration guidance for users who were previously using the "user" type. This could include:

  1. Alternative approaches to handle user resolution
  2. Migration examples
  3. Reason for the removal

96-96: ⚠️ Potential issue

Consider semantic versioning implications

The removal of the "user" type from SkillParamConfig is a breaking change that affects the public API. According to semantic versioning, this should trigger a major version bump (2.0.0) rather than a minor version bump (1.2.30).

packages/message-kit/src/lib/core.ts (1)

359-359: 🛠️ Refactor suggestion

Ensure consistent use of undefined instead of void

In the handler function used in awaitResponse, avoid returning void in the Promise<boolean | void> type. Replace void with undefined for consistency and to avoid confusion.

Apply this diff to the handler type definition:

- const handler = async (text: string): Promise<boolean | void> => {
+ const handler = async (text: string): Promise<boolean | undefined> => {

Likely invalid or redundant comment.

packages/docs/components/Video.tsx (1)

1-26: Component implementation looks good

The Video component is well-defined and correctly implements the required functionality. Props are properly handled, and the component should work as expected.

packages/message-kit/tests/V2.test.ts (1)

101-101: Update reflects refactoring to use XmtpPlugin

The change to use context.xmtp.getConversationKey() aligns with the refactoring effort to encapsulate XMTP functionalities within the XmtpPlugin. This ensures consistency across the codebase.

packages/docs/pages/concepts/xmtp.mdx (1)

107-107: LGTM! Documentation accurately reflects the updated API.

The example correctly demonstrates the new method of checking XMTP availability using context.xmtp.isOnXMTP(), which aligns with the modular architecture using the XmtpPlugin.

packages/docs/pages/skills/concierge.mdx (1)

1-10: LGTM! Documentation enhancement with media content.

The addition of the Video component and tweet reference improves the documentation by providing visual context and real-world examples.

packages/message-kit/src/xmtp/stream.ts (2)

81-81: LGTM! Consistent usage of the XmtpPlugin API.

The changes correctly use context.xmtp.getConversationKey() throughout the code, maintaining consistency with the new modular architecture.

Also applies to: 87-87, 97-97


Line range hint 15-33: LGTM! Improved developer experience with initialization warning.

The addition of initialization tracking and warning message helps developers identify and fix potential setup issues early. The warning includes helpful example code, which is a nice touch.

templates/gated-group/src/skills/gated.ts Show resolved Hide resolved
Comment on lines 182 to 188
async getLastMessageById(reference: string) {
let msg = await (this.version === "v3"
? this.getMessageById(reference)
: this.getV2MessageById(this.conversation.topic, reference));
msg = msg?.content;
return msg;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure this.conversation is defined before accessing topic

In the getLastMessageById method, this.conversation might be undefined, leading to a runtime error when accessing this.conversation.topic. Consider adding a null check to prevent potential crashes.

Apply this diff to check for this.conversation:

let msg = await (this.version === "v3"
  ? this.getMessageById(reference)
- : this.getV2MessageById(this.conversation.topic, reference));
+ : this.conversation
+   ? this.getV2MessageById(this.conversation.topic, reference)
+   : undefined);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getLastMessageById(reference: string) {
let msg = await (this.version === "v3"
? this.getMessageById(reference)
: this.getV2MessageById(this.conversation.topic, reference));
msg = msg?.content;
return msg;
}
async getLastMessageById(reference: string) {
let msg = await (this.version === "v3"
? this.getMessageById(reference)
: this.conversation
? this.getV2MessageById(this.conversation.topic, reference)
: undefined);
msg = msg?.content;
return msg;
}

packages/message-kit/src/plugins/xmtp.ts Outdated Show resolved Hide resolved
packages/message-kit/src/lib/core.ts Show resolved Hide resolved
@@ -128,7 +134,7 @@ async function notifyUser(
);

// Notify recipient if on XMTP
const { v2, v3 } = await context.isOnXMTP(toAddress);
const { v2, v3 } = await isOnXMTP(toAddress);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update isOnXMTP usage to match the new API pattern.

The current implementation uses a direct isOnXMTP() call, which differs from the documented pattern in xmtp.mdx that uses context.xmtp.isOnXMTP().

Apply this diff to align with the new API pattern:

-  const { v2, v3 } = await isOnXMTP(toAddress);
+  const { v2, v3 } = await context.xmtp.isOnXMTP(toAddress);

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

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

🔭 Outside diff range comments (2)
packages/message-kit/src/plugins/resolver.ts (1)

Line range hint 125-151: Enhance error handling for ENS data fetching.

Consider adding more robust error handling and logging for the ENS data fetching process.

 try {
   const response = await fetch(`https://ensdata.net/${keyToUse}`);
   if (response.status !== 200) {
-    if (process.env.MSG_LOG)
-      console.log("- ENS data request failed for", keyToUse);
+    console.warn(`ENS data request failed for ${keyToUse}: ${response.status} ${response.statusText}`);
+    if (response.status !== 404) {  // Don't retry on 404
+      // Consider implementing retry logic here
+    }
   } else {
     const ensData = (await response.json()) as EnsData;
packages/message-kit/src/plugins/circle.ts (1)

Line range hint 221-252: Add validation for swap parameters.

The new swap method needs input validation and error handling improvements.

 async swap(
   address: string,
   fromAssetId: string,
   toAssetId: string,
   amount: number,
 ): Promise<Trade | undefined> {
+  if (amount <= 0) {
+    throw new Error('Amount must be greater than 0');
+  }
+  if (!fromAssetId || !toAssetId) {
+    throw new Error('Asset IDs are required');
+  }
   address = address.toLowerCase();
♻️ Duplicate comments (3)
packages/message-kit/src/plugins/framekit.ts (1)

50-54: ⚠️ Potential issue

Breaking change: Add backward compatibility for sendReceipt

The new implementation requires an amount parameter which breaks existing callers.

+  // @deprecated Use sendReceipt(txLink: string, amount: number) instead
+  async sendReceipt(txLink: string): Promise<void>;
   async sendReceipt(txLink: string, amount: number) {
     if (!txLink) return;
     let receiptUrl = `${framesUrl}/receipt?networkId=${"base"}&txLink=${txLink}&amount=${amount}`;
     await this.context.dm(receiptUrl);
   }
packages/message-kit/src/plugins/cdp.ts (1)

37-40: ⚠️ Potential issue

Add validation for environment variables.

The environment variable handling needs validation.

packages/framekit/src/app/utils/networks.ts (1)

327-374: 🛠️ Refactor suggestion

Improve chain extraction logic.

The current implementation can be improved for better maintainability and robustness.

🧹 Nitpick comments (11)
packages/docs/pages/ux/frames.mdx (2)

14-16: Improve code block example

The URL example uses ellipsis which might be confusing. Consider providing a more concrete example or clarifying that it's a placeholder.

-Share in Farcaster (Framev2): https://frames.message-kit.org/dm/0x...
+Share in Farcaster (Framev2): https://frames.message-kit.org/dm/<agent-address>

20-20: Improve property description formatting and grammar

The property description needs better formatting and grammar.

-Could be converse profile name , ens name or address
+Can be a Converse profile name, ENS name, or Ethereum address
🧰 Tools
🪛 LanguageTool

[uncategorized] ~20-~20: Loose punctuation mark.
Context: .../0x... ``` Properties: - address: The address of the agent. Could be conv...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~20-~20: To form a complete sentence, be sure to include a subject or ‘there’.
Context: ... - address: The address of the agent. Could be converse profile name , ens name or ...

(MISSING_IT_THERE)

packages/message-kit/src/plugins/framekit.ts (2)

27-27: Consider making networkId configurable

The network ID is hardcoded to "base", which reduces flexibility and reusability.

-    let url = `${framesUrl}/wallet?networkId=${"base"}&agentAddress=${agentAddress}&ownerAddress=${ownerAddress}&balance=${balance}`;
+    let url = `${framesUrl}/wallet?networkId=${this.networkId || "base"}&agentAddress=${agentAddress}&ownerAddress=${ownerAddress}&balance=${balance}`;

33-34: Document default values in JSDoc

The default values for parameters should be documented for better API understanding.

+  /**
+   * Request a payment from a user
+   * @param to - Recipient address (default: "humanagent.eth")
+   * @param amount - Payment amount in USDC (default: 0.01)
+   * @param token - Token symbol (default: "usdc")
+   * @param onRampURL - Optional URL for fiat onramp
+   */
   async requestPayment(
     to: string = "humanagent.eth",
     amount: number = 0.01,
     token: string = "usdc",
     onRampURL?: string,
   )
packages/framekit/src/app/api/wallet/route.tsx (1)

57-57: Enhance error messaging for missing network parameters.

Consider providing more specific error messages to identify which network parameters are missing.

-    if (!networkName || !networkLogo || !tokenName) {
+    const missingParams = [];
+    if (!networkName) missingParams.push('networkName');
+    if (!networkLogo) missingParams.push('networkLogo');
+    if (!tokenName) missingParams.push('tokenName');
+    if (missingParams.length > 0) {
+      console.error(`Missing network parameters: ${missingParams.join(', ')}`);
packages/message-kit/src/helpers/utils.ts (2)

Line range hint 7-24: Consider implementing memory management for user interactions tracking.

The current implementation stores all user interactions in memory indefinitely. Consider:

  1. Implementing a maximum size limit for the Map
  2. Adding periodic cleanup of old entries
  3. Using a persistent storage solution for long-term tracking

110-116: Consolidate duplicate wallet service warning messages.

The same warning message is duplicated for both CDP and Circle wallet services. Consider extracting it to a constant.

+const WALLET_SERVICE_WARNING = 
+  `\t\t- Save wallets at your discretion.\n\t\t- An agent wallet will be available for every user.\n\t\t- Developers are responsible for their own wallets.`;

 if (process.env.COINBASE_API_KEY_NAME && process.env.COINBASE_API_KEY_PRIVATE_KEY) {
   console.warn("\t- ⚠️ CDP Wallet Service is enabled");
-  console.warn(
-    `\t\t- Save wallets at your discretion.\n\t\t- An agent wallet will be available for every user.\n\t\t- Developers are responsible for their own wallets.`,
-  );
+  console.warn(WALLET_SERVICE_WARNING);
 } else if (process.env.CIRCLE_API_KEY) {
   console.warn("\t- ⚠️ Circle Wallet Service is enabled");
-  console.warn(
-    `\t\t- Save wallets at your discretion.\n\t\t- An agent wallet will be available for every user.\n\t\t- Developers are responsible for their own wallets.`,
-  );
+  console.warn(WALLET_SERVICE_WARNING);
packages/message-kit/src/plugins/resolver.ts (2)

115-118: Extract hardcoded addresses to named constants.

Consider moving the hardcoded addresses to named constants at the top of the file for better maintainability.

+const KNOWN_ADDRESSES = {
+  ALIX: '0x3a044b218BaE80E5b9E16609443A192129A67BeA'.toLowerCase(),
+  BO: '0xbc3246461ab5e1682baE48fa95172CDf0689201a'.toLowerCase(),
+};

 if (key === "@alix") {
-  data.address = "0x3a044b218BaE80E5b9E16609443A192129A67BeA".toLowerCase();
+  data.address = KNOWN_ADDRESSES.ALIX;
   data.converseUsername = "alix";
 } else if (key === "@bo") {
-  data.address = "0xbc3246461ab5e1682baE48fa95172CDf0689201a".toLowerCase();
+  data.address = KNOWN_ADDRESSES.BO;
   data.converseUsername = "bo";

Line range hint 158-192: Consider making timeout duration configurable.

The timeout duration for Converse profile fetching is hardcoded to 5000ms. Consider making this configurable through environment variables or configuration options.

+const DEFAULT_FETCH_TIMEOUT = 5000;
+const FETCH_TIMEOUT = process.env.FETCH_TIMEOUT 
+  ? parseInt(process.env.FETCH_TIMEOUT, 10) 
+  : DEFAULT_FETCH_TIMEOUT;

 const response = await fetchWithTimeout(
   converseEndpoint,
   {
     method: "POST",
     headers: {
       "Content-Type": "application/json",
       Accept: "application/json",
     },
     body: JSON.stringify({ peer: username }),
   },
-  5000,
+  FETCH_TIMEOUT,
 );
packages/message-kit/src/plugins/circle.ts (1)

Line range hint 69-104: Add error handling for wallet creation.

The wallet creation logic looks good, but consider adding specific error handling for common failure scenarios.

 async createWallet(identifier: string): Promise<AgentWalletData> {
   try {
     const normalizedIdentifier = identifier.toLowerCase();
     console.log(`Creating new wallet with id ${normalizedIdentifier}...`);
+    if (!coinbase) {
+      throw new Error('Coinbase client not initialized');
+    }
     const response = await client?.createWallets({
packages/message-kit/src/plugins/cdp.ts (1)

36-36: Verify wallet count usage.

The getWalletCount call result is not being used. Consider storing or logging the result.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af76a11 and 3ba6167.

📒 Files selected for processing (23)
  • packages/docs/pages/skills/concierge.mdx (5 hunks)
  • packages/docs/pages/ux/frames.mdx (1 hunks)
  • packages/framekit/README.md (1 hunks)
  • packages/framekit/src/app/api/payment/route.tsx (4 hunks)
  • packages/framekit/src/app/api/receipt/route.tsx (7 hunks)
  • packages/framekit/src/app/api/wallet/route.tsx (5 hunks)
  • packages/framekit/src/app/generator/page.tsx (0 hunks)
  • packages/framekit/src/app/payment/page.tsx (3 hunks)
  • packages/framekit/src/app/receipt/page.tsx (2 hunks)
  • packages/framekit/src/app/utils/networks.ts (1 hunks)
  • packages/framekit/src/app/wallet/page.tsx (2 hunks)
  • packages/framekit/src/components/PaymentFrame.tsx (2 hunks)
  • packages/message-kit/src/helpers/utils.ts (1 hunks)
  • packages/message-kit/src/plugins/cdp.ts (10 hunks)
  • packages/message-kit/src/plugins/circle.ts (5 hunks)
  • packages/message-kit/src/plugins/framekit.ts (2 hunks)
  • packages/message-kit/src/plugins/gpt.ts (1 hunks)
  • packages/message-kit/src/plugins/resolver.ts (3 hunks)
  • packages/message-kit/src/plugins/storage.ts (2 hunks)
  • packages/message-kit/src/skills/concierge.ts (5 hunks)
  • packages/message-kit/tests/Frames.test.ts (2 hunks)
  • templates/paymentagent/example_prompt.md (1 hunks)
  • templates/playground/src/skills/drip.ts (3 hunks)
💤 Files with no reviewable changes (1)
  • packages/framekit/src/app/generator/page.tsx
✅ Files skipped from review due to trivial changes (1)
  • templates/paymentagent/example_prompt.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/message-kit/tests/Frames.test.ts
  • templates/playground/src/skills/drip.ts
  • packages/message-kit/src/skills/concierge.ts
  • packages/docs/pages/skills/concierge.mdx
🧰 Additional context used
🪛 LanguageTool
packages/docs/pages/ux/frames.mdx

[uncategorized] ~20-~20: Loose punctuation mark.
Context: .../0x... ``` Properties: - address: The address of the agent. Could be conv...

(UNLIKELY_OPENING_PUNCTUATION)


[style] ~20-~20: To form a complete sentence, be sure to include a subject or ‘there’.
Context: ... - address: The address of the agent. Could be converse profile name , ens name or ...

(MISSING_IT_THERE)

🪛 Gitleaks (8.21.2)
packages/framekit/src/app/utils/networks.ts

28-28: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


43-43: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


58-58: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


73-73: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


88-88: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


103-103: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


118-118: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


133-133: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


148-148: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


163-163: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


178-178: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


194-194: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


210-210: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


225-225: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


241-241: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


256-256: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


273-273: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


290-290: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


306-306: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


321-321: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (19)
packages/docs/pages/ux/frames.mdx (3)

1-2: LGTM!

The imports are correctly defined and match the components used in the document.


8-8: Video file path case mismatch

The video file exists at packages/docs/public/videos/frames.MP4, but it's referenced with a different case in the path.

-<Video src="/videos/frames.MP4" />
+<Video src="/videos/frames.mp4" />

26-33: LGTM!

The CustomHomePage components are properly structured with appropriate props.

packages/message-kit/src/plugins/gpt.ts (1)

297-297: Verify the use of random memory keys in recursive calls

In the recursive calls to textGeneration and checkIntent, a new memoryKey is generated using Math.random().toString(36).substring(2, 12). This means each attempt uses a different chat history, potentially losing context from previous interactions. Verify if this behavior is intentional. If maintaining conversation context is important, consider reusing the original memoryKey to preserve the chat history across attempts.

Also applies to: 312-312

packages/framekit/README.md (1)

1-3: Verify the external documentation link is accessible

The documentation now redirects to an external site. Let's ensure the link is valid and accessible.

✅ Verification successful

External documentation link is accessible and valid

The link https://message-kit.org/plugins/framekit returns a successful HTTP 200 response with proper HTML content, confirming it's a valid and accessible documentation resource.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the external documentation link
curl -I https://message-kit.org/plugins/framekit

Length of output: 946

packages/message-kit/src/plugins/storage.ts (1)

20-20: Consider data migration for case-insensitive keys

The change to lowercase keys is good for consistency, but could break access to existing data. Consider adding a migration script or backward compatibility check.

Also applies to: 26-26, 35-35

packages/framekit/src/app/receipt/page.tsx (2)

6-11: Remove async/await from client component

The component is still using async/await which could cause issues in client components.


26-31: Add validation for txLink before redirect

Direct URL redirection without validation poses a security risk.

packages/framekit/src/app/api/receipt/route.tsx (1)

17-25: 🛠️ Refactor suggestion

Improve error handling for search parameters

The current implementation could be more robust in handling invalid parameters.

   let searchParams = req.nextUrl.searchParams;
+  const txLink = searchParams.get("txLink");
+  if (!txLink || !txLink.startsWith("http")) {
+    return new ImageResponse(
+      (<div>Invalid transaction link</div>),
+      { width: 500, height: 500 }
+    );
+  }
   let params = {
     amount: searchParams.get("amount") ?? "",
     networkId:
       searchParams.get("networkId") ?? searchParams.get("networkid") ?? "base",
   };
+  if (!params.amount || isNaN(parseFloat(params.amount))) {
+    return new ImageResponse(
+      (<div>Invalid amount</div>),
+      { width: 500, height: 500 }
+    );
+  }

Likely invalid or redundant comment.

packages/framekit/src/app/wallet/page.tsx (1)

32-34: Verify network ID handling across the application

The code extracts chainId and tokenAddress from networkId, but we should verify this is handled consistently across the application.

✅ Verification successful

Let me gather more information about the implementation of extractFrameChain to verify its consistency.


Let me search for the actual implementation of extractFrameChain function to verify its consistency.


Let me try one final search to locate the complete implementation of extractFrameChain.


Network ID handling is consistent across the application

The extractFrameChain function is consistently used throughout the application to handle network IDs. The implementation:

  • Uses a well-defined Network type with all necessary chain properties
  • Maintains a centralized network configuration database
  • Properly extracts chainId and tokenAddress for all supported networks
  • Has consistent error handling with a default fallback
  • Is used uniformly across wallet, payment, and receipt routes

The usage pattern in the reviewed code matches the intended implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for networkId usage and chain extraction
echo "Checking networkId parameter handling:"
rg -l 'networkId|networkid' --type ts --type tsx

echo "\nChecking extractFrameChain usage:"
rg -l 'extractFrameChain' --type ts --type tsx

echo "\nChecking chain extraction patterns:"
ast-grep --pattern 'extractFrameChain($_)'

Length of output: 1233


Script:

#!/bin/bash
# Find the implementation of extractFrameChain
ast-grep --pattern 'function extractFrameChain($_) {
  $$$
}'

# Also search for interface or type definitions related to chain extraction
ast-grep --pattern 'type $_ = {
  chainId: $_,
  $$$
}'

# Search for any chain-related constants or configurations
rg 'chainId.*=' -A 3

Length of output: 3173


Script:

#!/bin/bash
# Find files that might contain the extractFrameChain implementation
fd extractFrameChain --type f --exec cat {}

# Also look for any chain-related utility files
fd 'chain|network' --type f --exec head -n 20 {}

Length of output: 591


Script:

#!/bin/bash
# Search for the complete implementation using ripgrep with context
rg -U "export.*function.*extractFrameChain" -A 20

# Also try to find any network configuration files
fd "networks?" --type f --exec cat {}

Length of output: 13259

packages/framekit/src/app/api/wallet/route.tsx (1)

Line range hint 7-33: LGTM! Improved parameter handling.

The changes enhance robustness by:

  • Centralizing network data extraction through extractFrameChain
  • Adding case-insensitive parameter extraction for better user experience
packages/message-kit/src/plugins/resolver.ts (1)

185-186: LGTM! Address normalization is consistently applied.

The changes ensure consistent address handling throughout the codebase.

packages/message-kit/src/plugins/circle.ts (4)

48-51: LGTM! Constructor changes improve clarity.

The renaming from humanAddress to senderAddress and direct initialization from context improves code clarity.


123-125: LGTM! Address normalization is consistent.

The normalization of addresses to lowercase is consistent with other methods.


Line range hint 255-255: LGTM! Consistent address handling.

The address normalization in deleteWallet is consistent with other methods.


56-66: Verify wallet data consistency.

The method now normalizes addresses to lowercase, which is good for consistency. However, ensure that the wallet data structure in LocalStorage is compatible with this change.

✅ Verification successful

The previous pattern didn't match because it was too specific. Let's try with broader patterns to understand the wallet data structure, storage operations, and usage patterns. This will help us verify the consistency of wallet data handling with the lowercase normalization.


Wallet data storage is consistent with lowercase normalization

The verification shows that wallet data handling is consistent with lowercase normalization:

  • In circle.ts, when storing wallet data:
    • Addresses are normalized using toLowerCase() before being used as storage keys (wallet:${normalizedAddress})
    • The stored wallet address is also explicitly converted to lowercase: address: wallet.address.toLowerCase()
  • In cdp.ts, a different encryption-based approach is used, but it also maintains consistency by lowercasing keys
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check wallet data structure in LocalStorage
ast-grep --pattern 'await this.walletStorage.get($address)'

Length of output: 61


Script:

#!/bin/bash
# Search for wallet storage related patterns
ast-grep --pattern 'this.walletStorage.set($$$)'

# Search for wallet data structure
ast-grep --pattern 'interface AgentWalletData {
  $$$
}'

# Search for wallet creation
ast-grep --pattern 'createWallet($$$) {
  $$$
}'

# Search for other wallet storage usages
rg "walletStorage" -A 3

Length of output: 3755

packages/message-kit/src/plugins/cdp.ts (2)

31-32: LGTM! Property renaming improves clarity.

The renaming from humanAddress to senderAddress and isGroup to developerAddress improves code clarity.


41-42: LGTM! Consistent address normalization.

The normalization of addresses to lowercase is consistent across the codebase.

packages/framekit/src/app/utils/networks.ts (1)

1-15: LGTM! Well-structured type definition.

The Network type is well-defined with all necessary properties for blockchain network configuration.

packages/docs/pages/ux/frames.mdx Outdated Show resolved Hide resolved
Comment on lines 278 to 314
attempts: number = 0,
) {
const MAX_ATTEMPTS = 10;
const intentDetected = reply.toLowerCase().includes("moment");
const hasValidCommand = reply.includes("\n/") || reply.startsWith("/");

if (intentDetected && !hasValidCommand) {
console.log("Intent detected but missing command:");
if (attempts >= MAX_ATTEMPTS) {
return "I apologize, but I'm having trouble processing your request correctly. Please try rephrasing your question or ask for a different task.";
}

if (intentDetected && !hasValidCommand) {
const fixPrompt = `You indicated you would perform an action by saying "One moment" but didn't include the proper command.
Your previous response was: "${reply}" to the users prompt: "${userPrompt}"
Please provide your response again with the exact command starting with / on a new line.
Remember: Commands must be on their own line starting with /.`;

// Request a fix with the fix prompt using temporary memory
const { reply: fixedReply } = await textGeneration(
fixPrompt,
systemPrompt,
memoryKey,
Math.random().toString(36).substring(2, 12),
);

if (process.env.MSG_LOG)
console.log("Intent detected but missing command", {
reply,
fixPrompt,
fixedReply,
});
// Verify the fixed reply has a command

if (!fixedReply.includes("/")) {
chatMemory.clear(memoryKey);
return "I apologize, but I'm having trouble formatting the command correctly. Please try rephrasing your request.";
return checkIntent(
systemPrompt,
userPrompt,
fixedReply,
Math.random().toString(36).substring(2, 12),
attempts + 1,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor recursive calls to iterative loop to prevent potential stack overflow

The checkIntent function currently uses recursion to handle retry attempts when the reply lacks a valid command. While the recursion is bounded by MAX_ATTEMPTS, using recursion can lead to a stack overflow error if the limit is increased or in environments with limited call stack size. Refactoring the logic to use an iterative loop enhances the robustness and prevents potential stack issues.

Apply this diff to refactor the function:

 export async function checkIntent(
   systemPrompt: string,
   userPrompt: string,
   reply: string,
   memoryKey: string,
-  attempts: number = 0,
 ) {
+  let attempts = 0;
   const MAX_ATTEMPTS = 10;

-  if (attempts >= MAX_ATTEMPTS) {
-    return "I apologize, but I'm having trouble processing your request correctly. Please try rephrasing your question or ask for a different task.";
-  }

-  if (intentDetected && !hasValidCommand) {
-    const fixPrompt = `You indicated you would perform an action by saying "One moment" but didn't include the proper command. 
-Your previous response was: "${reply}" to the users prompt: "${userPrompt}"
-Please provide your response again with the exact command starting with / on a new line. 
-Remember: Commands must be on their own line starting with /.`;
-
-    const { reply: fixedReply } = await textGeneration(
-      fixPrompt,
-      systemPrompt,
-      Math.random().toString(36).substring(2, 12),
-    );
-
-    if (process.env.MSG_LOG)
-      console.log("Intent detected but missing command", {
-        reply,
-        fixPrompt,
-        fixedReply,
-      });
-
-    if (!fixedReply.includes("/")) {
-      return checkIntent(
-        systemPrompt,
-        userPrompt,
-        fixedReply,
-        Math.random().toString(36).substring(2, 12),
-        attempts + 1,
-      );
-    }
-
-    return fixedReply;
-  }
-
-  return reply;
+  while (attempts < MAX_ATTEMPTS) {
+    const intentDetected = reply.toLowerCase().includes("moment");
+    const hasValidCommand = reply.includes("\n/") || reply.startsWith("/");
+
+    if (intentDetected && !hasValidCommand) {
+      const fixPrompt = `You indicated you would perform an action by saying "One moment" but didn't include the proper command. 
+Your previous response was: "${reply}" to the users prompt: "${userPrompt}"
+Please provide your response again with the exact command starting with / on a new line. 
+Remember: Commands must be on their own line starting with /.`;
+
+      const { reply: fixedReply } = await textGeneration(
+        fixPrompt,
+        systemPrompt,
+        Math.random().toString(36).substring(2, 12),
+      );
+
+      if (process.env.MSG_LOG)
+        console.log("Intent detected but missing command", {
+          reply,
+          fixPrompt,
+          fixedReply,
+        });
+
+      if (fixedReply.includes("/")) {
+        return fixedReply;
+      } else {
+        reply = fixedReply;
+        attempts += 1;
+        continue;
+      }
+    } else {
+      return reply;
+    }
+  }
+
+  return "I apologize, but I'm having trouble processing your request correctly. Please try rephrasing your question or ask for a different task.";
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
attempts: number = 0,
) {
const MAX_ATTEMPTS = 10;
const intentDetected = reply.toLowerCase().includes("moment");
const hasValidCommand = reply.includes("\n/") || reply.startsWith("/");
if (intentDetected && !hasValidCommand) {
console.log("Intent detected but missing command:");
if (attempts >= MAX_ATTEMPTS) {
return "I apologize, but I'm having trouble processing your request correctly. Please try rephrasing your question or ask for a different task.";
}
if (intentDetected && !hasValidCommand) {
const fixPrompt = `You indicated you would perform an action by saying "One moment" but didn't include the proper command.
Your previous response was: "${reply}" to the users prompt: "${userPrompt}"
Please provide your response again with the exact command starting with / on a new line.
Remember: Commands must be on their own line starting with /.`;
// Request a fix with the fix prompt using temporary memory
const { reply: fixedReply } = await textGeneration(
fixPrompt,
systemPrompt,
memoryKey,
Math.random().toString(36).substring(2, 12),
);
if (process.env.MSG_LOG)
console.log("Intent detected but missing command", {
reply,
fixPrompt,
fixedReply,
});
// Verify the fixed reply has a command
if (!fixedReply.includes("/")) {
chatMemory.clear(memoryKey);
return "I apologize, but I'm having trouble formatting the command correctly. Please try rephrasing your request.";
return checkIntent(
systemPrompt,
userPrompt,
fixedReply,
Math.random().toString(36).substring(2, 12),
attempts + 1,
);
export async function checkIntent(
systemPrompt: string,
userPrompt: string,
reply: string,
memoryKey: string,
) {
let attempts = 0;
const MAX_ATTEMPTS = 10;
while (attempts < MAX_ATTEMPTS) {
const intentDetected = reply.toLowerCase().includes("moment");
const hasValidCommand = reply.includes("\n/") || reply.startsWith("/");
if (intentDetected && !hasValidCommand) {
const fixPrompt = `You indicated you would perform an action by saying "One moment" but didn't include the proper command.
Your previous response was: "${reply}" to the users prompt: "${userPrompt}"
Please provide your response again with the exact command starting with / on a new line.
Remember: Commands must be on their own line starting with /.`;
const { reply: fixedReply } = await textGeneration(
fixPrompt,
systemPrompt,
Math.random().toString(36).substring(2, 12),
);
if (process.env.MSG_LOG)
console.log("Intent detected but missing command", {
reply,
fixPrompt,
fixedReply,
});
if (fixedReply.includes("/")) {
return fixedReply;
} else {
reply = fixedReply;
attempts += 1;
continue;
}
} else {
return reply;
}
}
return "I apologize, but I'm having trouble processing your request correctly. Please try rephrasing your question or ask for a different task.";
}

packages/message-kit/src/plugins/storage.ts Outdated Show resolved Hide resolved
packages/framekit/src/app/receipt/page.tsx Show resolved Hide resolved
Comment on lines +48 to +51
const { chainId, networkName, tokenName, networkLogo, tokenAddress } =
extractFrameChain(params.networkId);
const amountUint256 = parseUnits(params.amount.toString(), 6);
const ethereumUrl = `ethereum:${params.tokenAddress}@${params.chainId}/transfer?address=${params.recipientAddress}&uint256=${amountUint256}`;
const ethereumUrl = `ethereum:${tokenAddress}@${chainId}/transfer?address=${params.recipientAddress}&uint256=${amountUint256}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add error handling for chain extraction

The chain extraction lacks error handling for invalid network IDs.

-    const { chainId, networkName, tokenName, networkLogo, tokenAddress } =
-      extractFrameChain(params.networkId);
+    const chainData = extractFrameChain(params.networkId);
+    if (!chainData) {
+      throw new Error(`Unsupported network: ${params.networkId}`);
+    }
+    const { chainId, networkName, tokenName, networkLogo, tokenAddress } = chainData;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { chainId, networkName, tokenName, networkLogo, tokenAddress } =
extractFrameChain(params.networkId);
const amountUint256 = parseUnits(params.amount.toString(), 6);
const ethereumUrl = `ethereum:${params.tokenAddress}@${params.chainId}/transfer?address=${params.recipientAddress}&uint256=${amountUint256}`;
const ethereumUrl = `ethereum:${tokenAddress}@${chainId}/transfer?address=${params.recipientAddress}&uint256=${amountUint256}`;
const chainData = extractFrameChain(params.networkId);
if (!chainData) {
throw new Error(`Unsupported network: ${params.networkId}`);
}
const { chainId, networkName, tokenName, networkLogo, tokenAddress } = chainData;
const amountUint256 = parseUnits(params.amount.toString(), 6);
const ethereumUrl = `ethereum:${tokenAddress}@${chainId}/transfer?address=${params.recipientAddress}&uint256=${amountUint256}`;

Comment on lines +136 to +142
src={networkLogo}
style={{
borderRadius: "25px",
width: "30px",
}}
/>
<div style={{ fontSize: "24px" }}>{params.networkName}</div>
<div style={{ fontSize: "24px" }}>{networkName}</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Validate external image URLs

The networkLogo URL is being used directly in the img tag without validation, which could pose a security risk.

+              // Validate and sanitize the logo URL
+              src={validateImageUrl(networkLogo)}
-              src={networkLogo}
               style={{
                 borderRadius: "25px",
                 width: "30px",
               }}
             />

+function validateImageUrl(url: string): string {
+  const allowedDomains = ['cdn.example.com']; // Add your allowed domains
+  try {
+    const parsed = new URL(url);
+    if (!allowedDomains.some(domain => parsed.hostname.endsWith(domain))) {
+      throw new Error('Invalid image domain');
+    }
+    return url;
+  } catch {
+    return '/default-network-logo.png'; // Fallback to default
+  }
+}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +29 to +40
let searchParams = req.nextUrl.searchParams;
let params = {
url: process.env.NEXT_PUBLIC_URL,
networkLogo: req.nextUrl.searchParams.get("networkLogo"),
amount: req.nextUrl.searchParams.get("amount") ?? "1",
networkName: req.nextUrl.searchParams.get("networkName") ?? "base",
tokenName: req.nextUrl.searchParams.get("tokenName") ?? "",
recipientAddress: req.nextUrl.searchParams.get("recipientAddress"),
tokenAddress: req.nextUrl.searchParams.get("tokenAddress"),
chainId: req.nextUrl.searchParams.get("chainId"),
networkId: req.nextUrl.searchParams.get("networkId"),
amount: searchParams.get("amount") ?? "1",
recipientAddress:
searchParams.get("recipientAddress") ??
searchParams.get("recipientaddress") ??
"",
networkId:
searchParams.get("networkId") ??
searchParams.get("networkid") ??
"base",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enhance parameter validation and sanitization

The current parameter handling lacks proper validation and sanitization, which could lead to security issues.

 let params = {
   url: process.env.NEXT_PUBLIC_URL,
-  amount: searchParams.get("amount") ?? "1",
+  amount: validateAmount(searchParams.get("amount") ?? "1"),
   recipientAddress:
-    searchParams.get("recipientAddress") ??
-    searchParams.get("recipientaddress") ??
-    "",
+    validateAddress(
+      searchParams.get("recipientAddress") ??
+      searchParams.get("recipientaddress") ??
+      ""
+    ),
   networkId:
-    searchParams.get("networkId") ??
-    searchParams.get("networkid") ??
-    "base",
+    validateNetworkId(
+      searchParams.get("networkId") ??
+      searchParams.get("networkid") ??
+      "base"
+    ),
 };

+function validateAmount(amount: string): string {
+  const parsed = parseFloat(amount);
+  if (isNaN(parsed) || parsed <= 0) {
+    throw new Error("Invalid amount");
+  }
+  return amount;
+}

+function validateAddress(address: string): string {
+  if (!/^0x[a-fA-F0-9]{40}$/.test(address)) {
+    throw new Error("Invalid address");
+  }
+  return address.toLowerCase();
+}

+function validateNetworkId(networkId: string): string {
+  const validNetworks = ["base", "ethereum", "polygon"];
+  if (!validNetworks.includes(networkId.toLowerCase())) {
+    throw new Error("Invalid network");
+  }
+  return networkId.toLowerCase();
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let searchParams = req.nextUrl.searchParams;
let params = {
url: process.env.NEXT_PUBLIC_URL,
networkLogo: req.nextUrl.searchParams.get("networkLogo"),
amount: req.nextUrl.searchParams.get("amount") ?? "1",
networkName: req.nextUrl.searchParams.get("networkName") ?? "base",
tokenName: req.nextUrl.searchParams.get("tokenName") ?? "",
recipientAddress: req.nextUrl.searchParams.get("recipientAddress"),
tokenAddress: req.nextUrl.searchParams.get("tokenAddress"),
chainId: req.nextUrl.searchParams.get("chainId"),
networkId: req.nextUrl.searchParams.get("networkId"),
amount: searchParams.get("amount") ?? "1",
recipientAddress:
searchParams.get("recipientAddress") ??
searchParams.get("recipientaddress") ??
"",
networkId:
searchParams.get("networkId") ??
searchParams.get("networkid") ??
"base",
let searchParams = req.nextUrl.searchParams;
let params = {
url: process.env.NEXT_PUBLIC_URL,
amount: validateAmount(searchParams.get("amount") ?? "1"),
recipientAddress:
validateAddress(
searchParams.get("recipientAddress") ??
searchParams.get("recipientaddress") ??
""
),
networkId:
validateNetworkId(
searchParams.get("networkId") ??
searchParams.get("networkid") ??
"base"
),
function validateAmount(amount: string): string {
const parsed = parseFloat(amount);
if (isNaN(parsed) || parsed <= 0) {
throw new Error("Invalid amount");
}
return amount;
}
function validateAddress(address: string): string {
if (!/^0x[a-fA-F0-9]{40}$/.test(address)) {
throw new Error("Invalid address");
}
return address.toLowerCase();
}
function validateNetworkId(networkId: string): string {
const validNetworks = ["base", "ethereum", "polygon"];
if (!validNetworks.includes(networkId.toLowerCase())) {
throw new Error("Invalid network");
}
return networkId.toLowerCase();
}

Comment on lines +50 to +54
const { networkLogo, networkName, tokenName, chainId, tokenAddress } =
extractFrameChain(params.networkId as string);

const ethereumUrl = `ethereum:${tokenAddress}@${chainId}/transfer?address=${params.agentAddress}`;

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for invalid networkId.

While the network data extraction is improved, consider adding explicit error handling for invalid networkId values before destructuring the result.

-    const { networkLogo, networkName, tokenName, chainId, tokenAddress } =
-      extractFrameChain(params.networkId as string);
+    const chainData = extractFrameChain(params.networkId as string);
+    if (!chainData) {
+      throw new Error(`Invalid network ID: ${params.networkId}`);
+    }
+    const { networkLogo, networkName, tokenName, chainId, tokenAddress } = chainData;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { networkLogo, networkName, tokenName, chainId, tokenAddress } =
extractFrameChain(params.networkId as string);
const ethereumUrl = `ethereum:${tokenAddress}@${chainId}/transfer?address=${params.agentAddress}`;
const chainData = extractFrameChain(params.networkId as string);
if (!chainData) {
throw new Error(`Invalid network ID: ${params.networkId}`);
}
const { networkLogo, networkName, tokenName, chainId, tokenAddress } = chainData;
const ethereumUrl = `ethereum:${tokenAddress}@${chainId}/transfer?address=${params.agentAddress}`;

Comment on lines +16 to +325
isActive: true,
balance: "0.03",
},
{
networkId: "scroll_sepolia",
networkName: "Scroll Sepolia",
networkLogo:
"https://pbs.twimg.com/profile_images/1696533090683011075/46xlNPQR_400x400.jpg",
tokenName: "ETH",
dripAmount: 0.01,
address: "0x625BCC1142E97796173104A6e817Ee46C593b3C5",
isERC20: false,
erc20Address: undefined,
erc20Decimals: undefined,
chainId: 1115,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
isActive: true,
balance: "6.42",
},
{
networkId: "stacks",
networkName: "Stacks Testnet",
networkLogo: "https://cryptologos.cc/logos/stacks-stx-logo.png",
tokenName: "STX",
dripAmount: 1,
address: "ST4HMZRS8XSTGEPQXNKXFAY9T45HMS4FE72Q3ED0",
isERC20: false,
erc20Address: undefined,
erc20Decimals: undefined,
chainId: 1115,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
isActive: true,
balance: "907.42",
},
{
networkId: "starknet_sepolia",
networkName: "Starknet Sepolia",
networkLogo:
"https://pbs.twimg.com/profile_images/1834202903189618688/N4J8emeY_400x400.png",
tokenName: "ETH",
dripAmount: 0.001,
address:
"0x012b6781F1Fbe402F75efacDD4D90bb22c69c0172b7d34bB5233854631Ca3272",
isERC20: false,
erc20Address: undefined,
erc20Decimals: undefined,
chainId: 1115,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
isActive: true,
balance: "99.64",
},
{
networkId: "sui_testnet",
networkName: "Sui Testnet",
networkLogo:
"https://suifoundation.notion.site/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F25d4a7b2-cc43-4d0f-8b5e-7f840eef1508%2FSui_Droplet_Logo_Blue.png?table=block&id=cd93d06a-6ec4-474e-8a35-a09f4e86c3f6&spaceId=279a541f-304a-4674-a846-6f35af6d2aab&width=1570&userId=&cache=v2",
tokenName: "SUI",
dripAmount: 0.5,
address:
"0xda593ab6a600ccf74e9dc1f2ef0f7ba852bf29bcc92d91e302c33c883b333432",
isERC20: false,
erc20Address: undefined,
erc20Decimals: undefined,
chainId: 1115,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
isActive: true,
balance: "0.00",
},
{
networkId: "zksync_sepolia",
networkName: "zkSync Era Sepolia",
networkLogo:
"https://pbs.twimg.com/profile_images/1835668010951950336/Aq1Kg1p0_400x400.jpg",
tokenName: "ETH",
dripAmount: 0.01,
address: "0x625BCC1142E97796173104A6e817Ee46C593b3C5",
isERC20: false,
erc20Address: undefined,
erc20Decimals: undefined,
chainId: 1115,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
isActive: true,
balance: "369.47",
},
{
networkId: "zora_sepolia",
networkName: "Zora Sepolia",
networkLogo: "https://docs.zora.co/zoraOrb.svg",
tokenName: "zsETH",
dripAmount: 0.01,
address: "0x625BCC1142E97796173104A6e817Ee46C593b3C5",
isERC20: false,
erc20Address: undefined,
erc20Decimals: undefined,
chainId: 1115,
tokenAddress: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
isActive: true,
balance: "7.85",
},
];
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Critical configuration issues found in network settings

Several critical issues need to be addressed in the networks configuration:

  • Multiple networks incorrectly share the same chainId (1115): berachain_artio, holesky, eth, sepolia, flow, mode_sepolia, optimism_sepolia, polygon_amoy, scroll_sepolia, stacks, starknet_sepolia, sui_testnet, zksync_sepolia, and zora_sepolia
  • The same tokenAddress (0x036CbD53842c5426634e7929541eC2318f3dCF7e) is reused across multiple different networks and tokens
  • Base Sepolia and Base Goerli share the same chainId (84532)

Recommendations:

  • Update chainIds to their correct network-specific values
  • Verify and update tokenAddress values to be network-specific
  • Consider moving sensitive configuration to environment variables
🔗 Analysis chain

Review and secure token addresses.

The static analysis tool flags multiple token addresses as potential API keys. While these are false positives, some security considerations are needed:

  1. Verify the token addresses are correct for each network
  2. Consider moving sensitive configuration to environment variables

Let me analyze the token addresses in the networks configuration. I'll search for any potential inconsistencies in chainIds and verify token addresses across networks.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify token addresses format
rg -e '0x[a-fA-F0-9]{40}' --type ts

Length of output: 8215


Script:

#!/bin/bash
# Search for chainId 1115 which appears multiple times
rg "chainId: 1115" --type ts -C 5

# Search for the repeated tokenAddress
rg "0x036CbD53842c5426634e7929541eC2318f3dCF7e" --type ts -C 5

Length of output: 23896

🧰 Tools
🪛 Gitleaks (8.21.2)

28-28: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


43-43: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


58-58: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


73-73: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


88-88: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


103-103: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


118-118: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


133-133: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


148-148: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


163-163: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


178-178: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


194-194: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


210-210: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


225-225: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


241-241: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


256-256: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


273-273: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


290-290: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


306-306: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


321-321: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

Copy link
Contributor

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

🔭 Outside diff range comments (2)
packages/message-kit/src/plugins/cdp.ts (2)

Line range hint 71-84: Add input validation and reduce sensitive data logging

The wallet creation process needs additional security measures:

  1. Validate key format before creation
  2. Implement rate limiting
  3. Reduce logging of sensitive information
async createWallet(key: string): Promise<AgentWalletData> {
  try {
+   if (!key || key.length < 8) {
+     throw new Error('Invalid key format');
+   }
    key = key.toLowerCase();
-   console.log(`Creating new wallet for key ${key}...`);
+   console.log('Creating new wallet...');
    const wallet = await Wallet.create({
      networkId: Coinbase.networks.BaseMainnet,
    });

Also applies to: 97-99


Line range hint 253-261: Improve wallet deletion security

The deletion process should:

  1. Validate the key before deletion
  2. Reduce logging of sensitive information
  3. Consider adding a confirmation step
  async deleteWallet(key: string): Promise<boolean> {
+   if (!key || key.length < 8) {
+     throw new Error('Invalid key format');
+   }
    key = key.toLowerCase();
-   console.log(`Deleting wallet for key ${key}`);
+   console.log('Deleting wallet...');
    const encryptedKey = this.encrypt(key);
    await this.walletStorage.del(`wallet:${encryptedKey}`);
-   console.log(`Wallet deleted for key ${key}`);
+   console.log('Wallet deleted successfully');
    return true;
  }
♻️ Duplicate comments (4)
packages/message-kit/src/plugins/gpt.ts (1)

278-326: 🛠️ Refactor suggestion

Refactor recursive implementation to prevent stack overflow

The current implementation still uses recursion which could lead to stack overflow issues.

packages/message-kit/src/plugins/cdp.ts (2)

31-32: ⚠️ Potential issue

Fix security issues and add environment variable validation

Several issues need to be addressed:

  1. The typo in cdpEncriptionKey property name still exists
  2. Logging sensitive encryption key
  3. Missing environment variable validation

Apply these changes:

- private cdpEncriptionKey: string;
+ private cdpEncryptionKey: string;

  constructor(context: Context) {
    this.walletStorage = new LocalStorage();
    this.walletStorage.getWalletCount();
-   this.cdpEncriptionKey = (process.env.COINBASE_API_KEY_PRIVATE_KEY as string).toLowerCase();
-   console.log("cdpEncriptionKey", this.cdpEncriptionKey);
+   const encryptionKey = process.env.COINBASE_API_KEY_PRIVATE_KEY;
+   if (!encryptionKey) {
+     throw new Error('COINBASE_API_KEY_PRIVATE_KEY environment variable is required');
+   }
+   this.cdpEncryptionKey = encryptionKey.toLowerCase();
    this.senderAddress = context.message.sender.address.toLowerCase();
    this.developerAddress = context.client.accountAddress.toLowerCase();
  }

Also applies to: 36-42


220-251: ⚠️ Potential issue

Add validation to swap method

The swap implementation needs additional validation:

  1. Asset ID validation
  2. Minimum amount check
  3. Balance verification

Apply these changes:

  async swap(
    address: string,
    fromAssetId: string,
    toAssetId: string,
    amount: number,
  ): Promise<Trade | undefined> {
    address = address.toLowerCase();
    let walletData = await this.getWallet(address);
    if (!walletData) return undefined;
+   
+   // Validate asset IDs
+   const validAssets = [Coinbase.assets.Eth, Coinbase.assets.Usdc];
+   if (!validAssets.includes(fromAssetId) || !validAssets.includes(toAssetId)) {
+     throw new Error('Invalid asset ID provided');
+   }
+   
+   // Validate amount
+   if (amount <= 0) {
+     throw new Error('Amount must be greater than 0');
+   }
+   
+   // Check balance
+   const balance = await walletData.wallet.getBalance(fromAssetId);
+   if (Number(balance) < amount) {
+     throw new Error('Insufficient balance for swap');
+   }

    console.log(`Retrieved wallet data for ${address}`);
packages/message-kit/src/lib/core.ts (1)

129-129: 🛠️ Refactor suggestion

Replace 'void' with 'undefined' in union types for clarity

Using void inside a union type can be confusing and may lead to unintended behavior. Replace void with undefined in the type definition of awaitedHandler to enhance clarity and type safety.

Apply this diff:

- awaitedHandler: ((text: string) => Promise<boolean | void>) | undefined = undefined;
+ awaitedHandler: ((text: string) => Promise<boolean | undefined>) | undefined = undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 129-129: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🧹 Nitpick comments (8)
packages/docs/pages/changelog.mdx (1)

25-30: LGTM! Consider adding a newline after the Chores section.

The maintenance tasks are well-documented and align with the AI-generated summary. For consistency with other sections, consider adding a newline after line 30 to maintain uniform spacing between version entries.

  - Updated URL formats in the FrameKit documentation for receipts.

+ 
packages/message-kit/src/plugins/gpt.ts (1)

281-290: Consider making action indicators configurable

The action indicators are hardcoded in the function. Consider moving them to a configuration file or environment variables to allow easier updates and customization.

Apply this diff to make the indicators configurable:

+ // Move to a configuration file (e.g., config.ts)
+ export const DEFAULT_ACTION_INDICATORS = [
+   "moment",
+   "let's",
+   "i'll look up",
+   "check",
+   "checking",
+   "searching",
+   "hang",
+   "wait",
+ ];

  export async function checkIntent(
    systemPrompt: string,
    userPrompt: string,
    reply: string,
    memoryKey: string,
    attempts: number = 0,
  ) {
    const MAX_ATTEMPTS = 10;
-   const actionIndicators = [
-     "moment",
-     "let's",
-     "i'll look up",
-     "check",
-     "checking",
-     "searching",
-     "hang",
-     "wait",
-   ];
+   const actionIndicators = process.env.ACTION_INDICATORS
+     ? JSON.parse(process.env.ACTION_INDICATORS)
+     : DEFAULT_ACTION_INDICATORS;
packages/message-kit/src/plugins/cdp.ts (1)

Line range hint 46-55: Consider using a more secure encryption method

The current XOR encryption with keccak256 might not provide sufficient security for sensitive wallet data. Consider using industry-standard encryption libraries.

Also, update the property reference:

- const key = keccak256(toHex(this.cdpEncriptionKey));
+ const key = keccak256(toHex(this.cdpEncryptionKey));
packages/message-kit/src/xmtp/stream.ts (3)

Line range hint 14-31: Consider enhancing the initialization check mechanism.

The initialization check is a good addition, but could be improved:

  1. The 1-second delay might be too short for async initialization scenarios
  2. Consider adding a more robust state management system
 export let hasInitialized = false;
+const INIT_CHECK_DELAY = 5000; // 5 seconds
+let initCheckTimeout: NodeJS.Timeout;
 
 function checkInitialization() {
   if (!hasInitialized && !hasClientInitialized) {
     console.warn(`\x1b[33m
⚠️  MessageKit is imported but not running!
   Make sure to call run(agent) to start processing messages
...
\x1b[0m`);
   }
 }
 
-setTimeout(checkInitialization, 1000);
+initCheckTimeout = setTimeout(checkInitialization, INIT_CHECK_DELAY);
+
+export function cancelInitCheck() {
+  clearTimeout(initCheckTimeout);
+}

Line range hint 266-307: Enhance stream resilience and monitoring.

The current implementation has several areas for improvement:

  1. The infinite loop lacks graceful shutdown
  2. Missing exponential backoff for reconnection attempts
  3. No health monitoring or metrics

Consider implementing:

  1. Graceful shutdown mechanism
  2. Exponential backoff for reconnection
  3. Health metrics for monitoring
+const INITIAL_RETRY_DELAY = 1000;
+const MAX_RETRY_DELAY = 30000;
+let isShuttingDown = false;

 export async function streamMessages(
   version: "v3" | "v2",
   handleMessage: (
     version: "v3" | "v2",
     message: DecodedMessage | DecodedMessageV2 | undefined,
   ) => Promise<void>,
   client: V3Client | V2Client,
 ) {
   let v3client = client as V3Client;
   let v2client = client as V2Client;
+  let retryDelay = INITIAL_RETRY_DELAY;
+
+  const shutdown = () => {
+    isShuttingDown = true;
+    // Cleanup logic here
+  };
+
+  process.on('SIGTERM', shutdown);
+  process.on('SIGINT', shutdown);

-  while (true) {
+  while (!isShuttingDown) {
     try {
       if (version === "v3") {
         const stream = await v3client.conversations.streamAllMessages();
         console.warn(`\t- [${version}] Stream started`);
         for await (const message of stream) {
           handleMessage(version, message);
         }
       } else if (version === "v2") {
         const stream = await v2client.conversations.streamAllMessages();
         console.warn(`\t- [${version}] Stream started`);
         for await (const message of stream) {
           handleMessage(version, message);
         }
       }
+      retryDelay = INITIAL_RETRY_DELAY; // Reset on successful connection
     } catch (err) {
       console.error(`[${version}] Stream encountered an error:`, err);
+      await new Promise(resolve => 
+        setTimeout(resolve, Math.min(retryDelay, MAX_RETRY_DELAY))
+      );
+      retryDelay *= 2; // Exponential backoff
     }
   }
 }

Line range hint 54-55: Fix typo in comments.

The comment "do nothin" should be "do nothing".

-          //If same address do nothin
+          //If same address do nothing
packages/message-kit/src/content-types/agent-message.ts (2)

19-25: Define a specific interface for 'metadata' to enhance type safety

Currently, the metadata property in the AgentMessage class uses an index signature with [key: string]: any, which can lead to less type safety and potential runtime errors. Consider defining a specific Metadata interface to clearly specify the expected structure and types of the metadata properties.


27-27: Specify the type of the 'metadata' parameter in the constructor

The constructor accepts metadata: any, which can reduce type safety. By specifying the type as the newly defined Metadata interface, you can catch type errors at compile time and improve code maintainability.

Apply this diff:

- constructor(text: string, metadata: any) {
+ constructor(text: string, metadata: Metadata) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba6167 and 920e223.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (10)
  • packages/docs/pages/changelog.mdx (1 hunks)
  • packages/message-kit/package.json (2 hunks)
  • packages/message-kit/rollup.config.js (1 hunks)
  • packages/message-kit/src/content-types/agent-message.ts (1 hunks)
  • packages/message-kit/src/lib/core.ts (13 hunks)
  • packages/message-kit/src/plugins/cdp.ts (10 hunks)
  • packages/message-kit/src/plugins/gpt.ts (1 hunks)
  • packages/message-kit/src/xmtp/client.ts (2 hunks)
  • packages/message-kit/src/xmtp/stream.ts (2 hunks)
  • templates/paymentagent/example_prompt.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/message-kit/package.json
  • templates/paymentagent/example_prompt.md
🧰 Additional context used
🪛 Biome (1.9.4)
packages/message-kit/src/lib/core.ts

[error] 96-96: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


[error] 129-129: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🔇 Additional comments (5)
packages/docs/pages/changelog.mdx (3)

5-11: LGTM! New Features section is clear and well-documented.

The new features are clearly described and align with the changes mentioned in the AI-generated summary.


12-19: LGTM! Documentation section accurately reflects the changes.

The documentation updates are well-documented and consistent with the AI-generated summary about terminology standardization and documentation reorganization.


20-24: LGTM! Bug Fixes section is clear and accurate.

The bug fixes are well-documented and align with the changes mentioned in the AI-generated summary.

packages/message-kit/rollup.config.js (1)

20-20: Addition of external '@xmtp/content-type-read-receipt' dependency is appropriate

The inclusion of @xmtp/content-type-read-receipt in the external array aligns with the updates to support read receipt codecs. This ensures that Rollup recognizes and excludes this package from the bundle as intended.

packages/message-kit/src/xmtp/client.ts (1)

49-49: ⚠️ Potential issue

Verify the impact of converting 'dbPath' addresses to lowercase

Changing dbPath to use user.account?.address.toLowerCase() may cause the client to use a different database path than before. This could lead to issues accessing existing data stored under the original mixed-case address. Ensure that this change does not disrupt access to existing databases or result in data duplication.

Run the following script to identify existing database directories that might be affected:

Replace ${user_account_address} with the actual account address.

✅ Verification successful

No impact from converting dbPath addresses to lowercase

The change to use lowercase addresses in dbPath is safe and won't cause data access issues for the following reasons:

  1. This is a new configuration option being set in the default client options, not a modification to existing database access code
  2. The .data directory is created fresh for each installation, as evidenced by the create-message-kit setup process
  3. There's no existing database migration code or persistent storage access patterns that would be affected by this change
  4. The dbPath is consistently used only in this location for initial client configuration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for existing database directories with mixed-case addresses

# List all directories in .data and compare with the lowercase address
lowercase_address=$(echo "${user_account_address}" | tr '[:upper:]' '[:lower:]')
ls .data/ | grep -i "${lowercase_address}"

Length of output: 140


Script:

#!/bin/bash
# Let's first check how this dbPath is being used in the codebase
rg "dbPath.*\.data" -A 3 -B 3

Length of output: 498


Script:

#!/bin/bash
# Check the git history for any changes related to dbPath and case sensitivity
git log -G "dbPath.*\.data" --oneline

Length of output: 0


Script:

#!/bin/bash
# Look for any database initialization or migration code
ast-grep --pattern 'new Client($$$)' 

Length of output: 256


Script:

#!/bin/bash
# Check for any tests that might be using dbPath
rg "dbPath.*test" 

Length of output: 19


Script:

#!/bin/bash
# Let's check how the Client is being used and if there are any database-related operations
rg "Client.*xmtp" -A 5 -B 5

Length of output: 9220


Script:

#!/bin/bash
# Search for any database-related imports or usage
rg "\.data.*directory|database.*path" -A 3 -B 3

Length of output: 908


Script:

#!/bin/bash
# Look for any storage or persistence related code
ast-grep --pattern 'class $_ implements Storage {
  $$$
}'

Length of output: 60

const { reply: fixedReply } = await textGeneration(
fixPrompt,
systemPrompt,
memoryKey,
Math.random().toString(36).substring(2, 12),
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix memory key regeneration in retry logic

The code generates a new random memory key on each retry attempt, which could lead to fragmented chat history. Consider using the original memory key throughout the retry process to maintain conversation continuity.

Apply this diff to fix the memory key usage:

    const { reply: fixedReply } = await textGeneration(
      fixPrompt,
      systemPrompt,
-     Math.random().toString(36).substring(2, 12),
+     memoryKey,
    );

    if (!fixedReply.includes("/")) {
      return checkIntent(
        systemPrompt,
        userPrompt,
        fixedReply,
-       Math.random().toString(36).substring(2, 12),
+       memoryKey,
        attempts + 1,
      );
    }

Also applies to: 324-324

@@ -78,13 +77,13 @@ export async function run(agent: Agent) {

//Await response
const awaitedHandler = awaitedHandlers.get(
context.getConversationKey(),
context.xmtp.getConversationKey(),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling in message validation.

While the sender validation is a good security measure, the error handling could be enhanced:

  1. Add explicit error logging for validation failures
  2. Consider extracting the validation logic to a separate function
+function validateMessageSender(
+  expectedUser: string,
+  actualSender: string,
+  version: "v3" | "v2"
+): boolean {
+  return expectedUser?.toLowerCase() === actualSender?.toLowerCase();
+}

 const awaitedHandler = awaitedHandlers.get(
   context.xmtp.getConversationKey(),
 );
 if (awaitedHandler) {
   const messageText =
     context.message.content.text || context.message.content.reply || "";
   const expectedUser = context.xmtp.getConversationKey().split(":")[1];
   const actualSender =
     version === "v3"
       ? (message as DecodedMessage).senderInboxId
       : (message as DecodedMessageV2).senderAddress;

-  if (expectedUser?.toLowerCase() === actualSender?.toLowerCase()) {
+  if (validateMessageSender(expectedUser, actualSender, version)) {
     const isValidResponse = await awaitedHandler(messageText);
     if (isValidResponse) {
       awaitedHandlers.delete(context.xmtp.getConversationKey());
     }
+  } else {
+    console.warn(
+      `Message validation failed: Expected ${expectedUser}, got ${actualSender}`
+    );
   }

Also applies to: 86-96

@humanagent humanagent marked this pull request as ready for review December 16, 2024 13:34
@humanagent humanagent requested a review from a team as a code owner December 16, 2024 13:34
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