From 4af4c7706a7c3617d8eb3c2443096cdc634d74b0 Mon Sep 17 00:00:00 2001 From: Christopher Gerber Date: Wed, 6 Nov 2024 22:37:36 -0800 Subject: [PATCH] first pass implementing twitter account details action --- .../actions/social/twitter/__init__.py | 14 +++-- .../actions/social/twitter/account_details.py | 36 +++++++++++ .../examples/account_details/Makefile | 10 +++ .../account_details/account_details.py | 63 +++++++++++++++++++ .../twitter_langchain/twitter_api_wrapper.py | 18 +++++- .../twitter_langchain/twitter_toolkit.py | 9 +++ 6 files changed, 142 insertions(+), 8 deletions(-) create mode 100644 cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py create mode 100644 twitter-langchain/examples/account_details/Makefile create mode 100644 twitter-langchain/examples/account_details/account_details.py 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 4555629c5..ae5d0539a 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 @@ -1,9 +1,11 @@ -from cdp_agentkit_core.actions.social.twitter.post_tweet import ( - POST_TWEET_PROMPT as POST_TWEET_PROMPT, +from cdp_agentkit_core.actions.social.twitter.account_details import ( + ACCOUNT_DETAILS_PROMPT as ACCOUNT_DETAILS_PROMPT, ) +from cdp_agentkit_core.actions.social.twitter.account_details import AccountDetailsInput as AccountDetailsInput +from cdp_agentkit_core.actions.social.twitter.account_details import account_details as account_details + 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, + 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 diff --git a/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py new file mode 100644 index 000000000..7de241aed --- /dev/null +++ b/cdp-agentkit-core/cdp_agentkit_core/actions/social/twitter/account_details.py @@ -0,0 +1,36 @@ +from operator import itemgetter + +import tweepy +from pydantic import BaseModel, Field + +ACCOUNT_DETAILS_PROMPT = """ +This tool will return account details for the authenticated user context.""" + +class AccountDetailsInput(BaseModel): + """Input argument schema for twitter account details action.""" + +def account_details(client: tweepy.Client) -> str: + """. + + Args: + + Returns: + str: A message containing account details for the authenticated user context. + + """ + message = "" + + try: + response = client.get_me() + user = response.data + # user_id, user_name, username = itemgetter('id', 'name', 'username') + + message = f"""Successfully retrieved authenticated user account details. Please present the following as json and not markdown: + id: {user.id} + name: {user.name} + username: {user.username} + link: https://x.com/{user.username}""" + except tweepy.errors.TweepyException as e: + message = f"Error retrieving authenticated user account details: {e}" + + return message diff --git a/twitter-langchain/examples/account_details/Makefile b/twitter-langchain/examples/account_details/Makefile new file mode 100644 index 000000000..b2bf7df51 --- /dev/null +++ b/twitter-langchain/examples/account_details/Makefile @@ -0,0 +1,10 @@ +ifneq (,$(wildcard ./.env)) + include .env +endif + +export + +.PHONY: run +run: + poetry install --with dev + poetry run python account_details.py diff --git a/twitter-langchain/examples/account_details/account_details.py b/twitter-langchain/examples/account_details/account_details.py new file mode 100644 index 000000000..1f6b0763d --- /dev/null +++ b/twitter-langchain/examples/account_details/account_details.py @@ -0,0 +1,63 @@ +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 - get account details +events = agent_executor.stream( + { + "messages": [ + HumanMessage(content=f"Please obtain my twitter account information"), + ], + }, + stream_mode="values", +) + +for event in events: + event["messages"][-1].pretty_print() + +# ================================ Human Message ================================= +# What is my twitter account profile link? +# ================================== Ai Message ================================== +# Tool Calls: +# account_details (call_pYME8H1tHfdMakFZ1FTS0VBX) +# Call ID: call_pYME8H1tHfdMakFZ1FTS0VBX +# Args: +# ================================= Tool Message ================================= +# Name: account_details + +# Successfully retrieved authenticated user account details. Please present the following as json and not markdown: +# id: 1853889445319331840 +# name: CDP AgentKit +# username: CDPAgentKit +# link: https://x.com/CDPAgentKit +# ================================== Ai Message ================================== +# { +# "id": "[REDACTED]", +# "name": "[REDACTED]", +# "username": "[REDACTED]", +# "link": "[REDACTED]" +# } diff --git a/twitter-langchain/twitter_langchain/twitter_api_wrapper.py b/twitter-langchain/twitter_langchain/twitter_api_wrapper.py index 7acdde7e5..447813df8 100644 --- a/twitter-langchain/twitter_langchain/twitter_api_wrapper.py +++ b/twitter-langchain/twitter_langchain/twitter_api_wrapper.py @@ -1,12 +1,12 @@ """Util that calls Twitter API.""" - from typing import Any from langchain_core.utils import get_from_dict_or_env from pydantic import BaseModel, model_validator from cdp_agentkit_core.actions.social.twitter import ( + account_details, post_tweet, ) @@ -48,6 +48,18 @@ def validate_environment(cls, values: dict) -> Any: return values + def account_details_wrapper(self) -> str: + """. + + Args: + + Returns: + str: A message containing account details for the authenticated user context in JSON format. + + """ + + return account_details(client=self.client) + def post_tweet_wrapper(self, tweet: str) -> str: """Post tweet to Twitter. @@ -64,7 +76,9 @@ def post_tweet_wrapper(self, tweet: str) -> str: def run(self, mode: str, **kwargs) -> str: """Run the action via the Twitter API.""" - if mode == "post_tweet": + if mode == "account_details": + return self.account_details_wrapper() + elif mode == "post_tweet": return self.post_tweet_wrapper(**kwargs) else: raise ValueError("Invalid mode: " + mode) diff --git a/twitter-langchain/twitter_langchain/twitter_toolkit.py b/twitter-langchain/twitter_langchain/twitter_toolkit.py index a712e1bed..f01f00b9d 100644 --- a/twitter-langchain/twitter_langchain/twitter_toolkit.py +++ b/twitter-langchain/twitter_langchain/twitter_toolkit.py @@ -4,6 +4,8 @@ from langchain_core.tools.base import BaseToolkit from cdp_agentkit_core.actions.social.twitter import ( + ACCOUNT_DETAILS_PROMPT, + AccountDetailsInput, POST_TWEET_PROMPT, PostTweetInput, ) @@ -55,6 +57,7 @@ class TwitterToolkit(BaseToolkit): .. code-block:: none + account_details post_tweet Use within an agent: @@ -120,6 +123,12 @@ def from_twitter_api_wrapper(cls, twitter_api_wrapper: TwitterApiWrapper) -> "Tw """ actions: list[dict] = [ + { + "mode": "account_details", + "name": "account_details", + "description": ACCOUNT_DETAILS_PROMPT, + "args_schema": AccountDetailsInput, + }, { "mode": "post_tweet", "name": "post_tweet",