-
Notifications
You must be signed in to change notification settings - Fork 10
Brave search connecter and tools #521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Pranesh-Raghu
merged 6 commits into
scalekit-inc:main
from
Pranesh-Raghu:BraveSearch-Connecter-and-tools
Mar 24, 2026
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4e933e7
feat(brave-search): add Brave Search agent connector with 17 tools, s…
Pranesh-Raghu 6e384b3
fix(brave-search): replace B letter with Brave lion icon in dashboard…
Pranesh-Raghu d1e6087
feat(brave-search): full enrichment with Scalekit tools, CodeRabbit f…
Pranesh-Raghu 63cec28
fix(brave-search): replace placeholder icon with proper Brave lion lo…
Pranesh-Raghu 7e9150e
fix(brave-search): resolve CodeRabbit comments
Pranesh-Raghu b644838
fix(brave-search): use ## headings and 3-space indent inside Steps co…
Pranesh-Raghu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file added
BIN
+19.7 KB
src/assets/docs/agent-connectors/brave-search/add-connected-account.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 83 additions & 0 deletions
83
src/components/templates/agent-connectors/_setup-brave-search.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| import { Steps, Aside, Tabs, TabItem } from '@astrojs/starlight/components' | ||
|
|
||
| Register your Brave Search API key with Scalekit so it can authenticate and proxy search requests on behalf of your users. Unlike OAuth connectors, Brave Search uses API key authentication — there is no redirect URI or OAuth flow. | ||
|
|
||
| <Steps> | ||
| 1. ## Get a Brave Search API key | ||
|
|
||
| - Go to [api.search.brave.com](https://api.search.brave.com) and sign in or create a free account. | ||
|
|
||
| - In the left sidebar, click **API Keys** → **+ New Key**. Give it a name (e.g., `Agent Auth`) and click **Create**. | ||
|
|
||
| - Copy the key immediately — it is shown only once. | ||
|
|
||
|  | ||
|
|
||
| <Aside type="note" title="Choosing the right plan"> | ||
| Brave Search API offers several subscription tiers. Make sure your plan covers the tools you intend to use: | ||
|
|
||
| | Plan | Monthly free quota | Tools included | | ||
| | --- | --- | --- | | ||
| | **Free** | 2,000 queries/month, 1 req/s | `brave_web_search`, `brave_news_search`, `brave_image_search`, `brave_video_search`, `brave_suggest_search`, `brave_spellcheck` | | ||
| | **Base / Pro** | Pay-per-use ($3–$5 / 1,000 queries) | All Free tools + `brave_llm_context`, `brave_summarizer_*` (Pro and above) | | ||
| | **AI** | Pay-per-use | All Pro tools + `brave_chat_completions` | | ||
| | **Data for AI** | Pay-per-use | Adds `brave_local_place_search`, `brave_local_pois`, `brave_local_descriptions` | | ||
|
|
||
| Upgrade your plan at [api.search.brave.com](https://api.search.brave.com) → **Subscription**. | ||
| </Aside> | ||
|
|
||
| 2. ## Create a connection in Scalekit | ||
|
|
||
| - In [Scalekit dashboard](https://app.scalekit.com), go to **Agent Auth** → **Create Connection**. Find **Brave Search** and click **Create**. | ||
|
|
||
| - Note the **Connection name** — you will use this as `connection_name` in your code (e.g., `brave-search`). | ||
|
|
||
|  | ||
|
|
||
| 3. ## Add a connected account | ||
|
|
||
| Connected accounts link a specific user identifier in your system to a Brave Search API key. Add them via the dashboard for testing, or via the Scalekit API in production. | ||
|
|
||
| **Via dashboard (for testing)** | ||
|
|
||
| - Open the connection you created and click the **Connected Accounts** tab → **Add account**. | ||
|
|
||
| - Fill in: | ||
| - **Your User's ID** — a unique identifier for this user in your system (e.g., `user_123`) | ||
| - **API Key** — the Brave Search API key you copied in step 1 | ||
|
|
||
| - Click **Save**. | ||
|
|
||
|  | ||
|
|
||
| **Via API (for production)** | ||
|
|
||
| <Tabs syncKey="tech-stack"> | ||
| <TabItem label="Node.js"> | ||
| ```typescript | ||
| await scalekit.actions.upsertConnectedAccount({ | ||
| connectionName: 'brave-search', | ||
| identifier: 'user_123', // your user's unique ID | ||
| credentials: { api_key: 'BSA...' }, | ||
| }); | ||
| ``` | ||
| </TabItem> | ||
| <TabItem label="Python"> | ||
| ```python | ||
| scalekit_client.actions.upsert_connected_account( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| credentials={"api_key": "BSA..."} | ||
| ) | ||
| ``` | ||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| <Aside type="tip" title="Production usage tip"> | ||
| In production, call `upsert_connected_account` (Python) / `upsertConnectedAccount` (Node.js) when a user enters their Brave Search API key — for example, on a settings page in your app. | ||
| </Aside> | ||
| </Steps> | ||
|
|
||
| <Aside type="note" title="Rate limits and quotas"> | ||
| Every API key has plan-specific rate limits. The Free plan allows 1 request/second. Paid plans allow up to 20 req/s depending on your tier. Monitor your usage at [api.search.brave.com](https://api.search.brave.com) → **Usage**. Exceeding your quota returns a `429 Too Many Requests` error. | ||
| </Aside> | ||
296 changes: 296 additions & 0 deletions
296
src/components/templates/agent-connectors/_usage-brave-search.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,296 @@ | ||
| import { Tabs, TabItem, Aside } from '@astrojs/starlight/components' | ||
|
|
||
| Once a connected account is set up, make search API calls through the Scalekit proxy. Scalekit injects the Brave Search API key automatically as the `X-Subscription-Token` header — you never handle credentials in your application code. | ||
|
|
||
| You can interact with Brave Search in two ways — via direct proxy API calls or via Scalekit optimized tool calls. Scroll down to see the list of available Scalekit tools. | ||
|
Pranesh-Raghu marked this conversation as resolved.
|
||
|
|
||
| ## Proxy API calls | ||
|
|
||
| <Tabs syncKey="tech-stack"> | ||
| <TabItem label="Node.js"> | ||
| ```typescript | ||
| import { ScalekitClient } from '@scalekit-sdk/node'; | ||
| import 'dotenv/config'; | ||
|
|
||
| const connectionName = 'brave-search'; // connection name from your Scalekit dashboard | ||
| const identifier = 'user_123'; // your user's unique identifier | ||
|
|
||
| // Get your credentials from app.scalekit.com → Developers → Settings → API Credentials | ||
| const scalekit = new ScalekitClient( | ||
| process.env.SCALEKIT_ENV_URL, | ||
| process.env.SCALEKIT_CLIENT_ID, | ||
| process.env.SCALEKIT_CLIENT_SECRET | ||
| ); | ||
| const actions = scalekit.actions; | ||
|
|
||
| // Web search via Scalekit proxy — no API key needed here | ||
| const result = await actions.request({ | ||
| connectionName, | ||
| identifier, | ||
| path: '/res/v1/web/search', | ||
| method: 'GET', | ||
| queryParams: { q: 'best open source LLM frameworks 2025', count: '5' }, | ||
| }); | ||
| console.log(result.data.web.results); | ||
| ``` | ||
| </TabItem> | ||
| <TabItem label="Python"> | ||
| ```python | ||
| import scalekit.client, os | ||
| from dotenv import load_dotenv | ||
| load_dotenv() | ||
|
|
||
| connection_name = "brave-search" # connection name from your Scalekit dashboard | ||
| identifier = "user_123" # your user's unique identifier | ||
|
|
||
| # Get your credentials from app.scalekit.com → Developers → Settings → API Credentials | ||
| scalekit_client = scalekit.client.ScalekitClient( | ||
| client_id=os.getenv("SCALEKIT_CLIENT_ID"), | ||
| client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), | ||
| env_url=os.getenv("SCALEKIT_ENV_URL"), | ||
| ) | ||
| actions = scalekit_client.actions | ||
|
|
||
| # Web search via Scalekit proxy — no API key needed here | ||
| result = actions.request( | ||
| connection_name=connection_name, | ||
| identifier=identifier, | ||
| path="/res/v1/web/search", | ||
| method="GET", | ||
| params={"q": "best open source LLM frameworks 2025", "count": 5} | ||
| ) | ||
| print(result["web"]["results"]) | ||
| ``` | ||
| </TabItem> | ||
| </Tabs> | ||
|
|
||
| <Aside type="tip" title="No OAuth flow needed"> | ||
| Brave Search uses API key auth — unlike OAuth connectors, there is no authorization link or redirect flow. Once you call `upsert_connected_account` (Python) / `upsertConnectedAccount` (Node.js), or add an account via the dashboard, your users can make requests immediately. | ||
| </Aside> | ||
|
|
||
| ## Scalekit tools | ||
|
|
||
| Use `actions.execute_tool()` to call Brave Search tools directly. Scalekit injects credentials automatically — your application code never handles the API key. | ||
|
|
||
| ### Web search | ||
|
|
||
| Search the web and retrieve real-time results. Works on all plans including Free. | ||
|
|
||
| ```python title="examples/brave_web_search.py" | ||
| import os | ||
| from scalekit.client import ScalekitClient | ||
|
|
||
| scalekit_client = ScalekitClient( | ||
| client_id=os.environ["SCALEKIT_CLIENT_ID"], | ||
| client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], | ||
| env_url=os.environ["SCALEKIT_ENV_URL"], | ||
| ) | ||
|
|
||
| # Ensure a connected account exists for this user before making tool calls | ||
| scalekit_client.actions.get_or_create_connected_account( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| ) | ||
|
|
||
| # Search for recent articles — freshness "pw" limits results to the past 7 days | ||
| result = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_web_search", | ||
| input={ | ||
| "q": "open source LLM frameworks 2025", | ||
| "count": 5, | ||
| "freshness": "pw", | ||
| }, | ||
| ) | ||
|
|
||
| for item in result["web"]["results"]: | ||
| print(item["title"], item["url"]) | ||
| ``` | ||
|
|
||
| ### News search | ||
|
|
||
| Retrieve recent news articles by topic or keyword. Useful for monitoring a brand, topic, or competitor. | ||
|
|
||
| ```python title="examples/brave_news_search.py" | ||
| # Fetch the latest news on a topic from the past 24 hours | ||
| result = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_news_search", | ||
| input={ | ||
| "q": "AI regulation Europe", | ||
| "count": 10, | ||
| "freshness": "pd", # pd = past 24 hours | ||
| }, | ||
| ) | ||
|
|
||
| for article in result["results"]: | ||
| print(article["title"], article["age"], article["url"]) | ||
| ``` | ||
|
|
||
| ### LLM grounding context | ||
|
|
||
| Retrieve search results structured specifically for grounding LLM responses. Requires Pro plan. Use `token_budget` to stay within your model's context window. | ||
|
|
||
| ```python title="examples/brave_llm_context.py" | ||
| # Get search context sized to fit a 4 000-token budget | ||
| result = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_llm_context", | ||
| input={ | ||
| "q": "vector database comparison 2025", | ||
| "count": 5, | ||
| "token_budget": 4000, | ||
| }, | ||
| ) | ||
|
|
||
| # Pass the structured context directly to your LLM | ||
| grounding_context = result["context"] | ||
| print(grounding_context) | ||
| ``` | ||
|
|
||
| ### AI chat completions grounded in search | ||
|
|
||
| Get an AI-generated answer backed by real-time Brave Search results, using an OpenAI-compatible interface. Requires AI plan. | ||
|
|
||
| ```python title="examples/brave_chat_completions.py" | ||
| # Drop-in replacement for OpenAI /v1/chat/completions — results are grounded in live search | ||
| result = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_chat_completions", | ||
| input={ | ||
| "messages": [ | ||
| {"role": "user", "content": "What are the latest developments in quantum computing?"} | ||
| ], | ||
| "model": "brave/serp-claude-3-5-haiku", | ||
| }, | ||
| ) | ||
|
|
||
| print(result["choices"][0]["message"]["content"]) | ||
| # Each answer includes citations back to source URLs | ||
| for source in result.get("search_results", []): | ||
| print(source["title"], source["url"]) | ||
| ``` | ||
|
|
||
| ### Local place search and POI details | ||
|
|
||
| Find nearby businesses or points of interest, then retrieve full details. Requires Data for AI plan. | ||
|
|
||
| ```python title="examples/brave_local_search.py" | ||
| # Step 1: Find coffee shops near San Francisco city centre | ||
| places = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_local_place_search", | ||
| input={ | ||
| "q": "specialty coffee", | ||
| "location": "San Francisco, CA", | ||
| "count": 5, | ||
| }, | ||
| ) | ||
|
|
||
| location_ids = [p["id"] for p in places["results"]] | ||
|
|
||
| # Step 2: Fetch rich details (hours, ratings, address) for those locations | ||
| # Location IDs expire after ~8 hours — always fetch details in the same session | ||
| pois = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_local_pois", | ||
| input={"ids": location_ids}, | ||
| ) | ||
|
|
||
| for poi in pois["results"]: | ||
| print(poi["name"], poi["address"], poi["rating"]) | ||
| ``` | ||
|
|
||
| ### AI summary with follow-up queries | ||
|
|
||
| Get an AI-generated summary for a search query, then surface follow-up questions. Requires Pro plan. | ||
|
|
||
| ```python title="examples/brave_summarizer.py" | ||
| # Step 1: Web search with summary: true to obtain a summarizer key | ||
| search_result = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_web_search", | ||
| input={ | ||
| "q": "benefits of RAG vs fine-tuning for enterprise LLMs", | ||
| "summary": True, | ||
| "count": 5, | ||
| }, | ||
| ) | ||
|
|
||
| summarizer_key = search_result["summarizer"]["key"] | ||
|
|
||
| # Step 2: Retrieve the full AI summary using the key | ||
| summary = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_summarizer_search", | ||
| input={"key": summarizer_key, "entity_info": True}, | ||
| ) | ||
|
|
||
| print(summary["title"]) | ||
| print(summary["summary"]) | ||
|
|
||
| # Step 3: Get follow-up questions for a conversational search experience | ||
| followups = scalekit_client.actions.execute_tool( | ||
| connection_name="brave-search", | ||
| identifier="user_123", | ||
| tool_name="brave_summarizer_followups", | ||
| input={"key": summarizer_key}, | ||
| ) | ||
|
|
||
| for q in followups["queries"]: | ||
| print("-", q) | ||
| ``` | ||
|
|
||
| ### LangChain integration | ||
|
|
||
| Use Scalekit's LangChain helper to load all Brave Search tools into a LangChain agent. The agent selects and calls the right tool automatically based on the user's query. | ||
|
|
||
| ```python title="examples/brave_langchain_agent.py" | ||
| import os | ||
| from langchain.agents import AgentExecutor, create_tool_calling_agent | ||
| from langchain_anthropic import ChatAnthropic | ||
| from langchain_core.prompts import ChatPromptTemplate | ||
| from scalekit.client import ScalekitClient | ||
|
|
||
| scalekit_client = ScalekitClient( | ||
| client_id=os.environ["SCALEKIT_CLIENT_ID"], | ||
| client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], | ||
| env_url=os.environ["SCALEKIT_ENV_URL"], | ||
| ) | ||
|
|
||
| # Load all Brave Search tools — Scalekit handles auth for each call | ||
| tools = scalekit_client.actions.langchain.get_tools( | ||
| providers=["BRAVE_SEARCH"], | ||
| identifier="user_123", | ||
| ) | ||
|
|
||
| llm = ChatAnthropic( | ||
| model="claude-sonnet-4-6", | ||
| api_key=os.environ["ANTHROPIC_API_KEY"], | ||
| ) | ||
|
|
||
| prompt = ChatPromptTemplate.from_messages([ | ||
| ("system", "You are a helpful research assistant with access to Brave Search tools."), | ||
| ("human", "{input}"), | ||
| ("placeholder", "{agent_scratchpad}"), | ||
| ]) | ||
|
|
||
| agent = create_tool_calling_agent(llm, tools, prompt) | ||
| agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) | ||
|
|
||
| response = agent_executor.invoke({ | ||
| "input": ( | ||
| "Find the top 5 news articles about AI regulation in Europe from the past week " | ||
| "and give me a one-sentence summary of each." | ||
| ) | ||
| }) | ||
| print(response["output"]) | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.