Update Langgraph studio Example (#128)
This commit is contained in:
parent
275a3d63b9
commit
7f4280853c
2 changed files with 139 additions and 79 deletions
131
README.md
131
README.md
|
|
@ -2,7 +2,7 @@
|
||||||
<a name="readme-top"></a>
|
<a name="readme-top"></a>
|
||||||
<img
|
<img
|
||||||
src="https://docs.arcade-ai.com/images/logo/arcade-ai-logo.png"
|
src="https://docs.arcade-ai.com/images/logo/arcade-ai-logo.png"
|
||||||
height="200"
|
style="width: 400px;"
|
||||||
>
|
>
|
||||||
</h3>
|
</h3>
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
@ -12,44 +12,41 @@
|
||||||
<a href="https://pepy.tech/project/arcade-ai">
|
<a href="https://pepy.tech/project/arcade-ai">
|
||||||
<img src="https://static.pepy.tech/badge/arcade-ai" alt="Downloads">
|
<img src="https://static.pepy.tech/badge/arcade-ai" alt="Downloads">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/ArcadeAI/arcade-ai/graphs/contributors">
|
<img src="https://img.shields.io/github/last-commit/ArcadeAI/arcade-ai" alt="GitHub last commit">
|
||||||
<img src="https://img.shields.io/github/contributors/arcadeai/arcade-ai.svg" alt="GitHub Contributors">
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://arcade-ai.com">
|
<a href="https://img.shields.io/pypi/pyversions/arcade-ai">
|
||||||
<img src="https://img.shields.io/badge/Visit_Our_Website-orange" alt="Visit arcade-ai.com">
|
<img src="https://img.shields.io/pypi/pyversions/arcade-ai" alt="Python Version">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p align="center">
|
<p align="center" style="display: flex; justify-content: center; gap: 10px;">
|
||||||
<a href="https://x.com/TryArcade">
|
<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>
|
||||||
<a href="https://www.linkedin.com/company/arcade-ai">
|
<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" />
|
<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>
|
||||||
<a href="https://discord.com/invite/GUZEMpEZ9p">
|
<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>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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" target="_blank">Docs</a> •
|
||||||
<a href="https://docs.arcade-ai.com/integrations" target="_blank">Integrations</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://docs.arcade-ai.com/integrations/toolkits" target="_blank">Toolkits</a> •
|
||||||
<a href="https://github.com/ArcadeAI/arcade-py" target="_blank">Python Client</a> •
|
<a href="https://github.com/ArcadeAI/arcade-ai/tree/main/examples" target="_blank">Examples</a>
|
||||||
<a href="https://github.com/ArcadeAI/arcade-js" target="_blank">JavaScript Client</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## What is Arcade AI?
|
## 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).
|
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">
|
<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">
|
<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
|
### Requirements
|
||||||
|
|
||||||
1. An **[Arcade AI account](https://arcade-ai.typeform.com/early-access)** (current a waitlist)
|
1. An **[Arcade AI account](https://arcade-ai.typeform.com/early-access)** (currently a waitlist)
|
||||||
2. **Python 3.10+**. Verify your Python version by running `python --version` or `python3 --version` in your terminal
|
2. **Python 3.10+** and **pip**
|
||||||
3. **pip**, the Python package installer that is typically included with Python
|
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
|
Install the package:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install 'arcade-ai[fastapi]'
|
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
|
```bash
|
||||||
arcade login
|
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.
|
Use the `arcade chat` CLI app to test tools:
|
||||||
|
|
||||||
By default, `arcade chat` will connect to the hosted version of Arcade AI with built-in tools (found in `toolkits`).
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
arcade chat
|
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):
|
Assistant (gpt-4o):
|
||||||
I starred the ArcadeAI/arcade-ai repo on Github for you!
|
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
|
## Arcade Cloud
|
||||||
|
|
||||||
|
|
@ -242,6 +239,60 @@ Arcade AI offers a number of prebuilt toolkits that can be used by agents to int
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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
|
### 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).
|
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).
|
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
|
## 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).
|
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;">
|
<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;">
|
<a href="#readme-top" style="text-decoration: none; color: #007bff; font-weight: bold;">
|
||||||
↑ Back to Top ↑
|
↑ Back to Top ↑
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import os
|
import os
|
||||||
import time
|
from datetime import datetime
|
||||||
|
|
||||||
from configuration import AgentConfigurable
|
from configuration import AgentConfigurable
|
||||||
from langchain_arcade import ArcadeToolManager
|
from langchain_arcade import ArcadeToolManager
|
||||||
|
from langchain_core.messages import HumanMessage, ToolMessage
|
||||||
|
from langchain_core.prompts import ChatPromptTemplate
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
from langgraph.graph import END, START, MessagesState, StateGraph
|
from langgraph.graph import END, START, MessagesState, StateGraph
|
||||||
from langgraph.prebuilt import ToolNode
|
from langgraph.prebuilt import ToolNode
|
||||||
|
|
@ -16,54 +18,73 @@ toolkit = ArcadeToolManager(api_key=arcade_api_key)
|
||||||
tools = toolkit.get_tools(langgraph=True)
|
tools = toolkit.get_tools(langgraph=True)
|
||||||
tool_node = ToolNode(tools)
|
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
|
# Initialize the language model with your OpenAI API key
|
||||||
model = ChatOpenAI(model="gpt-4o", api_key=openai_api_key)
|
model = ChatOpenAI(model="gpt-4o", api_key=openai_api_key).bind_tools(tools)
|
||||||
# make the model aware of the tools
|
prompted_model = prompt | model
|
||||||
model_with_tools = model.bind_tools(tools)
|
|
||||||
|
|
||||||
|
|
||||||
# Define the agent function that invokes the model
|
|
||||||
def call_agent(state):
|
def call_agent(state):
|
||||||
|
"""Define the agent function that invokes the model"""
|
||||||
messages = state["messages"]
|
messages = state["messages"]
|
||||||
response = model_with_tools.invoke(messages)
|
# replace placeholder with messages from state
|
||||||
# Return the updated message history
|
response = prompted_model.invoke({"messages": messages})
|
||||||
return {"messages": [*messages, response]}
|
return {"messages": [response]}
|
||||||
|
|
||||||
|
|
||||||
# Function to determine the next step based on the model's response
|
def should_continue(state: MessagesState, config: dict):
|
||||||
def should_continue(state: MessagesState):
|
"""Function to determine the next step based on the model's response"""
|
||||||
last_message = state["messages"][-1]
|
last_message = state["messages"][-1]
|
||||||
if last_message.tool_calls:
|
if last_message.tool_calls:
|
||||||
tool_name = last_message.tool_calls[0]["name"]
|
user_id = config["configurable"].get("user_id")
|
||||||
if toolkit.requires_auth(tool_name):
|
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
|
# If the tool requires authorization, proceed to the authorization step
|
||||||
return "authorization"
|
return "authorization"
|
||||||
else:
|
|
||||||
# If no authorization is needed, proceed to execute the tool
|
|
||||||
return "tools"
|
|
||||||
# If no tool calls are present, end the workflow
|
# If no tool calls are present, end the workflow
|
||||||
return END
|
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):
|
def authorize(state: MessagesState, config: dict):
|
||||||
|
"""Function to handle tool authorization"""
|
||||||
user_id = config["configurable"].get("user_id")
|
user_id = config["configurable"].get("user_id")
|
||||||
tool_name = state["messages"][-1].tool_calls[0]["name"]
|
tool_name = state["messages"][-1].tool_calls[0]["name"]
|
||||||
auth_response = toolkit.authorize(tool_name, user_id)
|
auth_response = toolkit.authorize(tool_name, user_id)
|
||||||
|
|
||||||
if auth_response.status == "completed":
|
auth_message = (
|
||||||
# Authorization is complete; proceed to the next step
|
f"Please authorize the application in your browser:\n\n {auth_response.authorization_url}"
|
||||||
return {"messages": state["messages"]}
|
)
|
||||||
else:
|
tool_call_id = state["messages"][-1].tool_calls[0]["id"]
|
||||||
# Prompt the user to complete authorization
|
response = ToolMessage(
|
||||||
print("Please authorize the application in your browser:")
|
content=auth_message,
|
||||||
print(auth_response.authorization_url)
|
tool_call_id=tool_call_id,
|
||||||
input("Press Enter after completing authorization...")
|
)
|
||||||
|
# Add the new message to the message history and add a new human message
|
||||||
# Poll for authorization status
|
# saying that the agent should try again
|
||||||
while not toolkit.is_authorized(auth_response.authorization_id):
|
try_message = HumanMessage(
|
||||||
time.sleep(3)
|
content="Please try the previous tool call again now that you are authorized."
|
||||||
return {"messages": state["messages"]}
|
)
|
||||||
|
return {"messages": [response, try_message]}
|
||||||
|
|
||||||
|
|
||||||
# Build the workflow graph
|
# Build the workflow graph
|
||||||
|
|
@ -73,12 +94,14 @@ workflow = StateGraph(MessagesState, AgentConfigurable)
|
||||||
workflow.add_node("agent", call_agent)
|
workflow.add_node("agent", call_agent)
|
||||||
workflow.add_node("tools", tool_node)
|
workflow.add_node("tools", tool_node)
|
||||||
workflow.add_node("authorization", authorize)
|
workflow.add_node("authorization", authorize)
|
||||||
|
# workflow.add_node("wait_for_auth", wait_for_auth)
|
||||||
|
|
||||||
# Define the edges and control flow
|
# Define the edges and control flow
|
||||||
workflow.add_edge(START, "agent")
|
workflow.add_edge(START, "agent")
|
||||||
workflow.add_conditional_edges("agent", should_continue, ["authorization", "tools", END])
|
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")
|
workflow.add_edge("tools", "agent")
|
||||||
|
|
||||||
# Compile the graph
|
# Compile the graph with an interrupt after the authorization node
|
||||||
graph = workflow.compile()
|
# so that we can prompt the user to authorize the application
|
||||||
|
graph = workflow.compile(interrupt_after=["authorization"])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue