diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9ccf5607..26dd0ac17 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,17 +44,17 @@ jobs: run: yarn - name: Build run: yarn build:message-kit + - name: Test client + run: yarn test:client + continue-on-error: true + env: + KEY: ${{ secrets.KEY }} + TEST_ENCRYPTION_KEY: ${{ secrets.TEST_ENCRYPTION_KEY }} - name: Test parsing run: yarn test:parsing continue-on-error: true env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - - name: Test client - run: yarn test:client - - name: Test v3 - run: yarn test:v3 - - name: Test v2 - run: yarn test:v2 - name: Test Frames run: yarn test:frames - name: Test Prompting diff --git a/README.md b/README.md index 911efa09c..dfc92287e 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ This is the official repository for [MessageKit](https://message-kit.org/). Powe - [`message-kit`](/packages/message-kit):Β A kit for quickly building messaging apps - [`create-message-kit`](/packages/create-message-kit):Β A CLI for creating new apps easily - [`framekit`](/packages/framekit): A suite for backend frames +- ['xmtp](/packages/xmtp/): A secure agent sdk +- [`xmtp-client`](/packages/xmtp-client/): Client sided agent sdk - [`docs`](/packages/docs):Β Documentation for MessageKit ## Contributing diff --git a/community/plugins.json b/community/plugins.json index 93f85aa33..e9d014a32 100644 --- a/community/plugins.json +++ b/community/plugins.json @@ -90,6 +90,20 @@ "icon": "πŸ“’", "author": "humanagent" }, + { + "href": "/plugins/xmtp", + "title": "xmtp", + "description": "Use Xmtp to send E2EE messages.", + "icon": "πŸ’¬", + "author": "ephemeraHQ" + }, + { + "href": "/plugins/xmtp-groups", + "title": "Xmtp Groups", + "description": "Use Xmtp Groups to manage groups.", + "icon": "πŸ§‘β€πŸ§‘β€πŸ§’", + "author": "ephemeraHQ" + }, { "href": "/plugins/gpt", "title": "GPT", diff --git a/package.json b/package.json index db89fc2b4..7b283e86c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "message-kit-monorepo", - "version": "1.2.33", + "version": "1.2.35", "private": true, "type": "module", "workspaces": [ @@ -13,28 +13,28 @@ "build:message-kit": "turbo run build --filter=./packages/message-kit --force", "build:packages": "turbo run build --filter='./packages/*' --filter='!./packages/message-kit'", "build:templates": "turbo run build --filter='./templates/*'", + "build:xmtp": "turbo run build --filter=./packages/xmtp --force", + "build:xmtp-client": "turbo run build --filter=./packages/xmtp-client --force", "bump": "node scripts/update-version.js -t patch", "changeset": "yarn copy && changeset add --type patch", "clean": "turbo run clean && rm -rf node_modules && rm -rf .turbo && rm -rf packages/message-kit/dist && rm -rf packages/message-kit/.turbo && rm -rf packages/docs/dist && yarn cache clean", "cli": "node packages/create-message-kit/index.js", "copy": "node scripts/copyTemplates.js", - "dev": "cd packages/message-kit && yarn build:watch", + "dev": "yarn build:xmtp && cd packages/message-kit && yarn build:watch", "docs": "cd packages/docs && yarn dev", "domain": "ngrok http --hostname=frames.ngrok.app 3000", "format": "turbo run format", - "framekit": "cd packages/framekit && yarn dev", + "framekit": "yarn build:xmtp-client && cd packages/framekit && yarn dev", "play": "cd templates/playground && yarn dev", - "publish": "node scripts/publish.js", + "publish": "yarn install && yarn build && yarn copy && node scripts/publish.js", "templates": "node scripts/devTemplates.js", "test": "FORCE_COLOR=1 turbo run test --force --concurrency=1", - "test:client": "cd packages/message-kit/tests && yarn test:client", + "test:client": "cd packages/xmtp/tests && yarn test:client", "test:flow": "cd packages/message-kit/tests && yarn test:flow", "test:framekit": "cd packages/message-kit/tests && yarn test:framekit", "test:intent": "cd packages/message-kit/tests && yarn test:intent", "test:parsing": "cd packages/message-kit/tests && yarn test:parsing", "test:prompt": "cd packages/message-kit/tests && yarn test:prompt", - "test:v2": "cd packages/message-kit/tests && yarn test:v2", - "test:v3": "cd packages/message-kit/tests && yarn test:v3", "typecheck": "FORCE_COLOR=1 turbo run typecheck" }, "resolutions": { diff --git a/packages/create-message-kit/index.js b/packages/create-message-kit/index.js index 281b26724..b80e143aa 100755 --- a/packages/create-message-kit/index.js +++ b/packages/create-message-kit/index.js @@ -7,7 +7,6 @@ import { default as fs } from "fs-extra"; import { isCancel } from "@clack/prompts"; import { detect } from "detect-package-manager"; import pc from "picocolors"; -const defVersion = "1.2.33"; const __dirname = dirname(fileURLToPath(import.meta.url)); // Read package.json to get the version @@ -26,13 +25,7 @@ program log.info(pc.cyan(`pkgManager detected: ${pkgManager}`)); log.info(pc.cyan(`Welcome to MessageKit CLI v${version}!`)); - if (version !== defVersion) { - log.warn( - pc.red( - "You are using a version of the CLI that is not compatible with the latest MessageKit. Please update to the latest version.", - ), - ); - } + const coolLogo = ` β–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•— β–ˆβ–ˆβ•—β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β• β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β•šβ•β•β–ˆβ–ˆβ•”β•β•β• diff --git a/packages/create-message-kit/package.json b/packages/create-message-kit/package.json index ca36cc202..dfbe6464c 100644 --- a/packages/create-message-kit/package.json +++ b/packages/create-message-kit/package.json @@ -1,6 +1,6 @@ { "name": "create-message-kit", - "version": "1.2.33", + "version": "1.2.35", "license": "MIT", "type": "module", "main": "index.js", diff --git a/packages/docs/pages/changelog.mdx b/packages/docs/pages/changelog.mdx index f4a2f6e70..9cceca600 100644 --- a/packages/docs/pages/changelog.mdx +++ b/packages/docs/pages/changelog.mdx @@ -26,7 +26,7 @@ - **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. + - Added a new `XMTP` 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. @@ -435,7 +435,7 @@ Overall, these changes aim to enhance the functionality of GPT-based agents, imp - Replaced one-to-one with Agent example - Documented `skills` - Renamed examples as templates -- How to use a second `xmtpClient` client +- How to use a second `createClient` client - Optional parameters concepts/structure#optional-parameters - Added changelog diff --git a/packages/docs/pages/concepts/agents.mdx b/packages/docs/pages/concepts/agents.mdx index 063dd0551..5e2f1cf58 100644 --- a/packages/docs/pages/concepts/agents.mdx +++ b/packages/docs/pages/concepts/agents.mdx @@ -30,26 +30,15 @@ agent/ This is the main function that runs the listener. ```jsx -import { Agent, run, type Context } from "@xmtp/message-kit"; - -const agent: Agent = { - name: "Agent Name", - tag: "@bot", - description: "Agent Description", - skills: [skill1, skill2] -}; -//starts the agent -run(agent); +// [!include ~/../../templates/simple/src/index.ts] ``` ### Config ```tsx -const agent: Agent = { - config: { - /* Optional properties */ - }, -}; +config: { + /* Optional properties */ +} ``` - `privateKey`: the private key of the agent wallet, like any normal wallet private key. diff --git a/packages/docs/pages/concepts/xmtp.mdx b/packages/docs/pages/concepts/xmtp.mdx index d301d59da..66ddc7556 100644 --- a/packages/docs/pages/concepts/xmtp.mdx +++ b/packages/docs/pages/concepts/xmtp.mdx @@ -2,6 +2,8 @@ [XMTP](https://xmtp.org/) is the protocol that MessageKit uses to send and receive messages. +> Check out the [XMTP AI](/plugins/xmtp) plugins for more information. + ## Context The `Context` object is a core component that provides access to all XMTP messaging functionality. It handles conversations, groups, and messages. @@ -32,15 +34,8 @@ Contains information about the current message: - `sender`: Address of message sender - `sent`: Timestamp when message was sent - `typeId`: Type of message - -#### Clients - - `client`: V3 XMTP client instance - `v2client`: V2 XMTP client instance -- `version`: Current client version - -#### Conversation - - `conversation`: Current conversation object with messaging methods #### Group (V3 Only) @@ -56,7 +51,7 @@ Group chat information including: Each messages comes with a sender object that contains the address, name, and avatar of the sender. ```tsx -interface AbstractedMember { +interface Member { // Unique identifier for the user's inbox inboxId: string; @@ -86,15 +81,15 @@ const { sender } = context.message; MessageKit provides wrapped versions of XMTP clients for easier integration: ```tsx -import { V2Client, V3Client } from "@xmtp/message-kit"; +import { V2Client, V3Client } from "xmtp"; ``` -You can create new client instances using the `xmtpClient` helper: +You can create new client instances using the `createClient` helper: ```tsx -import { xmtpClient } from "@xmtp/message-kit"; +import { createClient } from "xmtp"; -const { v2client } = await xmtpClient({ +const { v2client } = await createClient({ // Optional configuration }); ``` diff --git a/packages/docs/pages/plugins/cron.mdx b/packages/docs/pages/plugins/cron.mdx index 8e115f87c..df852a7ad 100644 --- a/packages/docs/pages/plugins/cron.mdx +++ b/packages/docs/pages/plugins/cron.mdx @@ -16,12 +16,12 @@ Run a node cron daily to send message to users ```tsx [src/plugins/cron.ts] import cron from "node-cron"; -import { xmtpClient } from "@xmtp/message-kit"; +import { createClient } from "xmtp"; import { RedisClientType } from "@redis/client"; export async function startCron(redisClient: RedisClientType) { // Daily task - const client = await xmtpClient(); + const client = await createClient(); console.log("Starting daily cron"); cron.schedule( "0 0 * * *", // Daily or every 5 seconds in debug mode diff --git a/packages/docs/pages/plugins/stackso.mdx b/packages/docs/pages/plugins/stackso.mdx index 3714a61c7..96407d4df 100644 --- a/packages/docs/pages/plugins/stackso.mdx +++ b/packages/docs/pages/plugins/stackso.mdx @@ -38,7 +38,7 @@ export type { StackClient }; ## Example handler ```tsx [src/handler/loyalty.ts] -import { Context, AbstractedMember } from "@xmtp/message-kit"; +import { Context, Member } from "@xmtp/message-kit"; import { getStackClient } from "../plugins/stack.js"; export async function handler(context: Context, fake?: boolean) { @@ -76,7 +76,7 @@ export async function handler(context: Context, fake?: boolean) { } else if (typeId === "group_updated") { const { initiatedByInboxId, addedInboxes } = params; const adminAddress = members?.find( - (member: AbstractedMember) => member.inboxId === initiatedByInboxId, + (member: Member) => member.inboxId === initiatedByInboxId, ); if (addedInboxes && addedInboxes.length > 0) { //if add someone to the group diff --git a/packages/docs/pages/plugins/xmtp-groups.mdx b/packages/docs/pages/plugins/xmtp-groups.mdx new file mode 100644 index 000000000..eb8ef6398 --- /dev/null +++ b/packages/docs/pages/plugins/xmtp-groups.mdx @@ -0,0 +1,19 @@ +# XMTP Groups + +This is a simple abstracted plugin to manage groups on XMTP. + +## Description + +Interact with XMTP Groups. + +## Install libraries + +```bash [cmd] +npm install @xmtp/node-sdk +``` + +## Usage + +```tsx +// [!include ~/../../templates/gated-group/src/plugins/xmtp-groups.ts] +``` diff --git a/packages/docs/pages/plugins/xmtp.mdx b/packages/docs/pages/plugins/xmtp.mdx new file mode 100644 index 000000000..bd3563840 --- /dev/null +++ b/packages/docs/pages/plugins/xmtp.mdx @@ -0,0 +1,187 @@ +# Xmtp ai + +AI is transforming consumer tech, with messaging becoming the main channel for interacting with agent services. This shift will scale message traffic astronomically, akin to the web’s rise in the 2000s. Just as Cloudflare secured web traffic, messaging will need robust encryption, threat protection, and scalable infrastructure to handle the surge and protect sensitive AI-driven interactions. + +## Risks + +⚠️ **Risks of not using end-to-end encryption**: Exposes users to Man in the Middle Attacks. + +> **Man in the Middle Attacks (MITM)**: Intercept requests in between to alter or manipulate data sent or received by the AI service or user. + +- **Phishing**: Messages can be intercepted and manipulated. +- **Privacy**: Sensitive information read by unwanted parties. +- **Tampering**: Content can be altered without detection. + +## Anonymity + +Using ephemeral addresses can enhance security by allowing users to message agents anonymously, protecting their identities from exposure. + +## Backend + +### Installation + +Install the `xmtp` package + +```bash [cmd] +bun install xmtp +``` + +### Usage + +This is how you can use the `xmtp` package to create a client and handle messages. + +```tsx +import { createClient } from "xmtp"; + +const xmtp = await createClient(onMessage, { + encryptionKey: process.env.LOCAL_KEY, +}); + +const onMessage = async (message, user) => { + console.log(`Decoded message: ${response} by ${user}`); + // Your AI model response + xmtp.send(response); +}; +``` + +### Gpt example + +1. **`handleMessage`**: Triggered each time a new message is received from XMTP. +2. **`client.send()`**: Used to send messages (e.g., AI prompts and responses) back to the XMTP network. + +In this example, when `handleMessage` is invoked, it takes the incoming user message, passes it to the AI model (OpenAI's Chat Completion API), and then sends the AI's response back over XMTP. + +```javascript +import { createClient } from "xmtp"; +import { OpenAI } from "openai"; + +const openai = new OpenAI({ + apiKey: process.env.OPENAI_API_KEY, +}); + +const xmtp = await createClient(onMessage, { + encryptionKey: process.env.LOCAL_KEY, +}); + +const onMessage = async (message, user) => { + console.log(`Decoded message: ${response} by ${user}`); + + // Prepare conversation history or context as needed + const history = [ + { role: "system", content: "You are a helpful assistant." }, + { role: "user", content: message }, + ]; + + // Call the OpenAI API to process the user's message + const response = await openai.createChatCompletion({ + model: process.env.GPT_MODEL || "gpt-4", + messages: history, + }); + + const response = response.data.choices[0].message.content.trim(); + + // Send the AI-generated response back to the XMTP network + xmtp.send(response); +}; +``` + +## Frontend + +### Installation + +Install the `xmtp-client` package compatible with your frontend framework. + +```bash [cmd] +bun install xmtp-client +``` + +### Usage + +```tsx +import { createClient, XMTP, Message } from "xmtp-client"; + +const xmtp = await createClient(onMessage, { + encryptionKey: process.env.LOCAL_KEY, +}); + +const onSend = async (text) => { + const message = await xmtp.sendMessage(text, agentAddress); + return message; +}; + +const onMessage = async (message, agentAddress) => { + console.log(`Decoded message: ${message} by ${agentAddress}`); + // Your AI model response +}; +``` + +### React example + +This is how you can use the `xmtp-client` package to create a client and handle messages. + +```tsx +import { createClient, XMTP, Message } from "xmtp-client"; +// ... other imports ... + +function Chat({ user }: { user: UserInfo }) { + const [messages, setMessages] = useState([]); + const [newMessage, setNewMessage] = useState(""); + const [xmtp, setXmtp] = useState(undefined); + const [isLoading, setIsLoading] = useState(true); + // ... other state variables ... + + useEffect(() => { + const init = async () => { + const newWallet = Wallet.createRandom(); + // ... set wallet and recipient info ... + + try { + if (user?.address) { + await initXmtp(newWallet); + } + } catch (error) { + console.error("Error resolving recipient:", error); + setIsLoading(false); + } + }; + + init(); + }, [user.address]); + + const onMessage = async (message: Message | undefined) => { + if (message) { + setMessages((prevMessages) => [...prevMessages, message]); + } + }; + + const initXmtp = async (wallet: any) => { + try { + const xmtpClient = await createClient(onMessage, { + privateKey: wallet.privateKey, + }); + setXmtp(xmtpClient); + setIsLoading(false); + } catch (error) { + console.error("Error initializing XMTP:", error); + setIsLoading(false); + } + }; + + const sendMessage = async (e: React.FormEvent) => { + e.preventDefault(); + if (!xmtp || !newMessage || !recipientInfo?.address) return; + + try { + const message = await xmtp.sendMessage(newMessage, user.address); + setMessages((prevMessages) => [...prevMessages, message]); + setNewMessage(""); + } catch (error) { + console.error("Error sending message:", error); + } + }; + + return
{/* Render chat UI */}
; +} + +export default React.memo(Chat); +``` diff --git a/packages/docs/pages/quickstart.mdx b/packages/docs/pages/quickstart.mdx index 26432b27e..fbbbfffc4 100644 --- a/packages/docs/pages/quickstart.mdx +++ b/packages/docs/pages/quickstart.mdx @@ -85,7 +85,7 @@ See [Deployment](/deployment) for more information. ## Compatible apps -These wallets are built on top of XMTP and are EVM compatible, menaing they work with any wallet address or ens domain. +These wallets are built on top of XMTP and work with any identity. - [**Converse**](https://converse.xyz) - [**Coinbase Wallet**](https://www.coinbase.com/en-ar/wallet/downloads) diff --git a/packages/docs/pages/skills/concierge.mdx b/packages/docs/pages/skills/concierge.mdx index c1d5a36bb..50a77eca6 100644 --- a/packages/docs/pages/skills/concierge.mdx +++ b/packages/docs/pages/skills/concierge.mdx @@ -123,19 +123,7 @@ await notifyUser(context, sender.address, recipient?.address, tx, amount); Concierge is a [Skill](/concepts/skills) already included in Message Kit. ```tsx -import { run, Agent, concierge } from "@xmtp/message-kit"; - -export const agent: Agent = { - name: "Wallet Agent", - tag: "@bot", - description: "A payment agent with that manages wallets for its users", - skills: [concierge], // [!code focus] - config: { - walletService: true, - }, -}; - -run(agent); +// [!include ~/../../templates/paymentagent/src/index.ts] ``` ## Wallet Service diff --git a/packages/docs/pages/skills/gated.mdx b/packages/docs/pages/skills/gated.mdx index ddacb7faf..45e506264 100644 --- a/packages/docs/pages/skills/gated.mdx +++ b/packages/docs/pages/skills/gated.mdx @@ -20,6 +20,8 @@ Group created! - Once in the other group you can share the invite with your friends. ``` +> For more abstraction use the [Xmtp Groups](/plugins/xmtp-groups) plugin. + ## Start the server The code for the server is the following: diff --git a/packages/docs/pages/templates/paymentagent.mdx b/packages/docs/pages/templates/paymentagent.mdx index ecbffa189..4b04f57b9 100644 --- a/packages/docs/pages/templates/paymentagent.mdx +++ b/packages/docs/pages/templates/paymentagent.mdx @@ -2,7 +2,23 @@ Create wallets for users and interact with them. -> Payment Agent uses [CDP plugin](/plugins/cdp) to interact with Coinbase. +import Video from "../../components/Video"; + +## Interoperable agent + +`paymentagent.eth` is a template that has an agent that can perform transactions on behalf of the user. Since it's a ens domain its reachable from any app that supports ENS. + +### Converse + +