diff --git a/contrib/langchain/examples/README.md b/contrib/langchain/examples/README.md new file mode 100644 index 000000000..7b387b6f7 --- /dev/null +++ b/contrib/langchain/examples/README.md @@ -0,0 +1,187 @@ +# LangChain-Arcade Examples + +Examples demonstrating the integration between [Arcade AI](https://arcade.dev) tools and [LangChain](https://langchain.com)/[DeepAgents](https://github.com/langchain-ai/deepagents). + +## Research Agent + +An AI agent that researches topics, creates Google Docs reports, and emails them to you. + +> **Note:** This example requires **Python 3.11+** (deepagents requirement). + +### Features + +- πŸ”¬ **End-to-end research workflow** - Research β†’ Create Doc β†’ Email +- πŸ” **Just-in-time OAuth** - Automatic authorization when tools need access +- πŸ“„ **Creates real Google Docs** - Reports saved to your Google Drive +- πŸ“§ **Sends via Gmail** - Delivers report link to your inbox +- πŸ€– **Powered by DeepAgents** - Uses LangChain's deep agent framework + +### Setup + +#### 1. Install Dependencies + +```bash +cd contrib/langchain +pip install -e ".[dev]" +``` + +#### 2. Configure Environment + +```bash +cd examples +cp env.example .env +``` + +Edit `.env` with your credentials: + +```env +# Get your Arcade API key at https://arcade.dev +ARCADE_API_KEY=arc_your_key_here + +# OpenAI or Anthropic API key +OPENAI_API_KEY=sk-your_key_here + +# Your email (used for OAuth authorization) +USER_EMAIL=your-email@gmail.com + +# Email to receive research reports +RECIPIENT_EMAIL=recipient@example.com +``` + +### Running the Agent + +#### Interactive Mode + +```bash +python research_agent.py +``` + +#### Single Query Mode + +```bash +python research_agent.py --query "Research power banks released in 2025" +``` + +### Example Queries + +- `Research the latest trends in AI chips` +- `Research power banks released in 2025` +- `Research electric vehicle market in Europe` +- `Research remote work tools for 2024` + +The agent will automatically: +1. Research the topic +2. Create a Google Doc with findings +3. Email the document link to you + +### What to Expect + +#### 1. Initialization +``` +πŸš€ Initializing Research Agent... +βœ“ Loaded 55 tools +``` + +#### 2. Just-in-Time OAuth Authorization + +First time only - you'll see authorization prompts: + +``` +πŸ“‹ Checking tool authorizations... + +πŸ” Authorization required for: Google_CreateDocumentFromText + + Please authorize by visiting: + πŸ”— https://accounts.arcade.dev/oauth/authorize?... + + Waiting for authorization... +``` + +**Click the link** β†’ Sign in with Google β†’ Grant permissions β†’ Agent continues! + +``` + βœ“ Authorization completed! + +πŸ” Authorization required for: Google_SendEmail + + Please authorize by visiting: + πŸ”— https://accounts.arcade.dev/oauth/authorize?... + + Waiting for authorization... + βœ“ Authorization completed! +``` + +#### 3. Agent Execution + +``` +βœ“ Using OpenAI GPT-4o +βœ“ Agent ready! +βœ“ Reports will be sent to: recipient@example.com + +============================================================ +πŸ”¬ Research Agent - Interactive Mode +============================================================ + +πŸ“§ User: your-email@gmail.com +πŸ“¬ Reports sent to: recipient@example.com + +Examples: + β€’ Research the latest trends in AI chips + β€’ Research power banks released in 2025 + β€’ Research electric vehicle market in Europe + +The agent will create a Google Doc and email it to you. +Type 'quit' to exit. + +You: Research power banks released in 2025 +``` + +#### 4. Tool Execution & Results + +``` +──────────────────────────────────────────────────────────── +πŸ“ Query: Research power banks released in 2025 +──────────────────────────────────────────────────────────── + + πŸ”§ Tool: Google_CreateDocumentFromText + πŸ“„ Document: https://docs.google.com/document/d/1ABC.../edit + + πŸ”§ Tool: Google_SendEmail + βœ“ Email sent successfully + +πŸ€– Agent: I've created a research report on power banks released in 2025 +and sent it to recipient@example.com. You can also view the document here: +https://docs.google.com/document/d/1ABC.../edit +``` + +### Troubleshooting + +#### "Missing required environment variables" +Ensure your `.env` file exists and has valid API keys. + +#### "Authorization required" keeps appearing +- Click the authorization URL and complete the OAuth flow in your browser +- Make sure you're signed into the correct Google account +- Grant all requested permissions + +#### Email not received +- Check your spam folder +- Verify RECIPIENT_EMAIL is correct in `.env` +- Ensure Gmail authorization was completed + +### Architecture + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ DeepAgents │────▢│ langchain- │────▢│ Arcade API β”‚ +β”‚ (LangChain) β”‚ β”‚ arcade β”‚ β”‚ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Google Workspaceβ”‚ + β”‚ β€’ Docs β”‚ + β”‚ β€’ Gmail β”‚ + β”‚ β€’ Calendar β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` diff --git a/contrib/langchain/examples/env.example b/contrib/langchain/examples/env.example new file mode 100644 index 000000000..d49779f3a --- /dev/null +++ b/contrib/langchain/examples/env.example @@ -0,0 +1,16 @@ +# Copy this file to .env and fill in your values +# cp env.example .env + +# Arcade API Key - Get yours at https://arcade.dev +ARCADE_API_KEY=arc_... + +# OpenAI API Key - Get yours at https://platform.openai.com/api-keys +OPENAI_API_KEY=sk-... + +# Your email address - used for Arcade OAuth authorization +USER_EMAIL=your-email@gmail.com + +# Where to send research reports - the agent will email the Google Doc link here +RECIPIENT_EMAIL=recipient@example.com + + diff --git a/contrib/langchain/examples/research_agent.py b/contrib/langchain/examples/research_agent.py new file mode 100644 index 000000000..2dddd38ef --- /dev/null +++ b/contrib/langchain/examples/research_agent.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python3 +""" +Industry Research Agent with DeepAgents + Arcade + +An AI agent that researches topics and creates Google Docs reports. + +Features: +- Uses Arcade's Google and Gmail tools +- Just-in-time OAuth authorization flow +- Creates Google Docs with research findings +- Can send reports via email + +Requirements: + pip install langchain-arcade[dev] + +Environment Variables (create a .env file or export): + ARCADE_API_KEY: Your Arcade API key (https://arcade.dev) + OPENAI_API_KEY: Your OpenAI API key (or ANTHROPIC_API_KEY) + USER_EMAIL: Your email for Arcade authorization + +Usage: + # Interactive mode + python research_agent.py + + # Single query mode + python research_agent.py --query "Create a Google Doc about AI trends" +""" + +import os +import sys +from pathlib import Path + +# Load environment from .env file +try: + from dotenv import load_dotenv + env_path = Path(__file__).parent / ".env" + if env_path.exists(): + load_dotenv(env_path) + print(f"βœ“ Loaded environment from {env_path}") +except ImportError: + pass + +from deepagents import create_deep_agent +from langchain.chat_models import init_chat_model +from langgraph.checkpoint.memory import MemorySaver + +from langchain_arcade import ToolManager + + +SYSTEM_PROMPT_TEMPLATE = """You are a research assistant. When given a topic, do these steps IN ORDER: + +STEP 1: Search the web using Search_SearchGoogle tool to find real, current information about the topic. + Do 2-3 searches with different queries to get comprehensive results. + +STEP 2: Create a Google Doc using Google_CreateDocumentFromText with: + - title: "[Topic] Research Report" + - text_content: A detailed report based on the ACTUAL search results. Include: + * Executive Summary + * Key Findings (cite sources from search results) + * Details and Analysis + * Conclusion + +STEP 3: Send the document link via email using Google_SendEmail: + - recipient: {recipient_email} + - subject: "Research Report: [Topic]" + - body: "Here is your research report on [Topic]: [document URL]" + +IMPORTANT: +- Use REAL data from web searches, not made-up content +- Execute tools directly, do NOT delegate +- The recipient email is: {recipient_email}""" + + +def create_agent(manager: ToolManager, recipient_email: str): + """Create the research agent with tools and model.""" + tools = manager.to_langchain() + + # Format system prompt with recipient email + system_prompt = SYSTEM_PROMPT_TEMPLATE.format(recipient_email=recipient_email) + + # Select model based on available API key + if os.environ.get("OPENAI_API_KEY"): + model = init_chat_model("openai:gpt-4o") + print("βœ“ Using OpenAI GPT-4o") + elif os.environ.get("ANTHROPIC_API_KEY"): + model = init_chat_model("anthropic:claude-sonnet-4-20250514") + print("βœ“ Using Anthropic Claude") + else: + raise ValueError("No LLM API key found (OPENAI_API_KEY or ANTHROPIC_API_KEY)") + + return create_deep_agent( + model=model, + tools=tools, + system_prompt=system_prompt, + checkpointer=MemorySaver(), + ) + + +def handle_authorization(manager: ToolManager, tool_name: str, user_id: str) -> bool: + """Handle OAuth authorization for a tool. Returns True if authorized.""" + if not manager.requires_auth(tool_name): + return True + + print(f"\nπŸ” Authorization required for: {tool_name}") + + auth_response = manager.authorize(tool_name, user_id) + + if auth_response.status == "completed": + print(" βœ“ Already authorized!") + return True + + print(f"\n Please authorize by visiting:") + print(f" πŸ”— {auth_response.url}") + print(f"\n Waiting for authorization...") + + try: + manager.wait_for_auth(auth_response.id) + print(" βœ“ Authorization completed!") + return True + except KeyboardInterrupt: + print("\n βœ— Authorization cancelled") + return False + + +def pre_authorize_tools(manager: ToolManager, user_id: str) -> None: + """Pre-authorize key tools before starting the agent.""" + # These are the main tools the research agent uses + key_tools = [ + "Search_SearchGoogle", # Web search for research + "Google_CreateDocumentFromText", # Create research reports + "Google_SendEmail", # Email the reports + ] + + print("\nπŸ“‹ Checking tool authorizations...") + + for tool_name in key_tools: + if tool_name in manager.tools: + if not handle_authorization(manager, tool_name, user_id): + print(f" ⚠️ Skipping {tool_name} - not authorized") + else: + print(f" ⚠️ Tool {tool_name} not available") + + +def run_agent(manager: ToolManager, agent, user_id: str, query: str) -> None: + """Run the agent with a query and display results.""" + config = { + "configurable": { + "thread_id": "research-session", + "user_id": user_id, + }, + "recursion_limit": 50, + } + + print(f"\n{'─' * 60}") + print(f"πŸ“ Query: {query}") + print(f"{'─' * 60}\n") + + try: + for chunk in agent.stream( + {"messages": [{"role": "user", "content": query}]}, + config=config, + stream_mode="values", + ): + messages = chunk.get("messages", []) + if not messages: + continue + + last_msg = messages[-1] + + if last_msg.type == "tool": + tool_name = getattr(last_msg, "name", "unknown") + + # Skip internal planning tools + if tool_name in ("task", "delegate", "plan"): + continue + + # Simple status indicator + content = str(getattr(last_msg, "content", "")) + status = "⚠️" if "error" in content.lower() else "βœ“" + print(f" {status} {tool_name}") + + elif last_msg.type == "ai" and not getattr(last_msg, "tool_calls", None): + content = getattr(last_msg, "content", "") + if content: + print(f"\nπŸ€– Agent: {content}\n") + + except Exception as e: + if "authorization" in str(e).lower(): + print(f"\nπŸ” Authorization needed. Please complete OAuth and retry.\n") + else: + print(f"\n❌ Error: {e}\n") + + +def interactive_mode(manager: ToolManager, agent, user_id: str, recipient_email: str) -> None: + """Run the agent in interactive mode.""" + print(f"\n{'=' * 60}") + print("πŸ”¬ Research Agent - Interactive Mode") + print(f"{'=' * 60}") + print(f"\nπŸ“§ User: {user_id}") + print(f"πŸ“¬ Reports sent to: {recipient_email}") + print("\nExamples:") + print(" β€’ Research the latest trends in AI chips") + print(" β€’ Research power banks released in 2025") + print(" β€’ Research electric vehicle market in Europe") + print("\nThe agent will create a Google Doc and email it to you.") + print("Type 'quit' to exit.\n") + + while True: + try: + query = input("You: ").strip() + + if query.lower() in ("quit", "exit", "q"): + print("\nGoodbye! πŸ‘‹") + break + + if not query: + continue + + run_agent(manager, agent, user_id, query) + + except KeyboardInterrupt: + print("\n\nGoodbye! πŸ‘‹") + break + + +def main() -> None: + """Main entry point.""" + # Validate environment + missing = [] + if not os.environ.get("ARCADE_API_KEY"): + missing.append("ARCADE_API_KEY (get at https://arcade.dev)") + if not os.environ.get("OPENAI_API_KEY") and not os.environ.get("ANTHROPIC_API_KEY"): + missing.append("OPENAI_API_KEY or ANTHROPIC_API_KEY") + + if missing: + print("❌ Missing required environment variables:") + for var in missing: + print(f" β€’ {var}") + sys.exit(1) + + user_id = os.environ.get("USER_EMAIL", "user@example.com") + recipient_email = os.environ.get("RECIPIENT_EMAIL", user_id) + + print(f"\nπŸ“§ User (OAuth): {user_id}") + print(f"πŸ“¬ Recipient: {recipient_email}") + + # Initialize tool manager and load tools + print("\nπŸš€ Initializing Research Agent...") + manager = ToolManager() + # Search: web search, Google: Docs, Gmail: email + manager.init_tools(toolkits=["Search", "Google", "Gmail"]) + print(f"βœ“ Loaded {len(manager.tools)} tools") + + # Pre-authorize key tools + pre_authorize_tools(manager, user_id) + + # Create agent + agent = create_agent(manager, recipient_email) + print("βœ“ Agent ready!") + print(f"βœ“ Reports will be sent to: {recipient_email}") + + # Run in appropriate mode + if len(sys.argv) > 1 and sys.argv[1] == "--query": + if len(sys.argv) > 2: + query = " ".join(sys.argv[2:]) + run_agent(manager, agent, user_id, query) + else: + print("Usage: python research_agent.py --query 'Research topic here'") + sys.exit(1) + else: + interactive_mode(manager, agent, user_id, recipient_email) + + +if __name__ == "__main__": + main() diff --git a/contrib/langchain/pyproject.toml b/contrib/langchain/pyproject.toml index f5bb8f1f4..52acadeef 100644 --- a/contrib/langchain/pyproject.toml +++ b/contrib/langchain/pyproject.toml @@ -12,7 +12,7 @@ license = "MIT" requires-python = ">=3.10" dependencies = [ "arcadepy>=1.7.0", - "langchain-core>=0.3.49,<0.4", + "langchain-core>=1.0.0", ] @@ -25,7 +25,10 @@ dev = [ "mypy>=1.5.1,<1.6.0", "pre-commit>=3.4.0,<3.5.0", "ruff>=0.7.4,<0.8.0", - "langgraph>=0.3.23,<0.4" + "langgraph>=0.3.23", + "deepagents>=0.2.6", + "langchain-openai>=0.3.0", + "python-dotenv>=1.0.0", ]