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
44 changes: 43 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,48 @@ def mint_nft(wallet: Wallet, contract_address: str, destination: str) -> str:
```
5. Add the action to the list of tools in the `CdpToolkit` class documentation.

## 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

## Development Tools
### Formatting
`make format`
Expand All @@ -132,4 +174,4 @@ def mint_nft(wallet: Wallet, contract_address: str, destination: str) -> str:
`make test`

## Changelog
- For new features and bug fixes, please add a new changelog entry to the `CHANGELOG.md` file in the appropriate packages and include that in your Pull Request.
- For new features and bug fixes, please add a new changelog entry to the `CHANGELOG.md` file in the appropriate packages and include that in your Pull Request.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from cdp_agentkit_core.actions.social.twitter.post_tweet import (
POST_TWEET_PROMPT as POST_TWEET_PROMPT,
)
from cdp_agentkit_core.actions.social.twitter.post_tweet import (
PostTweetInput as PostTweetInput,
)
from cdp_agentkit_core.actions.social.twitter.post_tweet import (
post_tweet as post_tweet,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import tweepy
from pydantic import BaseModel, Field

POST_TWEET_PROMPT = """
This tool will post a tweet on Twitter. The tool takes the text of the tweet as input. Tweets can be maximum 280 characters."""

class PostTweetInput(BaseModel):
"""Input argument schema for twitter post tweet action."""

tweet: str = Field(
...,
description="The text of the tweet to post to twitter. Tweets can be maximum 280 characters.",
)

def post_tweet(client: tweepy.Client, 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.

"""
message = ""

try:
client.create_tweet(text=tweet)
message = f"Successfully posted to Twitter:\n{tweet}"
except tweepy.errors.TweepyException as e:
message = f"Error posting to Twitter:\n{tweet}\n{e}"

return message
14 changes: 7 additions & 7 deletions cdp-langchain/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions twitter-langchain/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.PHONY: format
format:
ruff format .

.PHONY: lint
lint:
ruff check .

.PHONY: lint-fix
lint-fix:
ruff check . --fix

.PHONY: docs
docs:
sphinx-apidoc -f -o ./docs ./twitter_langchain

.PHONY: local-docs
local-docs: docs
cd docs && make html && open ./_build/html/index.html

.PHONY: test
test:
pytest
110 changes: 110 additions & 0 deletions twitter-langchain/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,111 @@
# Twitter (X) Langchain Toolkit
Twitter integration with Langchain to enable agentic workflows using the core primitives defined in `cdp-agentkit-core`.

This toolkit contains tools that enable an LLM agent to interact with [Twitter](https://developer.x.com/en/docs/x-api). The toolkit provides a wrapper around the Twitter (X) API, allowing agents to perform social operations like posting text.

## Setup

### Prerequisites
- Python 3.10 or higher
- [OpenAI API Key](https://platform.openai.com/api-keys)
- [Twitter (X) App Developer Keys](https://developer.x.com/en/portal/dashboard)

### Installation

```bash
pip install twitter-langchain
```

### Environment Setup

Set the following environment variables:

```bash
OPENAI_API_KEY=<your-openai-api-key>
TWITTER_API_KEY=<your-api-key>
TWITTER_API_SECRET=<your-api-secret>
TWITTER_ACCESS_TOKEN=<your-access-token>
TWITTER_ACCESS_TOKEN_SECRET=<your-access-token-secret>
```

## Usage

### Basic Setup

```python
from twitter_langchain import (
TwitterApiWrapper,
TwitterToolkit
)

# Initialize TwitterApiwrapper
twitter_api_wrapper = TwitterApiWrapper()

# Create TwitterToolkit from the api wrapper
twitter_toolkit = TwitterToolkit.from_twitter_api_wrapper(twitter_api_wrapper)
```

View available tools:
```python
tools = twitter_toolkit.get_tools()
for tool in tools:
print(tool.name)
```

The toolkit provides the following tools:

1. **post_tweet** - Post tweet to Twitter

### Using with an Agent

```python
import uuid

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent

llm = ChatOpenAI(model="gpt-4o-mini")

# Create agent
agent_executor = create_react_agent(llm, tools)

# Example - post tweet
events = agent_executor.stream(
{
"messages": [
HumanMessage(content=f"Please post 'hello, world! {uuid.uuid4().hex}' to twitter"),
],
},
stream_mode="values",
)

for event in events:
event["messages"][-1].pretty_print()
```

Expected output:
```
================================ Human Message =================================
Please post 'hello, world! c4b8e3744c2e4345be9e0622b4c0a8aa' to twitter
================================== Ai Message ==================================
Tool Calls:
post_tweet (call_xVx4BMCSlCmCcbEQG1yyebbq)
Call ID: call_xVx4BMCSlCmCcbEQG1yyebbq
Args:
tweet: hello, world! c4b8e3744c2e4345be9e0622b4c0a8aa
================================= Tool Message =================================
Name: post_tweet
Successfully posted!
================================== Ai Message ==================================
The message "hello, world! c4b8e3744c2e4345be9e0622b4c0a8aa" has been successfully posted to Twitter!
```

## Contributing
See [CONTRIBUTING.md](../CONTRIBUTING.md) for detailed setup instructions and contribution guidelines.

## Documentation
For detailed documentation, please visit:
- [Agentkit-Core](https://coinbase.github.io/cdp-agentkit-core)
- [Agentkit-Langchain](https://coinbase.github.io/cdp-langchain)
- [Agentkit-Twitter-Langchain](https://coinbase.github.io/twitter-langchain)
10 changes: 10 additions & 0 deletions twitter-langchain/examples/post_tweet/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
ifneq (,$(wildcard ./.env))
include .env
endif

export

.PHONY: run
run:
poetry install --with dev
poetry run python post_tweet.py
55 changes: 55 additions & 0 deletions twitter-langchain/examples/post_tweet/post_tweet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import uuid

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent

from twitter_langchain import (
TwitterApiWrapper,
TwitterToolkit
)

# Initialize TwitterApiwrapper
twitter_api_wrapper = TwitterApiWrapper()

# Create TwitterToolkit from the api wrapper
twitter_toolkit = TwitterToolkit.from_twitter_api_wrapper(twitter_api_wrapper)

# View available tools
tools = twitter_toolkit.get_tools()
for tool in tools:
print(tool.name)

# Initialize LLM
llm = ChatOpenAI(model="gpt-4o-mini")

# Create agent
agent_executor = create_react_agent(llm, tools)

# Example - post tweet
events = agent_executor.stream(
{
"messages": [
HumanMessage(content=f"Please post 'hello, world! {uuid.uuid4().hex}' to twitter"),
],
},
stream_mode="values",
)

for event in events:
event["messages"][-1].pretty_print()

# Successful Output
# ================================ Human Message =================================
# Please post 'hello, world! c4b8e3744c2e4345be9e0622b4c0a8aa' to twitter
# ================================== Ai Message ==================================
# Tool Calls:
# post_tweet (call_xVx4BMCSlCmCcbEQG1yyebbq)
# Call ID: call_xVx4BMCSlCmCcbEQG1yyebbq
# Args:
# text: hello, world! c4b8e3744c2e4345be9e0622b4c0a8aa
# ================================= Tool Message =================================
# Name: post_tweet
# Successfully posted!
# ================================== Ai Message ==================================
# The message "hello, world! c4b8e3744c2e4345be9e0622b4c0a8aa" has been successfully posted to Twitter!
Loading