Update Langgraph studio Example (#128)

This commit is contained in:
Sam Partee 2024-10-28 09:51:02 -07:00 committed by GitHub
parent 275a3d63b9
commit 7f4280853c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 139 additions and 79 deletions

131
README.md
View file

@ -2,7 +2,7 @@
<a name="readme-top"></a>
<img
src="https://docs.arcade-ai.com/images/logo/arcade-ai-logo.png"
height="200"
style="width: 400px;"
>
</h3>
<div align="center">
@ -12,44 +12,41 @@
<a href="https://pepy.tech/project/arcade-ai">
<img src="https://static.pepy.tech/badge/arcade-ai" alt="Downloads">
</a>
<a href="https://github.com/ArcadeAI/arcade-ai/graphs/contributors">
<img src="https://img.shields.io/github/contributors/arcadeai/arcade-ai.svg" alt="GitHub Contributors">
<img src="https://img.shields.io/github/last-commit/ArcadeAI/arcade-ai" alt="GitHub last commit">
</a>
<a href="https://arcade-ai.com">
<img src="https://img.shields.io/badge/Visit_Our_Website-orange" alt="Visit arcade-ai.com">
<a href="https://img.shields.io/pypi/pyversions/arcade-ai">
<img src="https://img.shields.io/pypi/pyversions/arcade-ai" alt="Python Version">
</a>
</div>
<div>
<p align="center">
<p align="center" style="display: flex; justify-content: center; gap: 10px;">
<a href="https://x.com/TryArcade">
<img src="https://img.shields.io/badge/Follow%20on%20X-000000?style=for-the-badge&logo=x&logoColor=white" alt="Follow on X" />
<img src="https://img.shields.io/badge/Follow%20on%20X-000000?style=for-the-badge&logo=x&logoColor=white" alt="Follow on X" style="width: 125px;height: 25px; padding-top: .8px; border-radius: 5px;" />
</a>
<a href="https://www.linkedin.com/company/arcade-ai">
<img src="https://img.shields.io/badge/Follow%20on%20LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white" alt="Follow on LinkedIn" />
<a href="https://www.linkedin.com/company/arcade-ai" >
<img src="https://img.shields.io/badge/Follow%20on%20LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white" alt="Follow on LinkedIn" style="width: 150px; padding-top: 1.5px;height: 22px; border-radius: 5px;" />
</a>
<a href="https://discord.com/invite/GUZEMpEZ9p">
<img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Join our Discord" />
<img src="https://img.shields.io/badge/Join%20our%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" alt="Join our Discord" style="width: 150px; padding-top: 1.5px; height: 22px; border-radius: 5px;" />
</a>
</p>
</div>
<p align="center">
<p align="center" style="display: flex; justify-content: center; gap: 5px; font-size: 15px;">
<a href="https://docs.arcade-ai.com" target="_blank">Docs</a>
<a href="https://docs.arcade-ai.com/integrations" target="_blank">Integrations</a>
<a href="https://github.com/ArcadeAI/cookbook" target="_blank">Cookbook</a>
<a href="https://github.com/ArcadeAI/arcade-py" target="_blank">Python Client</a>
<a href="https://github.com/ArcadeAI/arcade-js" target="_blank">JavaScript Client</a>
</p>
<a href="https://docs.arcade-ai.com/integrations/toolkits" target="_blank">Toolkits</a>
<a href="https://github.com/ArcadeAI/arcade-ai/tree/main/examples" target="_blank">Examples</a>
## What is Arcade AI?
[Arcade AI](https://arcade-ai.com?ref=github) offers developer-focused tooling and APIs designed to improve the capabilities of LLM applications and agents.
[Arcade AI](https://arcade-ai.com?ref=github) provides developer-focused tooling and APIs designed to improve the capabilities of LLM applications and agents.
By providing an authentication and authorization layer for agents and the tools agents use, Arcade AI connects agentic applications with your users' data and services - like accessing their Gmail, GitHub, Zoom, Spotify, LinkedIn, and more.
By removing the complexity of connecting agentic applications with your users' data and services, Arcade AI enables developers to focus on building their agentic applications.
To learn more, check out our [documentation](https://docs.arcade-ai.com).
_Pst. hey, you, join our stargazers! It's free!_
_Pst. hey, you, give us a star if you like it!_
<a href="https://github.com/arcadeai/arcade-ai">
<img src="https://img.shields.io/github/stars/arcadeai/arcade-ai.svg?style=social&label=Star&maxAge=2592000" alt="GitHub stars">
@ -59,52 +56,52 @@ _Pst. hey, you, join our stargazers! It's free!_
### Requirements
1. An **[Arcade AI account](https://arcade-ai.typeform.com/early-access)** (current a waitlist)
2. **Python 3.10+**. Verify your Python version by running `python --version` or `python3 --version` in your terminal
3. **pip**, the Python package installer that is typically included with Python
1. An **[Arcade AI account](https://arcade-ai.typeform.com/early-access)** (currently a waitlist)
2. **Python 3.10+** and **pip**
### Installation
Install the package:
```bash
pip install 'arcade-ai[fastapi]'
```
Then login to your account (we're working through the waitlist as fast as we can!)
Log in to your account:
```bash
arcade login
```
This will open a browser window to login.
This opens a browser window for authentication.
### Verify Installation using `arcade chat`
### Verify Installation with `arcade chat`
The `arcade-ai` package comes with a CLI app called `arcade chat` that is used to test tools as you develop them.
By default, `arcade chat` will connect to the hosted version of Arcade AI with built-in tools (found in `toolkits`).
Use the `arcade chat` CLI app to test tools:
```bash
arcade chat
```
This launches a chat with the Arcade Cloud Engine (hosted at `api.arcade-ai.com`). All pre-built Arcade tools are available to use.
This connects to the Arcade Cloud Engine (`api.arcade-ai.com`) with all pre-built Arcade tools.
For example, try asking:
For example, try:
```
star the ArcadeAI/arcade-ai repo on Github
User (dev@arcade-ai.com):
> star the ArcadeAI/arcade-ai repo on Github
```
Arcade AI will ask you to authorize with GitHub, and then the AI assistant will star the [ArcadeAI/arcade-ai](https://github.com/ArcadeAI/arcade-ai) repo on your behalf.
Arcade AI will prompt you to authorize with GitHub and will star the [ArcadeAI/arcade-ai](https://github.com/ArcadeAI/arcade-ai) repo on your behalf.
You'll see output similar to this:
You'll see:
```
Assistant (gpt-4o):
I starred the ArcadeAI/arcade-ai repo on Github for you!
```
You can use Ctrl-C to exit the chat at any time.
Press `Ctrl-C` to exit the chat.
## Arcade Cloud
@ -242,6 +239,60 @@ Arcade AI offers a number of prebuilt toolkits that can be used by agents to int
</tbody>
</table>
### Supported Language Models
The LLM API supports a variety of language models. Currently, the ones supported in Arcade Cloud are OpenAI, Anthropic, Ollama, and Groq.
<table>
<thead>
<tr>
<th style="text-align: center;">Model</th>
<th style="text-align: center;">Provider</th>
<th style="text-align: center;">Documentation</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">
<img src="https://docs.arcade-ai.com/images/icons/openai.png" alt="OpenAI" width="30" height="30" />
</td>
<td style="text-align: center;">OpenAI</td>
<td style="text-align: center;">
<a href="https://docs.arcade-ai.com/integrations/models/openai">OpenAI Models Docs</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<img src="https://docs.arcade-ai.com/images/icons/anthropic.png" alt="Anthropic" width="30" height="30" />
</td>
<td style="text-align: center;">Anthropic</td>
<td style="text-align: center;">
<a href="https://docs.arcade-ai.com/integrations/models/anthropic">Anthropic Models Docs</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<img src="https://docs.arcade-ai.com/images/icons/ollama.png" alt="Ollama" width="30" height="30" />
</td>
<td style="text-align: center;">Ollama</td>
<td style="text-align: center;">
<a href="https://docs.arcade-ai.com/integrations/models/ollama">Ollama Models Docs</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<img src="https://docs.arcade-ai.com/images/icons/groq.png" alt="Groq" width="30" height="30" />
</td>
<td style="text-align: center;">Groq</td>
<td style="text-align: center;">
<a href="https://docs.arcade-ai.com/integrations/models/groq">Groq Models Docs</a>
</td>
</tr>
</tbody>
</table>
For more information, refer to the [models documentation](https://docs.arcade-ai.com/integrations/models/openai).
### Building Your Own Tools
Learn how to build your own tools by following our [creating a custom toolkit guide](https://docs.arcade-ai.com/tools/overview).
@ -252,24 +303,10 @@ Arcade AI enables you to evaluate your custom tools to ensure they function corr
Learn how to evaluate your tools by following our [evaluating tools guide](https://docs.arcade-ai.com/home/evaluate-tools/create-an-evaluation-suite).
### Models
<img src="https://docs.arcade-ai.com/images/icons/openai.png" alt="" width="30" height="30" style="vertical-align: top;" /><img src="https://docs.arcade-ai.com/images/icons/anthropic.png" alt="" width="30" height="30" style="vertical-align: top;" /><img src="https://docs.arcade-ai.com/images/icons/ollama.png" alt="" width="30" height="30" style="vertical-align: top;" /><img src="https://docs.arcade-ai.com/images/icons/groq.png" alt="" width="30" height="30" style="vertical-align: top;" />
<br><br>
Arcade AI supports a variety of model providers when using the Arcade AI LLM API.
To see all available models, refer to the [models documentation](https://docs.arcade-ai.com/integrations/models/openai).
## Contributing
We love contributions! Please read our [contributing guide](CONTRIBUTING.md) before submitting a pull request. If you'd like to self-host, refer to the [self-hosting documentation](https://docs.arcade-ai.com/home/install/overview).
## Contributors
<a href="https://github.com/ArcadeAI/arcade-ai/graphs/contributors">
<img alt="contributors" src="https://contrib.rocks/image?repo=ArcadeAI/arcade-ai"/>
</a>
<p align="right" style="font-size: 14px; color: #555; margin-top: 20px;">
<a href="#readme-top" style="text-decoration: none; color: #007bff; font-weight: bold;">
↑ Back to Top ↑

View file

@ -1,8 +1,10 @@
import os
import time
from datetime import datetime
from configuration import AgentConfigurable
from langchain_arcade import ArcadeToolManager
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode
@ -16,54 +18,73 @@ toolkit = ArcadeToolManager(api_key=arcade_api_key)
tools = toolkit.get_tools(langgraph=True)
tool_node = ToolNode(tools)
PROMPT_TEMPLATE = f"""
You are a helpful assistant who can use tools to help users with tasks
Today's date is {datetime.now().strftime("%Y-%m-%d")}
ALL RESPONSES should be in plain text and not markdown.
"""
# prompt for the main agent
prompt = ChatPromptTemplate.from_messages([
("system", PROMPT_TEMPLATE),
("placeholder", "{messages}"),
])
# Initialize the language model with your OpenAI API key
model = ChatOpenAI(model="gpt-4o", api_key=openai_api_key)
# make the model aware of the tools
model_with_tools = model.bind_tools(tools)
model = ChatOpenAI(model="gpt-4o", api_key=openai_api_key).bind_tools(tools)
prompted_model = prompt | model
# Define the agent function that invokes the model
def call_agent(state):
"""Define the agent function that invokes the model"""
messages = state["messages"]
response = model_with_tools.invoke(messages)
# Return the updated message history
return {"messages": [*messages, response]}
# replace placeholder with messages from state
response = prompted_model.invoke({"messages": messages})
return {"messages": [response]}
# Function to determine the next step based on the model's response
def should_continue(state: MessagesState):
def should_continue(state: MessagesState, config: dict):
"""Function to determine the next step based on the model's response"""
last_message = state["messages"][-1]
if last_message.tool_calls:
tool_name = last_message.tool_calls[0]["name"]
if toolkit.requires_auth(tool_name):
user_id = config["configurable"].get("user_id")
tool_name = state["messages"][-1].tool_calls[0]["name"]
auth_response = toolkit.authorize(tool_name, user_id)
if auth_response.status == "completed":
return "tools"
else:
# If the tool requires authorization, proceed to the authorization step
return "authorization"
else:
# If no authorization is needed, proceed to execute the tool
return "tools"
# If no tool calls are present, end the workflow
return END
# Function to handle tool authorization
def wait_for_auth(state: MessagesState):
last_message = state["messages"][-1]
if isinstance(last_message, HumanMessage):
return "agent"
return "tools"
def authorize(state: MessagesState, config: dict):
"""Function to handle tool authorization"""
user_id = config["configurable"].get("user_id")
tool_name = state["messages"][-1].tool_calls[0]["name"]
auth_response = toolkit.authorize(tool_name, user_id)
if auth_response.status == "completed":
# Authorization is complete; proceed to the next step
return {"messages": state["messages"]}
else:
# Prompt the user to complete authorization
print("Please authorize the application in your browser:")
print(auth_response.authorization_url)
input("Press Enter after completing authorization...")
# Poll for authorization status
while not toolkit.is_authorized(auth_response.authorization_id):
time.sleep(3)
return {"messages": state["messages"]}
auth_message = (
f"Please authorize the application in your browser:\n\n {auth_response.authorization_url}"
)
tool_call_id = state["messages"][-1].tool_calls[0]["id"]
response = ToolMessage(
content=auth_message,
tool_call_id=tool_call_id,
)
# Add the new message to the message history and add a new human message
# saying that the agent should try again
try_message = HumanMessage(
content="Please try the previous tool call again now that you are authorized."
)
return {"messages": [response, try_message]}
# Build the workflow graph
@ -73,12 +94,14 @@ workflow = StateGraph(MessagesState, AgentConfigurable)
workflow.add_node("agent", call_agent)
workflow.add_node("tools", tool_node)
workflow.add_node("authorization", authorize)
# workflow.add_node("wait_for_auth", wait_for_auth)
# Define the edges and control flow
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue, ["authorization", "tools", END])
workflow.add_edge("authorization", "tools")
workflow.add_edge("authorization", "agent")
workflow.add_edge("tools", "agent")
# Compile the graph
graph = workflow.compile()
# Compile the graph with an interrupt after the authorization node
# so that we can prompt the user to authorize the application
graph = workflow.compile(interrupt_after=["authorization"])