From 18c1d6ee2eb589297dcf64f5692bcc1465c3ddb7 Mon Sep 17 00:00:00 2001 From: Christopher Gerber Date: Tue, 5 Nov 2024 22:38:20 -0800 Subject: [PATCH] second pass implementing the post text to twitter action --- .../cdp_agentkit_core/actions/__init__.py | 9 ----- .../actions/social/__init__.py | 0 .../actions/social/twitter/__init__.py | 5 +++ .../actions/social/twitter/post_text.py | 18 +++++----- cdp-langchain/examples/chatbot/chatbot.py | 8 +++-- cdp-langchain/poetry.lock | 14 ++++---- twitter-langchain/Makefile | 23 +++++++++++++ .../twitter_langchain/twitter_action.py | 2 +- .../twitter_langchain/twitter_api_wrapper.py | 33 +++++++++++++------ .../twitter_langchain/twitter_toolkit.py | 16 ++++----- 10 files changed, 81 insertions(+), 47 deletions(-) create mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/social/__init__.py create mode 100644 twitter-langchain/Makefile diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py b/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py index d25594b1d..9a5cbf53b 100644 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/__init__.py @@ -49,12 +49,6 @@ uniswap_v3_create_pool, ) -from cdp_agentkit_core.actions.social.twitter.post_text import ( - TWITTER_POST_TEXT_PROMPT, - TwitterPostTextInput, - twitter_post_text, -) - __all__ = [ "UNISWAP_V3_CREATE_POOL_PROMPT", "UniswapV3CreatePoolInput", @@ -86,7 +80,4 @@ "TRANSFER_PROMPT", "TransferInput", "transfer", - "TWITTER_POST_TEXT_PROMPT", - "TwitterPostTextInput", - "twitter_post_text" ] diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/social/__init__.py b/cdp-agentkit-core/cdp_agentkit_core/actions/social/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py index e69de29bb..b2e55c0f0 100644 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/__init__.py @@ -0,0 +1,5 @@ +from cdp_agentkit_core.actions.social.twitter.post_text import ( + POST_TEXT_PROMPT, + PostTextInput, + post_text, +) diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/post_text.py b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/post_text.py index aab386eaa..71b1b951e 100644 --- a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/post_text.py +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/post_text.py @@ -3,23 +3,23 @@ from pydantic import BaseModel, Field -TWITTER_POST_TEXT_PROMPT = """ -This tool will post a text on Twitter.""" +POST_TEXT_PROMPT = """ +This tool will post text on Twitter.""" -class TwitterPostTextInput(BaseModel): +class PostTextInput(BaseModel): """Input argument schema for twitter post text actions.""" - client: Any = Field( - ..., - description="The tweepy client used to interface with the Twitter API", - ) + # client: Any = Field( + # ..., + # description="The tweepy client used to interface with the Twitter API", + # ) text: str = Field( ..., description="The text to post to twitter", ) -def twitter_post_text(client: tweepy.Client, text: str) -> str: +def post_text(client: tweepy.Client, text: str) -> str: """Post text to Twitter. Args: @@ -35,7 +35,7 @@ def twitter_post_text(client: tweepy.Client, text: str) -> str: try: client.create_tweet(text=text) message = f"Successfully posted!" - except tweepy.error.TweepError as e: + except tweepy.errors.TweepyException as e: message = f"Error posting: {e}" return text diff --git a/cdp-langchain/examples/chatbot/chatbot.py b/cdp-langchain/examples/chatbot/chatbot.py index d3131363d..f7aed7bef 100644 --- a/cdp-langchain/examples/chatbot/chatbot.py +++ b/cdp-langchain/examples/chatbot/chatbot.py @@ -50,9 +50,10 @@ def initialize_agent(): # Initialize twitter_api = TwitterApiWrapper(**values) twitter_toolkit = TwitterToolkit.from_twitter_api_wrapper(twitter_api) - twitter_tools = cdp_toolkit.get_tools() + twitter_tools = twitter_toolkit.get_tools() - tools.extend(twitter_tools) + # tools.extend(twitter_tools) + # tools = twitter_tools # Store buffered conversation history in memory. memory = MemorySaver() @@ -61,7 +62,8 @@ def initialize_agent(): # Create ReAct Agent using the LLM and CDP Agentkit tools. return create_react_agent( llm, - tools=tools, + # tools=tools, + tools=twitter_tools, checkpointer=memory, state_modifier="You are a helpful agent that can interact onchain on the Base Layer 2 using the Coinbase Developer Platform Agentkit. You are empowered to interact onchain using your tools. If you ever need funds, you can request them from the faucet. You can also deploy your own ERC-20 tokens, NFTs, and interact with them. If someone asks you to do something you can't do, you can say so, and encourage them to implement it themselves using the CDP SDK + Agentkit, recommend they go to docs.cdp.coinbase.com for more informaton.", ), config diff --git a/cdp-langchain/poetry.lock b/cdp-langchain/poetry.lock index 372c34cec..a9f5e4036 100644 --- a/cdp-langchain/poetry.lock +++ b/cdp-langchain/poetry.lock @@ -1942,18 +1942,18 @@ typing-extensions = ">=4.7" [[package]] name = "langchain-openai" -version = "0.2.5" +version = "0.2.6" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_openai-0.2.5-py3-none-any.whl", hash = "sha256:745fd9d51a5a3a9cb8839d41f3786ab38dfc539e47c713a806cbca32f3d0875c"}, - {file = "langchain_openai-0.2.5.tar.gz", hash = "sha256:55b98711a880474ec363267bf6cd0e2727dc00e8433731318d063a2184582c28"}, + {file = "langchain_openai-0.2.6-py3-none-any.whl", hash = "sha256:d56e4d9183bdd1a5fb5f3ed9d287f15108e01d631ded170dd330a566f2927b95"}, + {file = "langchain_openai-0.2.6.tar.gz", hash = "sha256:7054e5f64498ad8e59d77cdc210103f5ea4f67258997edc48ae237298adeb316"}, ] [package.dependencies] langchain-core = ">=0.3.15,<0.4.0" -openai = ">=1.52.0,<2.0.0" +openai = ">=1.54.0,<2.0.0" tiktoken = ">=0.7,<1" [[package]] @@ -2019,13 +2019,13 @@ orjson = ">=3.10.1" [[package]] name = "langsmith" -version = "0.1.139" +version = "0.1.140" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.139-py3-none-any.whl", hash = "sha256:2a4a541bfbd0a9727255df28a60048c85bc8c4c6a276975923785c3fd82dc879"}, - {file = "langsmith-0.1.139.tar.gz", hash = "sha256:2f9e4d32fef3ad7ef42c8506448cce3a31ad6b78bb4f3310db04ddaa1e9d744d"}, + {file = "langsmith-0.1.140-py3-none-any.whl", hash = "sha256:3de70183ae19a4ada4d77a8a9f336ff95ca0ead98215771033ee889a2889fe19"}, + {file = "langsmith-0.1.140.tar.gz", hash = "sha256:cb0a717d7b9e6d3145285d7ca0ab216e064cbe7a1ca4139fc04af57fb2315e70"}, ] [package.dependencies] diff --git a/twitter-langchain/Makefile b/twitter-langchain/Makefile new file mode 100644 index 000000000..8880a80f7 --- /dev/null +++ b/twitter-langchain/Makefile @@ -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 ./cdp_langchain + +.PHONY: local-docs +local-docs: docs + cd docs && make html && open ./_build/html/index.html + +.PHONY: test +test: + pytest diff --git a/twitter-langchain/twitter_langchain/twitter_action.py b/twitter-langchain/twitter_langchain/twitter_action.py index 73de16078..4ff0d14a3 100644 --- a/twitter-langchain/twitter_langchain/twitter_action.py +++ b/twitter-langchain/twitter_langchain/twitter_action.py @@ -1,7 +1,7 @@ """Tool allows agents to interact with the Twitter API. To use this tool, you must first set as environment variables: - # TODO: List ENV VARs required. + TWITTER_BEARER_TOKEN """ diff --git a/twitter-langchain/twitter_langchain/twitter_api_wrapper.py b/twitter-langchain/twitter_langchain/twitter_api_wrapper.py index dd34e5dd7..a42ef3219 100644 --- a/twitter-langchain/twitter_langchain/twitter_api_wrapper.py +++ b/twitter-langchain/twitter_langchain/twitter_api_wrapper.py @@ -8,9 +8,9 @@ from langchain_core.utils import get_from_dict_or_env -# from cdp_agentkit_core.actions import ( -# twitter_post_text, -# ) +from cdp_agentkit_core.actions.social.twitter import ( + post_text, +) class TwitterApiWrapper(BaseModel): """Wrapper for Twitter API.""" @@ -23,7 +23,10 @@ class TwitterApiWrapper(BaseModel): def validate_environment(cls, values: dict) -> Any: """Validate that Twitter access token, token secret, and tweepy exists in the environment.""" - bearer_token = get_from_dict_or_env(values, "twitter_bearer_token", "TWITTER_BEARER_TOKEN") + api_key = get_from_dict_or_env(values, "twitter_api_key", "TWITTER_API_KEY") + api_secret = get_from_dict_or_env(values, "twitter_api_secret", "TWITTER_API_SECRET") + access_token = get_from_dict_or_env(values, "twitter_access_token", "TWITTER_ACCESS_TOKEN") + access_token_secret = get_from_dict_or_env(values, "twitter_access_token_secret", "TWITTER_ACCESS_TOKEN_SECRET") try: import tweepy @@ -32,8 +35,18 @@ def validate_environment(cls, values: dict) -> Any: "Tweepy Twitter SDK is not installed. " "Please install it with `pip install tweepy`" ) from None - values["bearer_token"] = bearer_token - client = tweepy.Client(bearer_token) + client = tweepy.Client( + consumer_key=api_key, + consumer_secret=api_secret, + access_token=access_token, + access_token_secret=access_token_secret, + ) + + values["client"] = client + values["api_key"] = api_key + values["api_secret"] = api_secret + values["access_token"] = access_token + values["access_token_secret"] = access_token_secret return values @@ -47,12 +60,12 @@ def post_text_wrapper(self, text: str) -> str: str: A text containing the result of the post text to twitter response. """ - # return twitter_post_text(client=self.client, text=text) - return "" + return post_text(client=self.client, text=text) def run(self, mode: str, **kwargs) -> str: """Run the action via the Twitter API.""" if mode == "post_text": - return self.post_text_wrapper() + return self.post_text_wrapper(**kwargs) else: - raise ValueError("Invalid mode" + mode) + raise ValueError("Invalid mode: " + mode) + diff --git a/twitter-langchain/twitter_langchain/twitter_toolkit.py b/twitter-langchain/twitter_langchain/twitter_toolkit.py index 61004cae9..68388c505 100644 --- a/twitter-langchain/twitter_langchain/twitter_toolkit.py +++ b/twitter-langchain/twitter_langchain/twitter_toolkit.py @@ -3,10 +3,10 @@ from langchain_core.tools import BaseTool from langchain_core.tools.base import BaseToolkit -from cdp_agentkit_core.actions import ( - TWITTER_POST_TEXT_PROMPT, - TwitterPostTextInput, - twitter_post_text, +from cdp_agentkit_core.actions.social.twitter import ( + POST_TEXT_PROMPT, + PostTextInput, + post_text, ) from twitter_langchain.twitter_api_wrapper import TwitterApiWrapper from twitter_langchain.twitter_action import TwitterAction @@ -52,7 +52,7 @@ class TwitterToolkit(BaseToolkit): .. code-block:: none - # TODO: Add list of available tools. + twitter_post_text Use within an agent: .. code-block:: python @@ -83,7 +83,7 @@ class TwitterToolkit(BaseToolkit): Post a hello tweet to the world ==================================[1m Ai Message [0m================================== Tool Calls: - post_tweet (call_iSYJVaM7uchfNHOMJoVPQsOi) + twitter_post_tweet (call_iSYJVaM7uchfNHOMJoVPQsOi) Call ID: call_iSYJVaM7uchfNHOMJoVPQsOi Args: no_input: "hello world" @@ -118,8 +118,8 @@ def from_twitter_api_wrapper(cls, twitter_api_wrapper: TwitterApiWrapper) -> "Tw { "mode": "post_text", "name": "post_text", - "description": TWITTER_POST_TEXT_PROMPT, - "args_schema": TwitterPostTextInput, + "description": POST_TEXT_PROMPT, + "args_schema": PostTextInput, }, ]