Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions .github/CONTRIBUTING-PYTHON.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
# Python Development Guide

This guide covers Python-specific setup and development for AgentKit.

## Contents

- [Development Setup](#development-setup)
- [Adding an Agentic Action](#adding-an-agentic-action)
- [Adding an Agentic Action to Langchain Toolkit](#adding-an-agentic-action-to-langchain-toolkit)
- [Adding an Agentic Action to the Twitter Toolkit](#adding-an-agentic-action-to-the-twitter-toolkit)
- [Testing](#testing)
- [Code Style](#code-style)

## Development Setup

AgentKit uses Python 3.10 or higher and Poetry 1.8.5 or higher.

You can run the following commands in your terminal to check your local Python and Poetry versions:

```bash
python --version
poetry --version
```

If the versions are not correct or you don't have Python or Poetry installed, download and follow their setup instructions:
* Python: install with [pyenv](https://github.com/pyenv/pyenv)
* Poetry: follow the official [Poetry installation instructions](https://python-poetry.org/docs/#installation)

**Note**: You will also need to have Rust and Cargo installed. Follow the official [Rust installation instructions](https://doc.rust-lang.org/cargo/getting-started/installation.html)

## Adding an Agentic Action

One of the most common ways to contribute to AgentKit is by adding a new agentic action. Here are the high level steps:

**Note: It is recommended to point your editor to the specific package that you are working in. This will help ensure things like package imports are working correctly**

1. Create a new file in `cdp-agentkit-core/python/cdp_agentkit_core/actions`
2. Implement your new action inside your newly created file
- For an example of an action, see [mint_nft.py](./cdp-agentkit-core/python/cdp_agentkit_core/actions/mint_nft.py)
3. Add your action to [__init__.py](./cdp-agentkit-core/python/cdp_agentkit_core/actions/__init__.py)
4. Add a test for your action in `cdp-agentkit-core/python/tests/actions`
- For an example, see [test_mint_nft.py](./cdp-agentkit-core/python/tests/actions/test_mint_nft.py)

Actions are created by implementing the `CdpAction` interface:

```python
from collections.abc import Callable

from cdp import Wallet
from pydantic import BaseModel, Field

from cdp_agentkit_core.actions import CdpAction

MINT_NFT_PROMPT = """
This tool will mint an NFT (ERC-721) to a specified destination address onchain via a contract invocation.
It takes the contract address of the NFT onchain and the destination address onchain that will receive the NFT as inputs.
Do not use the contract address as the destination address. If you are unsure of the destination address, please ask the user before proceeding.
"""


class MintNftInput(BaseModel):
"""Input argument schema for mint NFT action."""

contract_address: str = Field(
...,
description="The contract address of the NFT (ERC-721) to mint, e.g. `0x036CbD53842c5426634e7929541eC2318f3dCF7e`",
)
destination: str = Field(
...,
description="The destination address that will receive the NFT onchain, e.g. `0x036CbD53842c5426634e7929541eC2318f3dCF7e`",
)


def mint_nft(wallet: Wallet, contract_address: str, destination: str) -> str:
"""Mint an NFT (ERC-721) to a specified destination address onchain via a contract invocation.

Args:
wallet (Wallet): The wallet to trade the asset from.
contract_address (str): The contract address of the NFT (ERC-721) to mint, e.g. `0x036CbD53842c5426634e7929541eC2318f3dCF7e`.
destination (str): The destination address that will receive the NFT onchain, e.g. `0x036CbD53842c5426634e7929541eC2318f3dCF7e`.

Returns:
str: A message containing the NFT mint details.

"""
mint_args = {"to": destination, "quantity": "1"}

try:
mint_invocation = wallet.invoke_contract(
contract_address=contract_address, method="mint", args=mint_args
).wait()
except Exception as e:
return f"Error minting NFT {e!s}"

return f"Minted NFT from contract {contract_address} to address {destination} on network {wallet.network_id}.\nTransaction hash for the mint: {mint_invocation.transaction.transaction_hash}\nTransaction link for the mint: {mint_invocation.transaction.transaction_link}"


class MintNftAction(CdpAction):
"""Mint NFT action."""

name: str = "mint_nft"
description: str = MINT_NFT_PROMPT
args_schema: type[BaseModel] | None = MintNftInput
func: Callable[..., str] = mint_nft
```

#### Components of an Agentic Action

1. **Input Schema**: Define the input parameters using Pydantic schemas
2. **Prompt**: A description that helps the AI understand when and how to use the action. It's important to describe the inputs and outputs of the action and include examples. Additionally, think about what inputs can be removed entirely and fetched or inferred by the LLM, so that users don't have to manually provide them.
3. **Action Class**: Implements the `CdpAction` interface with:
- `name`: Unique identifier for the action
- `description`: The prompt text
- `args_schema`: The Pydantic schema for validating inputs
- `func`: The implementation function
4. **Implementation Function**: The actual logic that executes the action

Check out the [Testing](#testing) section to learn how to manually test your new action.

## Adding an Agentic Action to Langchain Toolkit

The action will be included automatically, all you need to do is add the action to the list of tools in the `CdpToolkit` class documentation in `cdp-langchain/python/cdp_langchain/agent_toolkits/cdp_toolkit.py`.

## Adding an Agentic Action to the Twitter Toolkit

1. Ensure the action is implemented in `cdp-agentkit-core/actions/social/twitter`.
2. Add a wrapper method to `TwitterApiWrapper` in `./twitter_langchain/twitter_api_wrapper.py`
- E.g.
```python
def post_tweet_wrapper(self, tweet: str) -> str:
"""Post tweet to Twitter.

Args:
client (tweepy.Client): The tweepy client to use.
tweet (str): The text of the tweet to post to twitter. Tweets can be maximum 280 characters.

Returns:
str: A message containing the result of the post action and the tweet.

"""

return post_tweet(client=self.client, tweet=tweet)
```
3. Add call to the wrapper in `TwitterApiWrapper.run` in `./twitter_langchain/twitter_api_wrapper.py`
- E.g.
```python
if mode == "post_tweet":
return self.post_tweet_wrapper(**kwargs)

```
4. Add the action to the list of available tools in the `TwitterToolkit` in `./twitter_langchain/twitter_toolkit.py`
- E.g.
```python
actions: List[Dict] = [
{
"mode": "post_tweet",
"name": "post_tweet",
"description": POST_TWEET_PROMPT,
"args_schema": PostTweetInput,
},
]
```
5. Update `TwitterToolkit` documentation
- Add the action to the list of tools
- Add any additional ENV requirements

## Testing

### Local Testing

A good way to test new actions locally is by using the chatbot example in `cdp-langchain`. This requires a couple API keys:

- Get a Coinbase Developer Platform API Key from the [CDP Portal](https://portal.cdp.coinbase.com/access/api)
- Get an [OpenAI API Key](https://platform.openai.com/docs/quickstart#create-and-export-an-api-key)

The flow is:

1. Make your change as described in the [Adding an Agentic Action](#adding-an-agentic-action) section
2. Update `cdp-langchain/examples/chatbot-python/pyproject.toml` to point to the local package
```diff
[tool.poetry]
name = "chatbot-python"
version = "0.0.1"
description = "CDP AgentKit Example Chatbot"
authors = ["John Peterson <john.peterson@coinbase.com>"]
readme = "README.md"
package-mode = false

[tool.poetry.dependencies]
python = "^3.10"
- cdp-langchain = "^0.0.11"
+ cdp-langchain = { path: "../../cdp-agentkit-core/python", develop: true }

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
```
3. In `cdp-langchain/examples/chatbot-python`, run `python chatbot.py`
4. You can now interact with your new action via the chatbot!

### Running Unit Tests

From the package you are working in, you can run:

```bash
make test
```

For example, to run all tests in the `cdp_agentkit_core` package, you can run:
```bash
cd cdp-agentkit-core/python
make test
```

## Code Style

We use `ruff` for linting and formatting. Run:

```bash
# Format code
make format

# Lint code
make lint

# Fix linting issues
make lint-fix
```
159 changes: 159 additions & 0 deletions .github/CONTRIBUTING-TYPESCRIPT.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
# TypeScript Development Guide

This guide covers TypeScript-specific setup and development for AgentKit.

## Contents

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thoughts about putting a context section here or some sort of link out to CDP SDK for those using contract invocations? Want to prevent issues where someone uses an API or something that is an unnecessary dependency/requires each user to provision API keys (where possible. If there's no other option that's fine but we can't include it as a default tool)

- [Development Setup](#development-setup)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

May not be appropriate for this pass, but at some point it would be great to define how we want contributors to integrate AgentKit into new frameworks. Some of the prizes for the SF AI hackathon reward for this.

Main goal being to prevent a framework user from having to do anything but import the latest package for agentkit to get all of the most recent features and capabilities

- [Adding an Agentic Action](#adding-an-agentic-action)
- [Adding an Agentic Action to Langchain Toolkit](#adding-an-agentic-action-to-langchain-toolkit)
- [Testing](#testing)
- [Code Style](#code-style)

## Development Setup

AgentKit uses Node.js v23.4.0 or higher and npm 10.9.2 or higher.

You can run the following commands in your terminal to check your local Node.js and npm versions:

```bash
node --version
npm --version
```

If the versions are not correct or you don't have Node.js or npm installed, download through [nvm](https://github.com/nvm-sh/nvm).

## Adding an Agentic Action

One of the most common ways to contribute to AgentKit is by adding a new agentic action. Here are the high level steps:

**Note: It is recommended to point your editor to the specific package that you are working in. This will help ensure things like package imports are working correctly**

1. Create a new file in `cdp-agentkit-core/typescript/src/actions/cdp`
2. Implement your new action inside your newly created file
- For an example of an action, see [mint_nft.py](./cdp-agentkit-core/typescript/src/actions/cdp/mint_nft.ts)
Comment thread
0xRAG marked this conversation as resolved.
3. Add your action to [index.ts](./cdp-agentkit-core/typescript/src/actions/cdp/index.ts)
4. Add a test for your action in `cdp-agentkit-core/typescript/src/tests`
- For an example, see [mint_nft_test.ts](./cdp-agentkit-core/typescript/src/tests/mint_nft_test.ts)

Actions are created by implementing the `CdpAction` interface:

```typescript
import { CdpAction } from "./cdp_action";
import { Wallet } from "@coinbase/coinbase-sdk";
import { z } from "zod";

const MINT_NFT_PROMPT = `
This tool will mint an NFT (ERC-721) to a specified destination address onchain via a contract invocation. It takes the contract address of the NFT onchain and the destination address onchain that will receive the NFT as inputs. Do not use the contract address as the destination address. If you are unsure of the destination address, please ask the user before proceeding.`;

/**
* Input schema for mint NFT action.
*/
const MintNftInput = z
.object({
contractAddress: z.string().describe("The contract address of the NFT to mint"),
destination: z.string().describe("The destination address that will receive the NFT"),
})
.strip()
.describe("Instructions for minting an NFT");

/**
* Mints an NFT (ERC-721) to a specified destination address onchain.
*
* @param wallet - The wallet to mint the NFT from.
* @param args - The input arguments for the action.
* @returns A message containing the NFT mint details.
*/
async function mintNft(wallet: Wallet, args: z.infer<typeof MintNftInput>): Promise<string> {
const mintArgs = {
to: args.destination,
quantity: "1",
};

try {
const mintInvocation = await wallet.invokeContract({
contractAddress: args.contractAddress,
method: "mint",
args: mintArgs,
});

const result = await mintInvocation.wait();

return `Minted NFT from contract ${args.contractAddress} to address ${args.destination} on network ${wallet.getNetworkId()}.\nTransaction hash for the mint: ${result.getTransaction().getTransactionHash()}\nTransaction link for the mint: ${result.getTransaction().getTransactionLink()}`;
} catch (error) {
return `Error minting NFT: ${error}`;
}
}

/**
* Mint NFT action.
*/
export class MintNftAction implements CdpAction<typeof MintNftInput> {
public name = "mint_nft";
public description = MINT_NFT_PROMPT;
public argsSchema = MintNftInput;
public func = mintNft;
}
```

#### Components of an Agentic Action

1. **Input Schema**: Define the input parameters using Zod schemas
2. **Prompt**: A description that helps the AI understand when and how to use the action. It's important to describe the inputs and outputs of the action and include examples. Additionally, think about what inputs can be removed entirely and fetched or inferred by the LLM, so that users don't have to manually provide them.
3. **Action Class**: Implements the `CdpAction` interface with:
- `name`: Unique identifier for the action
- `description`: The prompt text
- `argsSchema`: The Zod schema for validating inputs
- `func`: The implementation function
4. **Implementation Function**: The actual logic that executes the action

Check out the [Testing](#testing) section to learn how to manually test your new action.

## Adding an Agentic Action to Langchain Toolkit

The action will be included automatically, all you need to do is add the action to the list of tools in the `CdpToolkit` class documentation in `cdp-langchain/typescript/src/toolkits/cdp_toolkit.ts`.

## Testing

### Local Testing

A good way to test new actions locally is by using the chatbot example in `cdp-langchain`. This requires a couple API keys:

- Get a Coinbase Developer Platform API Key from the [CDP Portal](https://portal.cdp.coinbase.com/access/api)
- Get an [OpenAI API Key](https://platform.openai.com/docs/quickstart#create-and-export-an-api-key)

The flow is:

1. Make your change as described in the [Adding an Agentic Action](#adding-an-agentic-action) section
2. Re-build the package by running `npm run build` (either from root, or from the package folder will do)
3. In `cdp-langchain/examples/chatbot-typescript`, run `npm run start`
Comment thread
0xRAG marked this conversation as resolved.
4. You can now interact with your new action via the chatbot!

### Running Tests

From the package you are working in, you can run:

```bash
npm test
```

For example, to run all tests in the `cdp-agentkit-core` package, you can run:
```bash
cd cdp-agentkit-core/typescript
npm test
```

## Code Style

We use ESLint and Prettier for linting and formatting. Run:

```bash
# Format code
npm run format

# Lint code
npm run lint

# Fix linting issues
npm run lint:fix
```
Loading