mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
refactor(search): select backend from available credentials
This commit is contained in:
parent
cfa8ae92c0
commit
88ed2ac9a3
40 changed files with 188 additions and 555 deletions
|
|
@ -39,6 +39,7 @@ the vault:
|
|||
- `FABRO_SLACK_BOT_TOKEN`
|
||||
- `DAYTONA_API_KEY`
|
||||
- `BRAVE_SEARCH_API_KEY`
|
||||
- `VENICE_API_KEY`
|
||||
|
||||
`FABRO_JWT_PRIVATE_KEY` and `FABRO_JWT_PUBLIC_KEY` are removed. `SESSION_SECRET` is the single auth root.
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ Add variables in **Service → Variables** as needed. The [Server Configuration]
|
|||
| `SESSION_SECRET` | 64-character hex string; required when the web UI is enabled |
|
||||
| `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` | Optional static S3 object-store credentials |
|
||||
|
||||
Do not put optional integration secrets in Railway variables for server runtime. After the server is running, add LLM provider keys, Slack, Daytona, Brave Search, `GITHUB_TOKEN`, and GitHub App secrets to the server vault with `fabro secret set`, `fabro provider login`, or `fabro install`.
|
||||
Do not put optional integration secrets in Railway variables for server runtime. After the server is running, add LLM provider keys, Slack, Daytona, Brave Search, Venice Search, `GITHUB_TOKEN`, and GitHub App secrets to the server vault with `fabro secret set`, `fabro provider login`, or `fabro install`.
|
||||
|
||||
No `.env` file is auto-loaded inside the container; bootstrap variables come from Railway's environment.
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ Fabro is single-tenant software designed for small, trusted teams. The following
|
|||
### Secrets
|
||||
|
||||
- **Keep API keys out of sandboxes.** The local sandbox strips environment variables ending in `_API_KEY`, `_SECRET`, `_TOKEN`, `_PASSWORD`, or `_CREDENTIAL`, but Docker and Daytona sandboxes provide stronger isolation — only explicitly configured variables are passed through.
|
||||
- **Use the server vault for optional integration credentials.** For server-backed workflows, persist LLM provider keys, Slack, Daytona, Brave Search, GitHub token, and GitHub App secrets with `fabro provider login`, `fabro secret set`, or `fabro install`. Process env and `server.env` are reserved for bootstrap secrets such as `SESSION_SECRET`, `FABRO_DEV_TOKEN`, and object-store credentials. Do not commit secrets to version control.
|
||||
- **Use the server vault for optional integration credentials.** For server-backed workflows, persist LLM provider keys, Slack, Daytona, Brave Search, Venice Search, GitHub token, and GitHub App secrets with `fabro provider login`, `fabro secret set`, or `fabro install`. Process env and `server.env` are reserved for bootstrap secrets such as `SESSION_SECRET`, `FABRO_DEV_TOKEN`, and object-store credentials. Do not commit secrets to version control.
|
||||
- **Rotate the session secret.** The `SESSION_SECRET` environment variable encrypts web app sessions. Rotate it periodically and use a strong random value.
|
||||
|
||||
### Execution
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ Generate one with `openssl rand -hex 32`.
|
|||
| `FABRO_DEV_TOKEN` | Optional — pre-set the dev token instead of reading the one written to `/storage` on first boot |
|
||||
| `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` | Optional static S3 object-store credentials |
|
||||
|
||||
Do not put optional integration secrets in `.env` for server runtime. Configure LLM provider keys, Slack, Daytona, Brave Search, `GITHUB_TOKEN`, and GitHub App secrets in the vault with `fabro secret set`, `fabro provider login`, or `fabro install`.
|
||||
Do not put optional integration secrets in `.env` for server runtime. Configure LLM provider keys, Slack, Daytona, Brave Search, Venice Search, `GITHUB_TOKEN`, and GitHub App secrets in the vault with `fabro secret set`, `fabro provider login`, or `fabro install`.
|
||||
|
||||
Optional:
|
||||
|
||||
|
|
|
|||
|
|
@ -334,22 +334,6 @@ Tailscale Services and Tailscale Funnel are different ingress features. Services
|
|||
|
||||
Incoming webhooks are authenticated only by GitHub's `X-Hub-Signature-256` HMAC signature, not by Fabro's bearer/session auth.
|
||||
|
||||
### `[server.integrations.search]` section
|
||||
|
||||
Select the HTTP backend for the built-in [`web_search`](/agents/tools#web_search) tool. Brave remains the default when this table is absent.
|
||||
|
||||
```toml title="settings.toml"
|
||||
[server.integrations.search]
|
||||
provider = "brave" # "brave" (default) | "venice"
|
||||
venice_engine = "brave" # venice-only: "brave" | "google"
|
||||
```
|
||||
|
||||
- `provider = "brave"`: direct Brave Search. Requires vault `BRAVE_SEARCH_API_KEY`. See [Brave Search](/integrations/brave-search).
|
||||
- `provider = "venice"`: Venice `POST /api/v1/augment/search`. Requires vault `VENICE_API_KEY` (the same key as the Venice LLM provider). See [Venice Search](/integrations/venice-search).
|
||||
- `venice_engine = "brave"` is Brave **through Venice** (Firecrawl ZDR, billed as Venice credits). Direct Brave remains `provider = "brave"`.
|
||||
|
||||
The tool is registered only when the selected provider is configured. Failed calls do not fall back between backends.
|
||||
|
||||
### `[run.checkpoint]` section
|
||||
|
||||
Configure checkpoint behavior for all runs.
|
||||
|
|
@ -421,11 +405,13 @@ fabro secret set BRAVE_SEARCH_API_KEY BSA...
|
|||
fabro secret set VENICE_API_KEY venice-...
|
||||
```
|
||||
|
||||
The built-in [`web_search`](/agents/tools#web_search) tool selects its backend from these credentials. It uses direct Brave Search when `BRAVE_SEARCH_API_KEY` exists. Otherwise it uses Venice Search when `VENICE_API_KEY` exists. When neither exists, the tool is not registered.
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `DAYTONA_API_KEY` | Daytona cloud sandbox API key |
|
||||
| `BRAVE_SEARCH_API_KEY` | Brave Search API key (`web_search` when `provider = "brave"`) |
|
||||
| `VENICE_API_KEY` | Venice API key (LLM provider, and `web_search` when `provider = "venice"`) |
|
||||
| `BRAVE_SEARCH_API_KEY` | Brave Search API key; the preferred `web_search` backend when present |
|
||||
| `VENICE_API_KEY` | Venice API key; used by the Venice LLM provider and by `web_search` when no Brave key exists |
|
||||
|
||||
### Server authentication
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ The system prompt varies by LLM provider. Each provider has its own identity tex
|
|||
<Accordion title="Example system prompt (Anthropic provider)">
|
||||
This is the full system prompt sent to Claude as the LLM system message. The `<environment>` block is filled in at runtime.
|
||||
|
||||
Tool guidance tracks the tools actually registered for the session. The `web_search` section shown below is present only when a [Brave Search API key](/integrations/brave-search) is configured; without one, both the tool and its guidance are omitted.
|
||||
Tool guidance tracks the tools actually registered for the session. The `web_search` section shown below is present when a [Brave Search API key](/integrations/brave-search) or [Venice API key](/integrations/venice-search) is configured. Without either key, both the tool and its guidance are omitted.
|
||||
|
||||
```
|
||||
You are Claude, an AI coding assistant made by Anthropic. You help users with
|
||||
|
|
@ -232,7 +232,7 @@ first). Use this for finding files rather than using shell find or ls
|
|||
commands.
|
||||
|
||||
## web_search
|
||||
Search the web using Brave Search. Returns titles, URLs, and descriptions.
|
||||
Search the web. Returns titles, URLs, and descriptions.
|
||||
|
||||
## web_fetch
|
||||
Fetch content from a URL and optionally summarize it. Pass a prompt to
|
||||
|
|
|
|||
|
|
@ -123,28 +123,18 @@ Patterns are case-sensitive and relative to `path`: `*` and `?` stay within one
|
|||
|
||||
### web_search
|
||||
|
||||
Searches the web using Brave Search (default) or Venice Search.
|
||||
Searches the web using Brave Search or Venice Search. Fabro selects the backend automatically from the available credentials.
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|---|---|---|---|
|
||||
| `query` | string | yes | Search query. Venice rejects queries longer than 400 characters before the HTTP call. |
|
||||
| `max_results` | integer | no | Maximum results (default: 5, max: 20) |
|
||||
| `engine` | `"brave"` \| `"google"` | no | Venice backend only. Overrides `[server.integrations.search].venice_engine`. Brave ignores this parameter. |
|
||||
|
||||
Select the backend in server settings. Brave remains the default when the table is absent:
|
||||
Fabro uses direct [Brave Search](/integrations/brave-search) when `BRAVE_SEARCH_API_KEY` is present. Otherwise it uses [Venice Search](/integrations/venice-search) when `VENICE_API_KEY` is present. If both credentials are present, Brave wins. Venice always uses its Brave search engine.
|
||||
|
||||
```toml
|
||||
[server.integrations.search]
|
||||
provider = "venice" # "brave" (default) | "venice"
|
||||
venice_engine = "brave" # venice-only: "brave" (ZDR) | "google" (anon proxy)
|
||||
```
|
||||
Runs read both keys from the server vault. Workers start from a cleared environment, so exporting a key in the server's shell has no effect. The standalone agent CLI reads the keys from the invoking shell instead.
|
||||
|
||||
Runs read the selected provider's key from the server vault — workers start from a cleared environment, so exporting the key in the server's shell has no effect. The standalone agent CLI reads keys from the invoking shell instead.
|
||||
|
||||
- Brave (`provider = "brave"`): `fabro secret set BRAVE_SEARCH_API_KEY <key>`. See [Brave Search](/integrations/brave-search).
|
||||
- Venice (`provider = "venice"`): reuse `VENICE_API_KEY` (`fabro provider login --provider venice` or `fabro secret set VENICE_API_KEY <key>`). See [Venice Search](/integrations/venice-search).
|
||||
|
||||
The tool is registered only when the **selected** provider is configured. Fabro does not fall back Brave ↔ Venice on a failed call. Returns numbered results with title, URL, and description; Venice includes `date` on a fourth line when present.
|
||||
The tool is registered when either credential is available. Once Fabro selects a backend, a failed call returns an error; it does not retry through the other backend. Results contain numbered titles, URLs, and descriptions. Venice includes `date` on a fourth line when present.
|
||||
|
||||
### web_fetch
|
||||
|
||||
|
|
|
|||
|
|
@ -14231,14 +14231,12 @@ components:
|
|||
|
||||
ServerIntegrationsSettings:
|
||||
type: object
|
||||
required: [github, slack, search]
|
||||
required: [github, slack]
|
||||
properties:
|
||||
github:
|
||||
$ref: "#/components/schemas/GithubIntegrationSettings"
|
||||
slack:
|
||||
$ref: "#/components/schemas/SlackIntegrationSettings"
|
||||
search:
|
||||
$ref: "#/components/schemas/SearchIntegrationSettings"
|
||||
|
||||
GithubIntegrationSettings:
|
||||
type: object
|
||||
|
|
@ -14278,23 +14276,6 @@ components:
|
|||
default_channel:
|
||||
type: ["string", "null"]
|
||||
|
||||
SearchIntegrationSettings:
|
||||
type: object
|
||||
required: [provider, venice_engine]
|
||||
properties:
|
||||
provider:
|
||||
$ref: "#/components/schemas/SearchProvider"
|
||||
venice_engine:
|
||||
$ref: "#/components/schemas/VeniceSearchEngine"
|
||||
|
||||
SearchProvider:
|
||||
type: string
|
||||
enum: [brave, venice]
|
||||
|
||||
VeniceSearchEngine:
|
||||
type: string
|
||||
enum: [brave, google]
|
||||
|
||||
IntegrationWebhooksSettings:
|
||||
type: object
|
||||
required: [strategy]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ date: "2026-08-21"
|
|||
|
||||
## Venice search backend for `web_search`
|
||||
|
||||
The built-in `web_search` tool now has a second HTTP backend. Brave Search remains the default. Set `[server.integrations.search].provider = "venice"` to send queries to Venice `POST /api/v1/augment/search`, reusing vault `VENICE_API_KEY`. Failed calls do not fall back between providers.
|
||||
The built-in `web_search` tool now supports Venice as an automatic alternative to direct Brave Search. Fabro uses `BRAVE_SEARCH_API_KEY` when present. Otherwise it uses `VENICE_API_KEY` with Venice's Brave search engine. If neither key is present, the tool is not registered. Failed calls do not fall back between providers.
|
||||
|
||||
See [Venice Search](/integrations/venice-search) and [Brave Search](/integrations/brave-search).
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ Workflow runs also add `x-session-id: <run-id>` to every LLM request so compatib
|
|||
|
||||
Provider `agent_profile` defaults from `adapter` and controls profile-specific behavior such as which tools the agent registers, project-memory filenames, CLI/ACP command selection, and native session routing. Valid values are `anthropic`, `openai`, `gemini`, `kimi`, and `gpt56`; model-level values override provider-level values.
|
||||
|
||||
Two profiles are selected per model rather than per provider, because they follow the model wherever it is served: `kimi` for Kimi models, and `gpt56` for the GPT-5.6 models (Sol, Terra, Luna). The `gpt56` profile uses Codex's narrow core surface — `shell_command`, `apply_patch`, and `update_plan`, plus optional Brave-backed `web_search` — instead of fabro's dedicated file-read, discovery, and `web_fetch` tools. On OpenAI-compatible routes that cannot carry the freeform `apply_patch` grammar, it substitutes the JSON-schema `edit_file` tool. Session features may add their own question, skill, or subagent tools separately.
|
||||
Two profiles are selected per model rather than per provider, because they follow the model wherever it is served: `kimi` for Kimi models, and `gpt56` for the GPT-5.6 models (Sol, Terra, Luna). The `gpt56` profile uses Codex's narrow core surface — `shell_command`, `apply_patch`, and `update_plan`, plus optional credential-backed `web_search` — instead of fabro's dedicated file-read, discovery, and `web_fetch` tools. On OpenAI-compatible routes that cannot carry the freeform `apply_patch` grammar, it substitutes the JSON-schema `edit_file` tool. Session features may add their own question, skill, or subagent tools separately.
|
||||
|
||||
Provider `billing_policy` defaults from `adapter` and controls usage-cost estimation. Use `openai`, `anthropic`, `gemini`, or `none`. Model rows may override it for models whose billing family differs from their provider's — for example, Claude models served through OpenRouter set `billing_policy = "anthropic"` so cache reads and writes price correctly.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ title: "Brave Search"
|
|||
description: "Give Fabro agents web search capabilities via the Brave Search API"
|
||||
---
|
||||
|
||||
Fabro's [`web_search`](/agents/tools#web_search) tool lets agents search the web during workflow execution. It uses the [Brave Search API](https://brave.com/search/api/) to return titles, URLs, and descriptions for any query. Setting the API key is the only configuration needed — the tool is then registered for all provider profiles (Anthropic, OpenAI, Gemini). Without a key the tool is not registered at all, so agents are never offered a search tool they cannot use.
|
||||
Fabro's [`web_search`](/agents/tools#web_search) tool lets agents search the web during workflow execution. It uses the [Brave Search API](https://brave.com/search/api/) to return titles, URLs, and descriptions for any query.
|
||||
|
||||
Brave is the default `web_search` backend. To use Venice instead, see [Venice Search](/integrations/venice-search).
|
||||
Fabro selects the backend from the credentials in its vault. Direct Brave Search is preferred whenever `BRAVE_SEARCH_API_KEY` is present. When that key is absent, Fabro can use [Venice Search](/integrations/venice-search) with `VENICE_API_KEY` instead.
|
||||
|
||||
## Setup
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ fabro secret set BRAVE_SEARCH_API_KEY BSA...
|
|||
fabro doctor
|
||||
```
|
||||
|
||||
The doctor output should show **Web Search** as `brave: configured and reachable`. If the key is missing, web search is reported as a warning — workflows still run, but the `web_search` tool is omitted from the agent's tool set and its system prompt, so agents fall back to other tools.
|
||||
The doctor output should show **Web Search** as `brave: configured and reachable`. If the Brave key is missing but a Venice key exists, Fabro checks Venice instead. If neither key exists, web search is reported as a warning. Workflows still run, but the `web_search` tool is omitted from the agent's tool set and its system prompt.
|
||||
|
||||
The Fabro server reads this key from the vault only. It does not read `BRAVE_SEARCH_API_KEY` from process env or `server.env`.
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ Agents call the `web_search` tool with a query string. Fabro sends the query to
|
|||
The Rust book
|
||||
```
|
||||
|
||||
If `BRAVE_SEARCH_API_KEY` is not configured in the vault, the tool returns an error explaining that the key is required. The agent can then fall back to other approaches.
|
||||
If `BRAVE_SEARCH_API_KEY` is not configured, Fabro uses Venice when `VENICE_API_KEY` is available. If neither key is configured, the tool is not registered.
|
||||
|
||||
See the [`web_search` tool reference](/agents/tools#web_search) for parameters and details.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ title: "Venice Search"
|
|||
description: "Give Fabro agents web search capabilities via Venice's augment/search API"
|
||||
---
|
||||
|
||||
Fabro's [`web_search`](/agents/tools#web_search) tool lets agents search the web during workflow execution. The default backend is [Brave Search](/integrations/brave-search). Set `[server.integrations.search].provider = "venice"` to use [Venice Search](https://docs.venice.ai/api-reference/endpoint/augment/search) instead, reusing the same `VENICE_API_KEY` already used for the Venice LLM provider.
|
||||
Fabro's [`web_search`](/agents/tools#web_search) tool lets agents search the web during workflow execution. Fabro uses [Venice Search](https://docs.venice.ai/api-reference/endpoint/augment/search) automatically when `VENICE_API_KEY` is available and a direct [Brave Search](/integrations/brave-search) key is not.
|
||||
|
||||
Agents keep calling `web_search`. Only the HTTP backend changes.
|
||||
Venice Search reuses the same `VENICE_API_KEY` as the Venice LLM provider. Agents keep calling `web_search`; only the HTTP backend changes.
|
||||
|
||||
## Setup
|
||||
|
||||
|
|
@ -17,30 +17,25 @@ fabro provider login --provider venice
|
|||
fabro secret set VENICE_API_KEY venice-...
|
||||
```
|
||||
|
||||
2. Select Venice as the search backend:
|
||||
Fabro prefers direct Brave Search whenever `BRAVE_SEARCH_API_KEY` is also present. To select Venice, leave that key unset or remove it:
|
||||
|
||||
```toml title="settings.toml"
|
||||
[server.integrations.search]
|
||||
provider = "venice"
|
||||
# venice_engine = "brave" # default: Firecrawl ZDR, billed as Venice credits
|
||||
# venice_engine = "google" # anonymized proxy
|
||||
```bash
|
||||
fabro secret rm BRAVE_SEARCH_API_KEY
|
||||
```
|
||||
|
||||
`provider = "brave"` (the default) talks to Brave Search directly and still needs `BRAVE_SEARCH_API_KEY`. `venice_engine = "brave"` is Brave **through Venice**, not the direct Brave backend.
|
||||
|
||||
3. Verify the key is working:
|
||||
2. Verify the key is working:
|
||||
|
||||
```bash
|
||||
fabro doctor
|
||||
```
|
||||
|
||||
The doctor output should show **Web Search** as `venice: configured and reachable`. If `VENICE_API_KEY` is missing, web search is reported as a warning — workflows still run, but the `web_search` tool is omitted from the agent's tool set.
|
||||
The doctor output should show **Web Search** as `venice: configured and reachable`. If neither Venice nor Brave is configured, web search is reported as a warning. Workflows still run, but the `web_search` tool is omitted from the agent's tool set.
|
||||
|
||||
The Fabro server reads this key from the vault only. It does not read `VENICE_API_KEY` from process env or `server.env`.
|
||||
|
||||
## How it works
|
||||
|
||||
Agents call the `web_search` tool with a query string. Fabro `POST`s to Venice `https://api.venice.ai/api/v1/augment/search` and returns numbered results with title, URL, description, and date when Venice includes one:
|
||||
Agents call the `web_search` tool with a query string. Fabro `POST`s to Venice `https://api.venice.ai/api/v1/augment/search` with the Brave search engine and returns numbered results with title, URL, description, and date when Venice includes one:
|
||||
|
||||
```
|
||||
1. Rust Lang
|
||||
|
|
@ -51,7 +46,7 @@ Agents call the `web_search` tool with a query string. Fabro `POST`s to Venice `
|
|||
|
||||
Venice Search is billed by Venice at $0.01 per request and is rate-limited to 20 requests per minute on the Venice side. Queries longer than 400 characters are rejected before the HTTP call.
|
||||
|
||||
If `VENICE_API_KEY` is not configured in the vault, the tool is not registered. Failed calls return an error; Fabro does not fall back to Brave.
|
||||
If `VENICE_API_KEY` is absent but `BRAVE_SEARCH_API_KEY` exists, Fabro uses direct Brave Search. If neither key exists, the tool is not registered. After selecting Venice, a failed call returns an error; Fabro does not retry through direct Brave Search.
|
||||
|
||||
See the [`web_search` tool reference](/agents/tools#web_search) for parameters and details.
|
||||
|
||||
|
|
@ -79,6 +74,6 @@ See the [`web_search` tool reference](/agents/tools#web_search) for parameters a
|
|||
Full `web_search` tool reference — parameters, output format, and error handling.
|
||||
</Card>
|
||||
<Card title="Brave Search" icon="globe" href="/integrations/brave-search">
|
||||
Direct Brave Search backend (the default when `provider` is unset).
|
||||
Direct Brave Search backend, preferred whenever its key is configured.
|
||||
</Card>
|
||||
</Columns>
|
||||
|
|
|
|||
|
|
@ -672,7 +672,7 @@ pub(crate) async fn run_diagnostics(
|
|||
{ "name": "GitHub App", "status": "pass", "summary": "demo configured", "details": [], "remediation": null },
|
||||
{ "name": "Docker Sandbox", "status": "pass", "summary": "disabled", "details": [{ "text": "server.sandbox.providers.docker.enabled = false", "warn": false }], "remediation": null },
|
||||
{ "name": "Cloud Sandbox", "status": "warning", "summary": "not configured", "details": [], "remediation": "Set DAYTONA_API_KEY to enable cloud sandbox execution" },
|
||||
{ "name": "Brave Search", "status": "warning", "summary": "not configured", "details": [], "remediation": "Set BRAVE_SEARCH_API_KEY to enable web search" }
|
||||
{ "name": "Web Search", "status": "warning", "summary": "optional, not configured", "details": [], "remediation": "Set BRAVE_SEARCH_API_KEY or VENICE_API_KEY to enable web search" }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use fabro_model::{Catalog, ProviderId};
|
|||
use fabro_redact::redact_string;
|
||||
use fabro_sandbox::{DockerSandboxProvider, daytona};
|
||||
use fabro_static::EnvVars;
|
||||
use fabro_types::settings::ServerAuthMethod;
|
||||
use fabro_types::settings::server::GithubIntegrationStrategy;
|
||||
use fabro_types::settings::{SearchProvider, ServerAuthMethod};
|
||||
use fabro_util::check_report::{CheckDetail, CheckResult, CheckSection, CheckStatus};
|
||||
use fabro_util::dev_token::validate_dev_token_format;
|
||||
use fabro_util::session_secret;
|
||||
|
|
@ -758,17 +758,7 @@ fn check_storage_dir_path(path: &std::path::Path) -> CheckResult {
|
|||
}
|
||||
|
||||
async fn check_web_search(state: &AppState) -> CheckResult {
|
||||
let search = state.server_settings().server.integrations.search;
|
||||
match search.provider {
|
||||
SearchProvider::Brave => check_brave_search(state).await,
|
||||
SearchProvider::Venice => check_venice_search(state).await,
|
||||
}
|
||||
}
|
||||
|
||||
const WEB_SEARCH_CHECK_NAME: &str = "Web Search";
|
||||
|
||||
async fn check_brave_search(state: &AppState) -> CheckResult {
|
||||
let api_key = match diagnostic_secret(
|
||||
let brave_api_key = match diagnostic_secret(
|
||||
state,
|
||||
WEB_SEARCH_CHECK_NAME,
|
||||
EnvVars::BRAVE_SEARCH_API_KEY,
|
||||
|
|
@ -778,18 +768,33 @@ async fn check_brave_search(state: &AppState) -> CheckResult {
|
|||
Ok(value) => value,
|
||||
Err(result) => return result,
|
||||
};
|
||||
let Some(api_key) = api_key else {
|
||||
return CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "brave: optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run `fabro secret set BRAVE_SEARCH_API_KEY` to enable web search".to_string(),
|
||||
),
|
||||
};
|
||||
};
|
||||
if let Some(api_key) = brave_api_key {
|
||||
return check_brave_search(api_key).await;
|
||||
}
|
||||
|
||||
let venice_api_key =
|
||||
match diagnostic_secret(state, WEB_SEARCH_CHECK_NAME, EnvVars::VENICE_API_KEY).await {
|
||||
Ok(value) => value,
|
||||
Err(result) => return result,
|
||||
};
|
||||
if let Some(api_key) = venice_api_key {
|
||||
return check_venice_search(api_key).await;
|
||||
}
|
||||
|
||||
CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run `fabro secret set BRAVE_SEARCH_API_KEY` or `fabro secret set VENICE_API_KEY` to enable web search".to_string(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
const WEB_SEARCH_CHECK_NAME: &str = "Web Search";
|
||||
|
||||
async fn check_brave_search(api_key: String) -> CheckResult {
|
||||
let http = match http_client_or_check(WEB_SEARCH_CHECK_NAME, CheckStatus::Warning) {
|
||||
Ok(http) => http,
|
||||
Err(result) => return result,
|
||||
|
|
@ -807,24 +812,7 @@ async fn check_brave_search(state: &AppState) -> CheckResult {
|
|||
match_web_search_probe(probe, "brave", "BRAVE_SEARCH_API_KEY")
|
||||
}
|
||||
|
||||
async fn check_venice_search(state: &AppState) -> CheckResult {
|
||||
let api_key =
|
||||
match diagnostic_secret(state, WEB_SEARCH_CHECK_NAME, EnvVars::VENICE_API_KEY).await {
|
||||
Ok(value) => value,
|
||||
Err(result) => return result,
|
||||
};
|
||||
let Some(api_key) = api_key else {
|
||||
return CheckResult {
|
||||
name: WEB_SEARCH_CHECK_NAME.to_string(),
|
||||
status: CheckStatus::Warning,
|
||||
summary: "venice: optional, not configured".to_string(),
|
||||
details: Vec::new(),
|
||||
remediation: Some(
|
||||
"Run `fabro secret set VENICE_API_KEY` to enable web search".to_string(),
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
async fn check_venice_search(api_key: String) -> CheckResult {
|
||||
let http = match http_client_or_check(WEB_SEARCH_CHECK_NAME, CheckStatus::Warning) {
|
||||
Ok(http) => http,
|
||||
Err(result) => return result,
|
||||
|
|
@ -833,7 +821,11 @@ async fn check_venice_search(state: &AppState) -> CheckResult {
|
|||
let probe = timeout(EXTERNAL_SERVICE_PROBE_TIMEOUT, async move {
|
||||
http.post("https://api.venice.ai/api/v1/augment/search")
|
||||
.bearer_auth(api_key)
|
||||
.json(&serde_json::json!({ "query": "test", "limit": 1 }))
|
||||
.json(&serde_json::json!({
|
||||
"query": "test",
|
||||
"limit": 1,
|
||||
"search_provider": "brave",
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.map_err(anyhow::Error::new)
|
||||
|
|
@ -1256,7 +1248,7 @@ enabled = false
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_web_search_ignores_env_backed_api_key() {
|
||||
async fn check_web_search_ignores_env_backed_brave_api_key() {
|
||||
let state = TestAppStateBuilder::new()
|
||||
.env_lookup(|name| {
|
||||
(name == EnvVars::BRAVE_SEARCH_API_KEY).then(|| "brave-from-env".to_string())
|
||||
|
|
@ -1267,29 +1259,18 @@ enabled = false
|
|||
|
||||
assert_eq!(result.name, "Web Search");
|
||||
assert_eq!(result.status, CheckStatus::Warning);
|
||||
assert_eq!(result.summary, "brave: optional, not configured");
|
||||
assert_eq!(result.summary, "optional, not configured");
|
||||
assert_eq!(
|
||||
result.remediation.as_deref(),
|
||||
Some("Run `fabro secret set BRAVE_SEARCH_API_KEY` to enable web search")
|
||||
Some(
|
||||
"Run `fabro secret set BRAVE_SEARCH_API_KEY` or `fabro secret set VENICE_API_KEY` to enable web search"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_web_search_venice_ignores_env_backed_api_key() {
|
||||
let settings = fabro_config::ServerSettingsBuilder::from_toml(
|
||||
r#"
|
||||
_version = 1
|
||||
|
||||
[server.auth]
|
||||
methods = ["dev-token"]
|
||||
|
||||
[server.integrations.search]
|
||||
provider = "venice"
|
||||
"#,
|
||||
)
|
||||
.expect("venice search settings should parse");
|
||||
async fn check_web_search_ignores_env_backed_venice_api_key() {
|
||||
let state = TestAppStateBuilder::new()
|
||||
.runtime_settings(settings, RunLayer::default())
|
||||
.env_lookup(|name| {
|
||||
(name == EnvVars::VENICE_API_KEY).then(|| "venice-from-env".to_string())
|
||||
})
|
||||
|
|
@ -1299,13 +1280,44 @@ provider = "venice"
|
|||
|
||||
assert_eq!(result.name, "Web Search");
|
||||
assert_eq!(result.status, CheckStatus::Warning);
|
||||
assert_eq!(result.summary, "venice: optional, not configured");
|
||||
assert_eq!(result.summary, "optional, not configured");
|
||||
assert_eq!(
|
||||
result.remediation.as_deref(),
|
||||
Some("Run `fabro secret set VENICE_API_KEY` to enable web search")
|
||||
Some(
|
||||
"Run `fabro secret set BRAVE_SEARCH_API_KEY` or `fabro secret set VENICE_API_KEY` to enable web search"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_web_search_prefers_brave_when_both_vault_keys_exist() {
|
||||
let state = TestAppStateBuilder::new()
|
||||
.vault_entries([
|
||||
(EnvVars::BRAVE_SEARCH_API_KEY, "invalid\n"),
|
||||
(EnvVars::VENICE_API_KEY, "invalid\n"),
|
||||
])
|
||||
.build();
|
||||
|
||||
let result = check_web_search(&state).await;
|
||||
|
||||
assert_eq!(result.name, "Web Search");
|
||||
assert_eq!(result.status, CheckStatus::Warning);
|
||||
assert_eq!(result.summary, "brave: connectivity error");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_web_search_uses_venice_when_brave_vault_key_is_absent() {
|
||||
let state = TestAppStateBuilder::new()
|
||||
.vault_entries([(EnvVars::VENICE_API_KEY, "invalid\n")])
|
||||
.build();
|
||||
|
||||
let result = check_web_search(&state).await;
|
||||
|
||||
assert_eq!(result.name, "Web Search");
|
||||
assert_eq!(result.status, CheckStatus::Warning);
|
||||
assert_eq!(result.summary, "venice: connectivity error");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_crypto_requires_github_client_secret_from_vault() {
|
||||
let settings = fabro_config::ServerSettingsBuilder::from_toml(
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ use crate::tool_permissions::{is_auto_approved, tool_category};
|
|||
use crate::tools::WebFetchSummarizer;
|
||||
use crate::{
|
||||
AgentEvent, AgentProfile, AgentProfileBuilder, LocalSandbox, Message, Sandbox, Session,
|
||||
SessionOptions, SessionShutdownReason, search_settings_from_disk,
|
||||
SessionOptions, SessionShutdownReason,
|
||||
};
|
||||
|
||||
#[expect(
|
||||
|
|
@ -45,7 +45,6 @@ fn cli_tool_secrets() -> ToolSecrets {
|
|||
ToolSecrets {
|
||||
brave_search_api_key: std::env::var(EnvVars::BRAVE_SEARCH_API_KEY).ok(),
|
||||
venice_api_key: std::env::var(EnvVars::VENICE_API_KEY).ok(),
|
||||
search: search_settings_from_disk(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use fabro_llm::types::{ReasoningEffort, Speed};
|
|||
use fabro_mcp::config::McpServerSettings;
|
||||
use fabro_model::AgentProfileKind;
|
||||
use fabro_types::PermissionLevel;
|
||||
use fabro_types::settings::SearchIntegrationSettings;
|
||||
|
||||
/// Callback invoked before each tool execution. Return `Ok(())` to allow,
|
||||
/// `Err(message)` to deny with the given message.
|
||||
|
|
@ -105,7 +104,6 @@ impl ToolHookCallback for ToolApprovalAdapter {
|
|||
pub struct ToolSecrets {
|
||||
pub brave_search_api_key: Option<String>,
|
||||
pub venice_api_key: Option<String>,
|
||||
pub search: SearchIntegrationSettings,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ToolSecrets {
|
||||
|
|
@ -116,7 +114,6 @@ impl std::fmt::Debug for ToolSecrets {
|
|||
&self.brave_search_api_key.is_some(),
|
||||
)
|
||||
.field("venice_search_configured", &self.venice_api_key.is_some())
|
||||
.field("search_provider", &self.search.provider.as_str())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
@ -355,15 +352,13 @@ mod tests {
|
|||
fn tool_secrets_debug_redacts_values() {
|
||||
let secrets = ToolSecrets {
|
||||
brave_search_api_key: Some("brave-secret-value".to_string()),
|
||||
venice_api_key: Some("venice-secret-value".to_string()),
|
||||
..ToolSecrets::default()
|
||||
venice_api_key: Some("venice-secret-value".to_string()),
|
||||
};
|
||||
|
||||
let debug = format!("{secrets:?}");
|
||||
|
||||
assert!(debug.contains("brave_search_configured: true"));
|
||||
assert!(debug.contains("venice_search_configured: true"));
|
||||
assert!(debug.contains("search_provider: \"brave\""));
|
||||
assert!(!debug.contains("brave-secret-value"));
|
||||
assert!(!debug.contains("venice-secret-value"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ pub use types::{
|
|||
AgentEvent, McpToolSummary, MemoryFileSummary, Message, SessionEvent, SessionState,
|
||||
SkillActivationSource, SkillSummary,
|
||||
};
|
||||
pub use web_search::search_settings_from_disk;
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(
|
||||
|
|
|
|||
|
|
@ -116,28 +116,19 @@ pub(crate) fn make_bash_tool(options: &NativeToolOptions) -> RegisteredTool {
|
|||
|
||||
#[must_use]
|
||||
pub(crate) fn make_web_search_tool(backend: SearchBackend) -> RegisteredTool {
|
||||
let includes_engine = backend.includes_engine_param();
|
||||
let mut tool = web_search::make_web_search_tool(backend);
|
||||
let mut properties = serde_json::json!({
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The web search query."
|
||||
}
|
||||
});
|
||||
if includes_engine {
|
||||
properties["engine"] = serde_json::json!({
|
||||
"type": "string",
|
||||
"enum": ["brave", "google"],
|
||||
"description": "Venice search engine. brave is ZDR (default); google is an anonymized proxy."
|
||||
});
|
||||
}
|
||||
tool.definition = definition(
|
||||
NativeTool::WebSearch,
|
||||
"Search the web when current external information is needed. Returns result titles, URLs, \
|
||||
and descriptions; use WebFetch to inspect a specific URL.",
|
||||
serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": properties,
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The web search query."
|
||||
}
|
||||
},
|
||||
"required": ["query"],
|
||||
"additionalProperties": false
|
||||
}),
|
||||
|
|
@ -468,7 +459,6 @@ mod tests {
|
|||
use std::collections::BTreeSet;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use fabro_types::settings::VeniceSearchEngine;
|
||||
use serde_json::json;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
|
|
@ -553,11 +543,8 @@ mod tests {
|
|||
&["query"],
|
||||
);
|
||||
assert_schema(
|
||||
&make_web_search_tool(SearchBackend::venice(
|
||||
"key".to_string(),
|
||||
VeniceSearchEngine::Brave,
|
||||
)),
|
||||
&["engine", "query"],
|
||||
&make_web_search_tool(SearchBackend::venice("key".to_string())),
|
||||
&["query"],
|
||||
&["query"],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ Search file contents with regex. Use glob_filter to narrow results.
|
|||
Find files by name pattern.
|
||||
|
||||
{% if inputs.has_web_search %}## web_search
|
||||
Search the web using Brave Search. Returns titles, URLs, and descriptions.
|
||||
Search the web. Returns titles, URLs, and descriptions.
|
||||
|
||||
{% endif %}## web_fetch
|
||||
Fetch content from a URL and optionally summarize it. Pass a prompt to extract specific information instead of returning the full page. URLs must start with http:// or https://.
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ Search file contents with regex. Use glob_filter to narrow results.
|
|||
Find files by name pattern.
|
||||
|
||||
## web_search
|
||||
Search the web using Brave Search. Returns titles, URLs, and descriptions.
|
||||
Search the web. Returns titles, URLs, and descriptions.
|
||||
|
||||
## web_fetch
|
||||
Fetch content from a URL and optionally summarize it. Pass a prompt to extract specific information instead of returning the full page. URLs must start with http:// or https://.
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Search file contents with regex. Use glob_filter to narrow results.
|
|||
Find files by name pattern.
|
||||
|
||||
## web_search
|
||||
Search the web using Brave Search. Returns titles, URLs, and descriptions.
|
||||
Search the web. Returns titles, URLs, and descriptions.
|
||||
|
||||
## web_fetch
|
||||
Fetch content from a URL and optionally summarize it. Pass a prompt to extract specific information instead of returning the full page. URLs must start with http:// or https://.
|
||||
|
|
|
|||
|
|
@ -50,14 +50,14 @@ fn html_to_markdown(text: &str) -> String {
|
|||
converter.convert(text).unwrap_or_else(|_| text.to_string())
|
||||
}
|
||||
|
||||
/// Name of the Brave-backed web search tool. Profiles look this up in their own
|
||||
/// registry to decide whether to advertise web search in the system prompt, so
|
||||
/// availability and prompt guidance cannot drift apart.
|
||||
/// Name of the credential-backed web search tool. Profiles look this up in
|
||||
/// their own registry to decide whether to advertise web search in the system
|
||||
/// prompt, so availability and prompt guidance cannot drift apart.
|
||||
pub const WEB_SEARCH_TOOL_NAME: &str = "web_search";
|
||||
|
||||
/// Registers the core tools shared by all provider profiles: `read_file`,
|
||||
/// `write_file`, `shell`, `grep`, `glob`, and `web_fetch`. `web_search` is
|
||||
/// included when a Brave Search API key is configured.
|
||||
/// included when a Brave or Venice Search API key is configured.
|
||||
///
|
||||
/// The shell tool captures its default and max timeouts from `options`.
|
||||
pub fn register_core_tools(
|
||||
|
|
@ -83,7 +83,7 @@ pub(crate) fn register_discovery_and_web_tools(
|
|||
registry.register(make_web_fetch_tool(summarizer));
|
||||
}
|
||||
|
||||
/// Register `web_search` when the selected search provider is configured.
|
||||
/// Register `web_search` when a search provider credential is configured.
|
||||
///
|
||||
/// Separate from [`register_discovery_and_web_tools`] for profiles that offer
|
||||
/// search without fabro's discovery tools.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
//! Built-in `web_search` backends.
|
||||
//!
|
||||
//! Agents always call the same tool. The HTTP backend is selected by
|
||||
//! `[server.integrations.search].provider`.
|
||||
//! Agents always call the same tool. Brave is preferred when its credential
|
||||
//! is present; otherwise Venice is used when its credential is present.
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Duration;
|
||||
|
||||
use fabro_llm::types::ToolDefinition;
|
||||
use fabro_types::settings::{SearchIntegrationSettings, SearchProvider, VeniceSearchEngine};
|
||||
|
||||
use crate::config::ToolSecrets;
|
||||
use crate::tool_registry::{RegisteredTool, ToolSource};
|
||||
|
|
@ -29,7 +28,6 @@ pub(crate) enum SearchBackend {
|
|||
},
|
||||
Venice {
|
||||
api_key: String,
|
||||
engine: VeniceSearchEngine,
|
||||
search_url: String,
|
||||
},
|
||||
}
|
||||
|
|
@ -37,15 +35,13 @@ pub(crate) enum SearchBackend {
|
|||
impl SearchBackend {
|
||||
#[must_use]
|
||||
pub(crate) fn from_secrets(secrets: &ToolSecrets) -> Option<Self> {
|
||||
match secrets.search.provider {
|
||||
SearchProvider::Brave => secrets
|
||||
.brave_search_api_key
|
||||
.as_ref()
|
||||
.map(|api_key| Self::brave(api_key.clone())),
|
||||
SearchProvider::Venice => secrets
|
||||
.venice_api_key
|
||||
.as_ref()
|
||||
.map(|api_key| Self::venice(api_key.clone(), secrets.search.venice_engine)),
|
||||
match (
|
||||
secrets.brave_search_api_key.as_ref(),
|
||||
secrets.venice_api_key.as_ref(),
|
||||
) {
|
||||
(Some(api_key), _) => Some(Self::brave(api_key.clone())),
|
||||
(None, Some(api_key)) => Some(Self::venice(api_key.clone())),
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,25 +54,14 @@ impl SearchBackend {
|
|||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn venice(api_key: String, engine: VeniceSearchEngine) -> Self {
|
||||
pub(crate) fn venice(api_key: String) -> Self {
|
||||
Self::Venice {
|
||||
api_key,
|
||||
engine,
|
||||
search_url: VENICE_SEARCH_URL.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn includes_engine_param(&self) -> bool {
|
||||
matches!(self, Self::Venice { .. })
|
||||
}
|
||||
|
||||
async fn search(
|
||||
&self,
|
||||
query: &str,
|
||||
max_results: u64,
|
||||
engine_override: Option<VeniceSearchEngine>,
|
||||
) -> Result<String, String> {
|
||||
async fn search(&self, query: &str, max_results: u64) -> Result<String, String> {
|
||||
match self {
|
||||
Self::Brave {
|
||||
api_key,
|
||||
|
|
@ -84,7 +69,6 @@ impl SearchBackend {
|
|||
} => search_brave(api_key, search_url, query, max_results).await,
|
||||
Self::Venice {
|
||||
api_key,
|
||||
engine,
|
||||
search_url,
|
||||
} => {
|
||||
if query.chars().count() > VENICE_QUERY_MAX_CHARS {
|
||||
|
|
@ -92,8 +76,7 @@ impl SearchBackend {
|
|||
"query exceeds Venice Search maximum of {VENICE_QUERY_MAX_CHARS} characters"
|
||||
));
|
||||
}
|
||||
let engine = engine_override.unwrap_or(*engine);
|
||||
search_venice(api_key, search_url, query, max_results, engine).await
|
||||
search_venice(api_key, search_url, query, max_results).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +133,6 @@ async fn search_venice(
|
|||
search_url: &str,
|
||||
query: &str,
|
||||
max_results: u64,
|
||||
engine: VeniceSearchEngine,
|
||||
) -> Result<String, String> {
|
||||
let limit = max_results.clamp(1, MAX_RESULTS);
|
||||
let resp = search_http_client()
|
||||
|
|
@ -161,7 +143,7 @@ async fn search_venice(
|
|||
.json(&serde_json::json!({
|
||||
"query": query,
|
||||
"limit": limit,
|
||||
"search_provider": engine.as_str(),
|
||||
"search_provider": "brave",
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
|
|
@ -277,16 +259,6 @@ fn optional_json_str(value: &serde_json::Value, key: &str) -> Option<String> {
|
|||
.map(str::to_owned)
|
||||
}
|
||||
|
||||
fn parse_engine_arg(args: &serde_json::Value) -> Result<Option<VeniceSearchEngine>, String> {
|
||||
let Some(value) = args.get("engine").and_then(serde_json::Value::as_str) else {
|
||||
return Ok(None);
|
||||
};
|
||||
value
|
||||
.parse()
|
||||
.map(Some)
|
||||
.map_err(|_| format!("Invalid engine `{value}`; expected `brave` or `google`"))
|
||||
}
|
||||
|
||||
fn max_results_arg(args: &serde_json::Value) -> u64 {
|
||||
args.get("max_results")
|
||||
.and_then(serde_json::Value::as_u64)
|
||||
|
|
@ -296,25 +268,16 @@ fn max_results_arg(args: &serde_json::Value) -> u64 {
|
|||
|
||||
#[must_use]
|
||||
pub(crate) fn make_web_search_tool(backend: SearchBackend) -> RegisteredTool {
|
||||
let mut properties = serde_json::json!({
|
||||
"query": {"type": "string", "description": "Search query"},
|
||||
"max_results": {"type": "integer", "description": "Maximum number of results (default 5, max 20)"}
|
||||
});
|
||||
if backend.includes_engine_param() {
|
||||
properties["engine"] = serde_json::json!({
|
||||
"type": "string",
|
||||
"enum": ["brave", "google"],
|
||||
"description": "Venice search engine. `brave` is ZDR (default); `google` is an anonymized proxy."
|
||||
});
|
||||
}
|
||||
|
||||
RegisteredTool {
|
||||
definition: ToolDefinition {
|
||||
name: WEB_SEARCH_TOOL_NAME.into(),
|
||||
description: "Search the web when current external information is needed. Returns result titles, URLs, and descriptions; use web_fetch for a specific URL.".into(),
|
||||
parameters: serde_json::json!({
|
||||
"type": "object",
|
||||
"properties": properties,
|
||||
"properties": {
|
||||
"query": {"type": "string", "description": "Search query"},
|
||||
"max_results": {"type": "integer", "description": "Maximum number of results (default 5, max 20)"}
|
||||
},
|
||||
"required": ["query"]
|
||||
}),
|
||||
},
|
||||
|
|
@ -322,10 +285,7 @@ pub(crate) fn make_web_search_tool(backend: SearchBackend) -> RegisteredTool {
|
|||
let backend = backend.clone();
|
||||
Box::pin(async move {
|
||||
let query = required_str(&args, "query")?;
|
||||
let engine = parse_engine_arg(&args)?;
|
||||
backend
|
||||
.search(query, max_results_arg(&args), engine)
|
||||
.await
|
||||
backend.search(query, max_results_arg(&args)).await
|
||||
})
|
||||
}),
|
||||
source: ToolSource::Native,
|
||||
|
|
@ -338,19 +298,10 @@ pub(crate) fn make_web_search_tool_with_api_key(api_key: String) -> RegisteredTo
|
|||
make_web_search_tool(SearchBackend::brave(api_key))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn search_settings_from_disk() -> SearchIntegrationSettings {
|
||||
fabro_config::ServerSettingsBuilder::load_default()
|
||||
.ok()
|
||||
.map(|settings| settings.server.integrations.search)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use fabro_types::settings::{SearchIntegrationSettings, SearchProvider, VeniceSearchEngine};
|
||||
use httpmock::Method::{GET, POST};
|
||||
use httpmock::MockServer;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
|
@ -361,14 +312,10 @@ mod tests {
|
|||
use crate::test_support::MockSandbox;
|
||||
use crate::tool_registry::ToolContext;
|
||||
|
||||
fn secrets(brave: Option<&str>, venice: Option<&str>, provider: SearchProvider) -> ToolSecrets {
|
||||
fn secrets(brave: Option<&str>, venice: Option<&str>) -> ToolSecrets {
|
||||
ToolSecrets {
|
||||
brave_search_api_key: brave.map(str::to_string),
|
||||
venice_api_key: venice.map(str::to_string),
|
||||
search: SearchIntegrationSettings {
|
||||
provider,
|
||||
venice_engine: VeniceSearchEngine::Brave,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -387,39 +334,26 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn from_secrets_registers_brave_by_default_when_brave_key_is_present() {
|
||||
let backend = SearchBackend::from_secrets(&secrets(
|
||||
Some("brave-key"),
|
||||
Some("venice-key"),
|
||||
SearchProvider::Brave,
|
||||
));
|
||||
fn from_secrets_prefers_brave_when_both_keys_are_present() {
|
||||
let backend = SearchBackend::from_secrets(&secrets(Some("brave-key"), Some("venice-key")));
|
||||
assert!(matches!(backend, Some(SearchBackend::Brave { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_secrets_omits_brave_when_key_missing() {
|
||||
assert!(
|
||||
SearchBackend::from_secrets(&secrets(None, Some("venice-key"), SearchProvider::Brave))
|
||||
.is_none()
|
||||
);
|
||||
fn from_secrets_registers_brave_when_only_brave_key_is_present() {
|
||||
let backend = SearchBackend::from_secrets(&secrets(Some("brave-key"), None));
|
||||
assert!(matches!(backend, Some(SearchBackend::Brave { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_secrets_registers_venice_when_selected_and_key_present() {
|
||||
let backend = SearchBackend::from_secrets(&secrets(
|
||||
Some("brave-key"),
|
||||
Some("venice-key"),
|
||||
SearchProvider::Venice,
|
||||
));
|
||||
fn from_secrets_registers_venice_when_only_venice_key_is_present() {
|
||||
let backend = SearchBackend::from_secrets(&secrets(None, Some("venice-key")));
|
||||
assert!(matches!(backend, Some(SearchBackend::Venice { .. })));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_secrets_omits_venice_when_key_missing() {
|
||||
assert!(
|
||||
SearchBackend::from_secrets(&secrets(Some("brave-key"), None, SearchProvider::Venice))
|
||||
.is_none()
|
||||
);
|
||||
fn from_secrets_omits_search_when_both_keys_are_missing() {
|
||||
assert!(SearchBackend::from_secrets(&secrets(None, None)).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -466,26 +400,14 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn venice_schema_includes_engine_and_brave_schema_does_not() {
|
||||
fn brave_and_venice_use_the_same_tool_schema() {
|
||||
let brave = make_web_search_tool(SearchBackend::brave("key".into()));
|
||||
let venice = make_web_search_tool(SearchBackend::venice(
|
||||
"key".into(),
|
||||
VeniceSearchEngine::Brave,
|
||||
));
|
||||
assert!(
|
||||
brave.definition.parameters["properties"]
|
||||
.get("engine")
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
venice.definition.parameters["properties"]
|
||||
.get("engine")
|
||||
.is_some()
|
||||
);
|
||||
let venice = make_web_search_tool(SearchBackend::venice("key".into()));
|
||||
assert_eq!(brave.definition.parameters, venice.definition.parameters);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn venice_search_posts_augment_search_and_maps_engine() {
|
||||
async fn venice_search_posts_augment_search_with_brave_engine() {
|
||||
let server = MockServer::start();
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(POST)
|
||||
|
|
@ -494,7 +416,7 @@ mod tests {
|
|||
.json_body(serde_json::json!({
|
||||
"query": "fabro",
|
||||
"limit": 3,
|
||||
"search_provider": "google"
|
||||
"search_provider": "brave"
|
||||
}));
|
||||
then.status(200).json_body(serde_json::json!({
|
||||
"query": "fabro",
|
||||
|
|
@ -507,7 +429,7 @@ mod tests {
|
|||
}));
|
||||
});
|
||||
|
||||
let mut backend = SearchBackend::venice("venice-key".into(), VeniceSearchEngine::Brave);
|
||||
let mut backend = SearchBackend::venice("venice-key".into());
|
||||
if let SearchBackend::Venice { search_url, .. } = &mut backend {
|
||||
*search_url = format!("{}/api/v1/augment/search", server.base_url());
|
||||
}
|
||||
|
|
@ -516,8 +438,7 @@ mod tests {
|
|||
&tool,
|
||||
serde_json::json!({
|
||||
"query": "fabro",
|
||||
"max_results": 3,
|
||||
"engine": "google"
|
||||
"max_results": 3
|
||||
}),
|
||||
)
|
||||
.await
|
||||
|
|
@ -539,7 +460,7 @@ mod tests {
|
|||
.json_body(serde_json::json!({"results": []}));
|
||||
});
|
||||
|
||||
let mut backend = SearchBackend::venice("venice-key".into(), VeniceSearchEngine::Brave);
|
||||
let mut backend = SearchBackend::venice("venice-key".into());
|
||||
if let SearchBackend::Venice { search_url, .. } = &mut backend {
|
||||
*search_url = format!("{}/api/v1/augment/search", server.base_url());
|
||||
}
|
||||
|
|
@ -567,7 +488,7 @@ mod tests {
|
|||
then.status(status).body("error");
|
||||
}),
|
||||
};
|
||||
let mut backend = SearchBackend::venice("venice-key".into(), VeniceSearchEngine::Brave);
|
||||
let mut backend = SearchBackend::venice("venice-key".into());
|
||||
if let SearchBackend::Venice { search_url, .. } = &mut backend {
|
||||
*search_url = format!("{}/api/v1/augment/search", server.base_url());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,6 @@ async fn tool_secrets_from_configured_sources(vault: &Arc<AsyncRwLock<Vault>>) -
|
|||
ToolSecrets {
|
||||
brave_search_api_key: vault.get(EnvVars::BRAVE_SEARCH_API_KEY).map(str::to_string),
|
||||
venice_api_key: vault.get(EnvVars::VENICE_API_KEY).map(str::to_string),
|
||||
search: fabro_agent::search_settings_from_disk(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -324,21 +324,6 @@ fn main() {
|
|||
"fabro_types::settings::server::SlackIntegrationSettings",
|
||||
&[],
|
||||
),
|
||||
(
|
||||
"SearchIntegrationSettings",
|
||||
"fabro_types::settings::server::SearchIntegrationSettings",
|
||||
&[],
|
||||
),
|
||||
(
|
||||
"SearchProvider",
|
||||
"fabro_types::settings::server::SearchProvider",
|
||||
&[],
|
||||
),
|
||||
(
|
||||
"VeniceSearchEngine",
|
||||
"fabro_types::settings::server::VeniceSearchEngine",
|
||||
&[],
|
||||
),
|
||||
(
|
||||
"IntegrationWebhooksSettings",
|
||||
"fabro_types::settings::server::IntegrationWebhooksSettings",
|
||||
|
|
|
|||
|
|
@ -28,12 +28,11 @@ pub mod types {
|
|||
pub use fabro_types::settings::run::{McpHttpProtocol, RunModelControls, RunModelSettings};
|
||||
pub use fabro_types::settings::server::{
|
||||
GithubIntegrationSettings, GithubIntegrationStrategy, IntegrationWebhooksSettings,
|
||||
LogDestination, ObjectStoreSettings, SearchIntegrationSettings, SearchProvider,
|
||||
ServerApiSettings, ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod,
|
||||
ServerAuthSettings, ServerIntegrationsSettings, ServerListenSettings,
|
||||
ServerLoggingSettings, ServerSandboxProviderSettings, ServerSandboxProvidersSettings,
|
||||
ServerSandboxSettings, ServerSchedulerSettings, ServerSlateDbSettings,
|
||||
ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings, VeniceSearchEngine,
|
||||
LogDestination, ObjectStoreSettings, ServerApiSettings, ServerArtifactsSettings,
|
||||
ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings, ServerIntegrationsSettings,
|
||||
ServerListenSettings, ServerLoggingSettings, ServerSandboxProviderSettings,
|
||||
ServerSandboxProvidersSettings, ServerSandboxSettings, ServerSchedulerSettings,
|
||||
ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings,
|
||||
WebhookStrategy,
|
||||
};
|
||||
pub use fabro_types::settings::{McpTransport, ServerNamespace};
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use fabro_types::settings::run::{
|
|||
ApprovalMode, EnvironmentNetworkMode, EnvironmentProvider, MergeStrategy, RunMode,
|
||||
};
|
||||
use fabro_types::settings::server::{
|
||||
GithubIntegrationStrategy, LogDestination, ObjectStoreProvider, SearchProvider,
|
||||
ServerAuthMethod, VeniceSearchEngine, WebhookStrategy,
|
||||
GithubIntegrationStrategy, LogDestination, ObjectStoreProvider, ServerAuthMethod,
|
||||
WebhookStrategy,
|
||||
};
|
||||
use fabro_types::settings::{Duration, InterpString, Size};
|
||||
|
||||
|
|
@ -82,9 +82,7 @@ impl_combine_or_option!(
|
|||
GithubIntegrationStrategy,
|
||||
LogDestination,
|
||||
ObjectStoreProvider,
|
||||
SearchProvider,
|
||||
ServerAuthMethod,
|
||||
VeniceSearchEngine,
|
||||
WebhookStrategy,
|
||||
LogFilter,
|
||||
AgentProfileKind,
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ pub use run::{
|
|||
};
|
||||
pub use server::{
|
||||
GithubIntegrationLayer, IntegrationWebhooksLayer, ObjectStoreLocalLayer, ObjectStoreS3Layer,
|
||||
SearchIntegrationLayer, ServerApiLayer, ServerArtifactsLayer, ServerAuthGithubLayer,
|
||||
ServerAuthLayer, ServerIntegrationsLayer, ServerLayer, ServerListenLayer, ServerLoggingLayer,
|
||||
ServerApiLayer, ServerArtifactsLayer, ServerAuthGithubLayer, ServerAuthLayer,
|
||||
ServerIntegrationsLayer, ServerLayer, ServerListenLayer, ServerLoggingLayer,
|
||||
ServerSandboxLayer, ServerSandboxProviderLayer, ServerSandboxProvidersLayer,
|
||||
ServerSchedulerLayer, ServerSlateDbLayer, ServerStorageLayer, ServerWebLayer,
|
||||
SlackIntegrationLayer,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Sparse `[server]` settings layer definitions.
|
||||
|
||||
use fabro_types::settings::server::{
|
||||
GithubIntegrationStrategy, LogDestination, ObjectStoreProvider, SearchProvider,
|
||||
ServerAuthMethod, VeniceSearchEngine, WebhookStrategy,
|
||||
GithubIntegrationStrategy, LogDestination, ObjectStoreProvider, ServerAuthMethod,
|
||||
WebhookStrategy,
|
||||
};
|
||||
use fabro_types::settings::{Duration, InterpString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -206,8 +206,6 @@ pub struct ServerIntegrationsLayer {
|
|||
pub github: Option<GithubIntegrationLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub slack: Option<SlackIntegrationLayer>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub search: Option<SearchIntegrationLayer>,
|
||||
}
|
||||
|
||||
/// `[server.integrations.github]` — GitHub App, credentials, and inbound
|
||||
|
|
@ -239,16 +237,6 @@ pub struct SlackIntegrationLayer {
|
|||
pub default_channel: Option<String>,
|
||||
}
|
||||
|
||||
/// `[server.integrations.search]` — backend for the built-in `web_search` tool.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SearchIntegrationLayer {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub provider: Option<SearchProvider>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub venice_engine: Option<VeniceSearchEngine>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, fabro_macros::Combine)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct IntegrationWebhooksLayer {
|
||||
|
|
|
|||
|
|
@ -53,12 +53,11 @@ pub use layers::{
|
|||
RunArtifactsLayer, RunCheckpointLayer, RunCloneLayer, RunEnvironmentLayer, RunExecutionLayer,
|
||||
RunGitLayer, RunGoalLayer, RunIntegrationsGithubLayer, RunIntegrationsLayer, RunLayer,
|
||||
RunMetaBranchLayer, RunModelControlsLayer, RunModelLayer, RunPrepareLayer, RunPullRequestLayer,
|
||||
RunRunBranchLayer, RunScmLayer, ScmGitHubLayer, SearchIntegrationLayer, ServerApiLayer,
|
||||
ServerArtifactsLayer, ServerAuthGithubLayer, ServerAuthLayer, ServerIntegrationsLayer,
|
||||
ServerLayer, ServerListenLayer, ServerLoggingLayer, ServerSandboxLayer,
|
||||
ServerSandboxProviderLayer, ServerSandboxProvidersLayer, ServerSchedulerLayer,
|
||||
ServerSlateDbLayer, ServerStorageLayer, ServerWebLayer, SettingsLayer, SlackIntegrationLayer,
|
||||
StickyMap, StringOrSplice, WorkflowLayer,
|
||||
RunRunBranchLayer, RunScmLayer, ScmGitHubLayer, ServerApiLayer, ServerArtifactsLayer,
|
||||
ServerAuthGithubLayer, ServerAuthLayer, ServerIntegrationsLayer, ServerLayer,
|
||||
ServerListenLayer, ServerLoggingLayer, ServerSandboxLayer, ServerSandboxProviderLayer,
|
||||
ServerSandboxProvidersLayer, ServerSchedulerLayer, ServerSlateDbLayer, ServerStorageLayer,
|
||||
ServerWebLayer, SettingsLayer, SlackIntegrationLayer, StickyMap, StringOrSplice, WorkflowLayer,
|
||||
};
|
||||
pub use logging::{resolve_log_destination, resolve_log_destination_with_env};
|
||||
pub use parse::ParseError;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use std::path::Path;
|
|||
|
||||
use fabro_types::settings::server::{
|
||||
GithubIntegrationSettings, GithubIntegrationStrategy, IntegrationWebhooksSettings,
|
||||
ObjectStoreProvider, ObjectStoreSettings, SearchIntegrationSettings, ServerApiSettings,
|
||||
ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings,
|
||||
ServerIntegrationsSettings, ServerListenSettings, ServerLoggingSettings, ServerNamespace,
|
||||
ServerSandboxProviderSettings, ServerSandboxProvidersSettings, ServerSandboxSettings,
|
||||
ServerSchedulerSettings, ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings,
|
||||
SlackIntegrationSettings, WebhookStrategy,
|
||||
ObjectStoreProvider, ObjectStoreSettings, ServerApiSettings, ServerArtifactsSettings,
|
||||
ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings, ServerIntegrationsSettings,
|
||||
ServerListenSettings, ServerLoggingSettings, ServerNamespace, ServerSandboxProviderSettings,
|
||||
ServerSandboxProvidersSettings, ServerSandboxSettings, ServerSchedulerSettings,
|
||||
ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings,
|
||||
WebhookStrategy,
|
||||
};
|
||||
use fabro_util::Home;
|
||||
|
||||
|
|
@ -375,13 +375,6 @@ fn resolve_integrations(layer: Option<&ServerIntegrationsLayer>) -> ServerIntegr
|
|||
}
|
||||
},
|
||||
),
|
||||
search: layer
|
||||
.and_then(|integrations| integrations.search.as_ref())
|
||||
.map(|search| SearchIntegrationSettings {
|
||||
provider: search.provider.unwrap_or_default(),
|
||||
venice_engine: search.venice_engine.unwrap_or_default(),
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
)]
|
||||
|
||||
use fabro_types::settings::server::{
|
||||
GithubIntegrationStrategy, LogDestination, ObjectStoreSettings, SearchProvider,
|
||||
ServerAuthMethod, ServerListenSettings, ServerNamespace, VeniceSearchEngine,
|
||||
GithubIntegrationStrategy, LogDestination, ObjectStoreSettings, ServerAuthMethod,
|
||||
ServerListenSettings, ServerNamespace,
|
||||
};
|
||||
use fabro_util::Home;
|
||||
use temp_env::with_var;
|
||||
|
|
@ -127,10 +127,6 @@ fn resolved_server_integrations_disable_slack_when_config_is_absent() {
|
|||
"enabled": false,
|
||||
"default_channel": null,
|
||||
},
|
||||
"search": {
|
||||
"provider": "brave",
|
||||
"venice_engine": "brave",
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
@ -177,43 +173,6 @@ default_channel = "#releases"
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_search_defaults_to_brave_when_config_is_absent() {
|
||||
let settings = resolve_server(&parse(
|
||||
r"
|
||||
_version = 1
|
||||
",
|
||||
));
|
||||
|
||||
assert_eq!(settings.integrations.search.provider, SearchProvider::Brave);
|
||||
assert_eq!(
|
||||
settings.integrations.search.venice_engine,
|
||||
VeniceSearchEngine::Brave
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_search_provider_venice_and_google_engine() {
|
||||
let settings = resolve_server(&parse(
|
||||
r#"
|
||||
_version = 1
|
||||
|
||||
[server.integrations.search]
|
||||
provider = "venice"
|
||||
venice_engine = "google"
|
||||
"#,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
settings.integrations.search.provider,
|
||||
SearchProvider::Venice
|
||||
);
|
||||
assert_eq!(
|
||||
settings.integrations.search.venice_engine,
|
||||
VeniceSearchEngine::Google
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_slack_default_channel_keeps_template_token_literal() {
|
||||
// `server.integrations.slack.default_channel` is a plain literal now: a
|
||||
|
|
|
|||
|
|
@ -46,11 +46,10 @@ pub use run::{
|
|||
};
|
||||
pub use server::{
|
||||
GithubIntegrationSettings, IntegrationWebhooksSettings, LogDestination, ObjectStoreSettings,
|
||||
SearchIntegrationSettings, SearchProvider, ServerApiSettings, ServerArtifactsSettings,
|
||||
ServerAuthGithubSettings, ServerAuthMethod, ServerAuthSettings, ServerIntegrationsSettings,
|
||||
ServerListenSettings, ServerLoggingSettings, ServerNamespace, ServerSchedulerSettings,
|
||||
ServerSlateDbSettings, ServerStorageSettings, ServerWebSettings, SlackIntegrationSettings,
|
||||
VeniceSearchEngine,
|
||||
ServerApiSettings, ServerArtifactsSettings, ServerAuthGithubSettings, ServerAuthMethod,
|
||||
ServerAuthSettings, ServerIntegrationsSettings, ServerListenSettings, ServerLoggingSettings,
|
||||
ServerNamespace, ServerSchedulerSettings, ServerSlateDbSettings, ServerStorageSettings,
|
||||
ServerWebSettings, SlackIntegrationSettings,
|
||||
};
|
||||
pub use size::{ParseSizeError, Size};
|
||||
pub use workflow::WorkflowNamespace;
|
||||
|
|
|
|||
|
|
@ -242,7 +242,6 @@ pub struct ServerLoggingSettings {
|
|||
pub struct ServerIntegrationsSettings {
|
||||
pub github: GithubIntegrationSettings,
|
||||
pub slack: SlackIntegrationSettings,
|
||||
pub search: SearchIntegrationSettings,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -270,75 +269,6 @@ impl Default for SlackIntegrationSettings {
|
|||
}
|
||||
}
|
||||
|
||||
/// Backend used by the built-in `web_search` tool.
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
strum::EnumString,
|
||||
strum::IntoStaticStr,
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
pub enum SearchProvider {
|
||||
#[default]
|
||||
Brave,
|
||||
Venice,
|
||||
}
|
||||
|
||||
impl SearchProvider {
|
||||
#[must_use]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Brave => "brave",
|
||||
Self::Venice => "venice",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Venice `/augment/search` engine. `brave` is Firecrawl ZDR; `google` is an
|
||||
/// anonymized proxy. Direct Brave Search remains [`SearchProvider::Brave`].
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Copy,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
strum::EnumString,
|
||||
strum::IntoStaticStr,
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
pub enum VeniceSearchEngine {
|
||||
#[default]
|
||||
Brave,
|
||||
Google,
|
||||
}
|
||||
|
||||
impl VeniceSearchEngine {
|
||||
#[must_use]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Brave => "brave",
|
||||
Self::Google => "google",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SearchIntegrationSettings {
|
||||
pub provider: SearchProvider,
|
||||
pub venice_engine: VeniceSearchEngine,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct IntegrationWebhooksSettings {
|
||||
pub strategy: Option<WebhookStrategy>,
|
||||
|
|
|
|||
|
|
@ -441,8 +441,6 @@ models/saved-query.ts
|
|||
models/secret-list-response.ts
|
||||
models/secret-metadata.ts
|
||||
models/secret-type.ts
|
||||
models/search-integration-settings.ts
|
||||
models/search-provider.ts
|
||||
models/server-api-settings.ts
|
||||
models/server-artifacts-settings.ts
|
||||
models/server-auth-github-settings.ts
|
||||
|
|
@ -534,7 +532,6 @@ models/user-response.ts
|
|||
models/validate-response.ts
|
||||
models/variable-list-response.ts
|
||||
models/variable.ts
|
||||
models/venice-search-engine.ts
|
||||
models/vnc-preview-response.ts
|
||||
models/webhook-strategy.ts
|
||||
models/workflow-detail-response.ts
|
||||
|
|
|
|||
|
|
@ -410,8 +410,6 @@ export * from './saved-query';
|
|||
export * from './secret-list-response';
|
||||
export * from './secret-metadata';
|
||||
export * from './secret-type';
|
||||
export * from './search-integration-settings';
|
||||
export * from './search-provider';
|
||||
export * from './server-api-settings';
|
||||
export * from './server-artifacts-settings';
|
||||
export * from './server-auth-github-settings';
|
||||
|
|
@ -503,7 +501,6 @@ export * from './user-response';
|
|||
export * from './validate-response';
|
||||
export * from './variable';
|
||||
export * from './variable-list-response';
|
||||
export * from './venice-search-engine';
|
||||
export * from './vnc-preview-response';
|
||||
export * from './webhook-strategy';
|
||||
export * from './workflow-detail-response';
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Fabro Run API
|
||||
* HTTP API for managing Fabro workflow run executions.
|
||||
*
|
||||
* The version of the OpenAPI document: 0.2.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { SearchProvider } from './search-provider';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { VeniceSearchEngine } from './venice-search-engine';
|
||||
|
||||
export interface SearchIntegrationSettings {
|
||||
'provider': SearchProvider;
|
||||
'venice_engine': VeniceSearchEngine;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Fabro Run API
|
||||
* HTTP API for managing Fabro workflow run executions.
|
||||
*
|
||||
* The version of the OpenAPI document: 0.2.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
export const SearchProvider = {
|
||||
BRAVE: 'brave',
|
||||
VENICE: 'venice'
|
||||
} as const;
|
||||
|
||||
export type SearchProvider = typeof SearchProvider[keyof typeof SearchProvider];
|
||||
|
|
@ -18,13 +18,9 @@
|
|||
import type { GithubIntegrationSettings } from './github-integration-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { SearchIntegrationSettings } from './search-integration-settings';
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import type { SlackIntegrationSettings } from './slack-integration-settings';
|
||||
|
||||
export interface ServerIntegrationsSettings {
|
||||
'github': GithubIntegrationSettings;
|
||||
'slack': SlackIntegrationSettings;
|
||||
'search': SearchIntegrationSettings;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Fabro Run API
|
||||
* HTTP API for managing Fabro workflow run executions.
|
||||
*
|
||||
* The version of the OpenAPI document: 0.2.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
export const VeniceSearchEngine = {
|
||||
BRAVE: 'brave',
|
||||
GOOGLE: 'google'
|
||||
} as const;
|
||||
|
||||
export type VeniceSearchEngine = typeof VeniceSearchEngine[keyof typeof VeniceSearchEngine];
|
||||
Loading…
Add table
Reference in a new issue