mirror of
https://github.com/RuoJi6/ARTEX.git
synced 2026-10-27 17:03:49 +08:00
feat(search): 网络搜索新增 DeepSeek 官方来源
不单独配置凭据,直接复用当前激活的 LLM 配置(base_url/api_key/model)。 这个来源与 ddgs/brave/tavily 性质不同:DeepSeek 没有可直接调用的搜索接口, 搜索只存在于其 Anthropic 兼容 messages 接口内部,以 web_search_20250305 服务端工具的形式由 DeepSeek 服务端执行。由此带来几个必须让用户知道的差异, 已在设置页写明: - 仅支持 DeepSeek 官方端点 + anthropic 协议。实测其 OpenAI 协议端点会直接以 "unknown variant, expected `function`" 拒绝一切服务端工具,web_search_options 之类的顶层字段则被静默忽略,没有可用的替代写法。 - 每次搜索额外消耗一次模型调用。 - 搜索请求由 DeepSeek 服务端发出,不经过搜索出口代理,也不计入流量留痕。 - 返回结果只有标题与链接,没有摘要(DeepSeek 只给 encrypted_content),需要正文 时仍由 WebFetch 抓取。 上述条件不做程序校验,仅在界面说明,由用户自行确认——配置不满足时搜索会在实际 调用时报错,与其它来源填错 Key 的反馈路径一致,可用「测试搜索」按钮实跑验证。 依赖 norma v0.3.8。
This commit is contained in:
1 parent
abf701e03c
commit
e4c744a318
11 files changed
+133
-47
No files matched your search
@@ -4,6 +4,12 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### 网络
|
||||
|
||||
#### 新增的功能
|
||||
|
||||
- **网络搜索新增 DeepSeek 官方来源**:直接复用当前激活的 LLM 配置。它与其余三个来源性质不同——DeepSeek 没有可直接调用的搜索接口,搜索只存在于其 Anthropic 兼容接口内部(`web_search_20250305` 服务端工具),由 DeepSeek 服务端执行。因此它**仅支持 DeepSeek 官方端点 + anthropic 协议**(OpenAI 协议端点会直接拒绝服务端工具),且每次搜索会**额外消耗一次模型调用**、请求**不经过搜索出口代理**、也**不计入流量留痕**,返回结果**只有标题与链接**(无摘要,需正文时由 WebFetch 抓取)。设置页说明上述限制但**不做校验拦截**,是否满足由用户自行确认,可用「测试搜索」按钮实跑一次验证。
|
||||
|
||||
### Agent
|
||||
|
||||
#### 修改的功能
|
||||
|
||||
+14
-11
@@ -129,17 +129,20 @@ func (c *ChatAgent) Chat(ctx context.Context, agentKey, sessionID, message strin
|
||||
WebFetchCACert: c.proxyCACert,
|
||||
// 联网搜索(可选)。ddgs 无需 key;brave-free 需 BraveKey;tavily 需 TavilyKey。
|
||||
// WebSearchProxy 是独立出口代理(http/https/socks5),与记录流量的 MITM 代理无关;空则直连。
|
||||
EnableWebSearch: ws.Enabled,
|
||||
WebSearchBackend: ws.Backend,
|
||||
BraveSearchAPIKey: ws.BraveKey,
|
||||
TavilySearchAPIKey: ws.TavilyKey,
|
||||
WebSearchProxy: ws.Proxy,
|
||||
BashEnv: proxyEnv(c.proxyAddr, c.proxyCACert), // Bash 子命令默认走代理+信任 CA
|
||||
WorkingDir: sessionWorkDir,
|
||||
MaxTurns: maxTurns,
|
||||
MaxDuration: maxDuration,
|
||||
Compaction: compactionConfig(c.window),
|
||||
Todos: actool.NewTodoStore(),
|
||||
EnableWebSearch: ws.Enabled,
|
||||
WebSearchBackend: ws.Backend,
|
||||
BraveSearchAPIKey: ws.BraveKey,
|
||||
TavilySearchAPIKey: ws.TavilyKey,
|
||||
DeepSeekSearchBaseURL: ws.DeepSeekBaseURL,
|
||||
DeepSeekSearchAPIKey: ws.DeepSeekAPIKey,
|
||||
DeepSeekSearchModel: ws.DeepSeekModel,
|
||||
WebSearchProxy: ws.Proxy,
|
||||
BashEnv: proxyEnv(c.proxyAddr, c.proxyCACert), // Bash 子命令默认走代理+信任 CA
|
||||
WorkingDir: sessionWorkDir,
|
||||
MaxTurns: maxTurns,
|
||||
MaxDuration: maxDuration,
|
||||
Compaction: compactionConfig(c.window),
|
||||
Todos: actool.NewTodoStore(),
|
||||
// large tool output spills to cmd-output/ under the session dir.
|
||||
// 截断上限用 SDK 默认(tool.Capture 的 30000 字符)。
|
||||
ToolOutputDir: filepath.Join(sessionWorkDir, "cmd-output"),
|
||||
|
||||
+14
-11
@@ -136,17 +136,20 @@ func (m *MainAgent) Chat(ctx context.Context, taskID int64, mainSeg int, as *db.
|
||||
WebFetchCACert: m.proxyCACert,
|
||||
// 联网搜索(可选)。ddgs 无需 key;brave-free 需 BraveKey;tavily 需 TavilyKey。
|
||||
// WebSearchProxy 是独立出口代理(http/https/socks5),与记录流量的 MITM 代理无关;空则直连。
|
||||
EnableWebSearch: m.webSearch.Enabled,
|
||||
WebSearchBackend: m.webSearch.Backend,
|
||||
BraveSearchAPIKey: m.webSearch.BraveKey,
|
||||
TavilySearchAPIKey: m.webSearch.TavilyKey,
|
||||
WebSearchProxy: m.webSearch.Proxy,
|
||||
BashEnv: proxyEnv(m.proxyAddr, m.proxyCACert), // Bash 子命令默认走代理+信任 CA
|
||||
WorkingDir: mainDir, // 本任务工作目录 <workDir>/tasks/<taskID>
|
||||
ToolOutputDir: cmdOutDir(mainDir),
|
||||
MaxTurns: m.maxTurns, // 0 = unlimited (configurable in agent management)
|
||||
Compaction: compactionConfig(m.compactionWindow()), // long chats stay within the window
|
||||
Todos: actool.NewTodoStore(), // 会话级临时待办(TodoWrite),纯规划用,退出即丢
|
||||
EnableWebSearch: m.webSearch.Enabled,
|
||||
WebSearchBackend: m.webSearch.Backend,
|
||||
BraveSearchAPIKey: m.webSearch.BraveKey,
|
||||
TavilySearchAPIKey: m.webSearch.TavilyKey,
|
||||
DeepSeekSearchBaseURL: m.webSearch.DeepSeekBaseURL,
|
||||
DeepSeekSearchAPIKey: m.webSearch.DeepSeekAPIKey,
|
||||
DeepSeekSearchModel: m.webSearch.DeepSeekModel,
|
||||
WebSearchProxy: m.webSearch.Proxy,
|
||||
BashEnv: proxyEnv(m.proxyAddr, m.proxyCACert), // Bash 子命令默认走代理+信任 CA
|
||||
WorkingDir: mainDir, // 本任务工作目录 <workDir>/tasks/<taskID>
|
||||
ToolOutputDir: cmdOutDir(mainDir),
|
||||
MaxTurns: m.maxTurns, // 0 = unlimited (configurable in agent management)
|
||||
Compaction: compactionConfig(m.compactionWindow()), // long chats stay within the window
|
||||
Todos: actool.NewTodoStore(), // 会话级临时待办(TodoWrite),纯规划用,退出即丢
|
||||
// 命中预算(步数)→ SDK 跑收尾:向用户输出一句进展总结。Prompt 与收尾轮数可后台编辑(默认 10 轮)。
|
||||
Settlement: wrapupSettlement("mainagent", nil),
|
||||
NonStreaming: m.nonStreaming(), // 该 profile 选非流式时走 Provider.Complete
|
||||
|
||||
+14
-11
@@ -394,17 +394,20 @@ func (p *Planner) Plan(ctx context.Context, taskID int64, as *db.AssetStore, ts
|
||||
WebFetchCACert: p.proxyCACert,
|
||||
// 联网搜索(可选)。ddgs 无需 key;brave-free 需 BraveKey;tavily 需 TavilyKey。
|
||||
// WebSearchProxy 是独立出口代理(http/https/socks5),与记录流量的 MITM 代理无关;空则直连。
|
||||
EnableWebSearch: p.webSearch.Enabled,
|
||||
WebSearchBackend: p.webSearch.Backend,
|
||||
BraveSearchAPIKey: p.webSearch.BraveKey,
|
||||
TavilySearchAPIKey: p.webSearch.TavilyKey,
|
||||
WebSearchProxy: p.webSearch.Proxy,
|
||||
BashEnv: proxyEnv(p.proxyAddr, p.proxyCACert), // Bash 子命令默认走代理+信任 CA
|
||||
WorkingDir: taskDir, // 本任务工作目录 <workDir>/tasks/<taskID>
|
||||
ToolOutputDir: cmdOutDir(taskDir),
|
||||
MaxTurns: p.maxTurns, // 0 = unlimited (configurable in agent management)
|
||||
MaxDuration: maxDur, // 0=不限;有 deadline 时=距 deadline 剩余
|
||||
Compaction: compactionConfig(p.compactionWindow()),
|
||||
EnableWebSearch: p.webSearch.Enabled,
|
||||
WebSearchBackend: p.webSearch.Backend,
|
||||
BraveSearchAPIKey: p.webSearch.BraveKey,
|
||||
TavilySearchAPIKey: p.webSearch.TavilyKey,
|
||||
DeepSeekSearchBaseURL: p.webSearch.DeepSeekBaseURL,
|
||||
DeepSeekSearchAPIKey: p.webSearch.DeepSeekAPIKey,
|
||||
DeepSeekSearchModel: p.webSearch.DeepSeekModel,
|
||||
WebSearchProxy: p.webSearch.Proxy,
|
||||
BashEnv: proxyEnv(p.proxyAddr, p.proxyCACert), // Bash 子命令默认走代理+信任 CA
|
||||
WorkingDir: taskDir, // 本任务工作目录 <workDir>/tasks/<taskID>
|
||||
ToolOutputDir: cmdOutDir(taskDir),
|
||||
MaxTurns: p.maxTurns, // 0 = unlimited (configurable in agent management)
|
||||
MaxDuration: maxDur, // 0=不限;有 deadline 时=距 deadline 剩余
|
||||
Compaction: compactionConfig(p.compactionWindow()),
|
||||
// 跨唤醒共享的规划待办:让串行链在多轮之间保留(session 是新的,store 不是)。
|
||||
Todos: p.todoFor(ts.ID()),
|
||||
// 命中【本轮】步数预算→ SDK 跑收尾:把本轮已想清楚的结论落地(该派的 add_intent、
|
||||
|
||||
+21
-7
@@ -26,17 +26,28 @@ import (
|
||||
// goal on its own. Multiple workers run concurrently as goroutines.
|
||||
// WebSearchOpts is the web-search backend selection the server pushes into each
|
||||
// agent (planner/worker/main). Enabled=false leaves the web_search tool off.
|
||||
// Backend is "ddgs" (no key), "brave-free" (BraveKey required), or "tavily"
|
||||
// (TavilyKey required). It maps directly onto agentcore.Options.
|
||||
// Backend is "ddgs" (no key), "brave-free" (BraveKey required), "tavily"
|
||||
// (TavilyKey required), or "deepseek" (DeepSeek* required, filled from the
|
||||
// active LLM profile). It maps directly onto agentcore.Options.
|
||||
// Proxy is a dedicated egress proxy for the search request (http/https/socks5),
|
||||
// independent of the traffic-recording MITM proxy — set it when the search endpoint
|
||||
// is only reachable via a VPN/SOCKS proxy. Empty = direct.
|
||||
//
|
||||
// 注意 deepseek 后端与其它三个的性质不同:DeepSeek 没有可直接调用的搜索接口,
|
||||
// 搜索只存在于其 Anthropic 兼容 messages 接口内部(web_search_20250305 server
|
||||
// tool),因此每次搜索会消耗一次模型调用,且搜索请求由 DeepSeek 服务端发出——
|
||||
// 不经过本机 Proxy,也不会进流量留痕。
|
||||
type WebSearchOpts struct {
|
||||
Enabled bool
|
||||
Backend string
|
||||
BraveKey string
|
||||
TavilyKey string
|
||||
Proxy string
|
||||
// DeepSeek* 来自当前激活的 LLM 配置(仅 anthropic 格式的 DeepSeek 官方端点),
|
||||
// 不单独配置,随 LLM 配置切换而变。
|
||||
DeepSeekBaseURL string
|
||||
DeepSeekAPIKey string
|
||||
DeepSeekModel string
|
||||
}
|
||||
|
||||
type Worker struct {
|
||||
@@ -417,11 +428,14 @@ func (w *Worker) execute(ctx context.Context, name string, taskID int64, as *db.
|
||||
WebFetchCACert: w.proxyCACert,
|
||||
// 联网搜索(可选)。ddgs 无需 key;brave-free 需 BraveKey;tavily 需 TavilyKey。
|
||||
// WebSearchProxy 是独立的出口代理(http/https/socks5),与记录流量的 MITM 代理无关;空则直连。
|
||||
EnableWebSearch: w.webSearch.Enabled,
|
||||
WebSearchBackend: w.webSearch.Backend,
|
||||
BraveSearchAPIKey: w.webSearch.BraveKey,
|
||||
TavilySearchAPIKey: w.webSearch.TavilyKey,
|
||||
WebSearchProxy: w.webSearch.Proxy,
|
||||
EnableWebSearch: w.webSearch.Enabled,
|
||||
WebSearchBackend: w.webSearch.Backend,
|
||||
BraveSearchAPIKey: w.webSearch.BraveKey,
|
||||
TavilySearchAPIKey: w.webSearch.TavilyKey,
|
||||
DeepSeekSearchBaseURL: w.webSearch.DeepSeekBaseURL,
|
||||
DeepSeekSearchAPIKey: w.webSearch.DeepSeekAPIKey,
|
||||
DeepSeekSearchModel: w.webSearch.DeepSeekModel,
|
||||
WebSearchProxy: w.webSearch.Proxy,
|
||||
// Bash 子命令的 HTTP 默认走记录代理 + 信任其 CA(工具无需 -x/-k)。
|
||||
BashEnv: proxyEnv(w.proxyAddr, w.proxyCACert),
|
||||
WorkingDir: runDir,
|
||||
|
||||
@@ -3,7 +3,7 @@ module github.com/Autumn-27/artex
|
||||
go 1.26.3
|
||||
|
||||
require (
|
||||
github.com/Autumn-27/norma v0.3.7
|
||||
github.com/Autumn-27/norma v0.3.8
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jackc/pgx/v5 v5.10.0
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
github.com/Autumn-27/norma v0.3.7 h1:BdzVV3LUqN3zzaoL5cqY9aq0l/ucOYonSewQHhoL8Wo=
|
||||
github.com/Autumn-27/norma v0.3.7/go.mod h1:BudWrf7iHl96FgHqFr/HwN3mKYmGjJDt+xL2ZHXfFZw=
|
||||
github.com/Autumn-27/norma v0.3.8 h1:MOz9bekMyQ29cgt728nZ4gq+HjpeDgQwCTd/7dtBvuc=
|
||||
github.com/Autumn-27/norma v0.3.8/go.mod h1:BudWrf7iHl96FgHqFr/HwN3mKYmGjJDt+xL2ZHXfFZw=
|
||||
github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
|
||||
github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
|
||||
+23
-1
@@ -273,6 +273,9 @@ const (
|
||||
settingConcurrencyLimit = "task_concurrency_limit"
|
||||
// defaultWebSearchBackend is used when web search is on but no backend was picked.
|
||||
defaultWebSearchBackend = "ddgs"
|
||||
// deepSeekWebSearchBackend borrows the active LLM profile instead of its own
|
||||
// key, so it only works on an anthropic-format profile pointed at DeepSeek.
|
||||
deepSeekWebSearchBackend = "deepseek"
|
||||
// defaultWorkers is the concurrent work-agent count when the setting is unset.
|
||||
defaultWorkers = 3
|
||||
// defaultConcurrencyLimit is the simultaneous-running-task cap when the feature
|
||||
@@ -539,7 +542,26 @@ func (m *Manager) WebSearchOpts() agent.WebSearchOpts {
|
||||
if on && backend == "tavily" && strings.TrimSpace(tavilyKey) == "" {
|
||||
on = false
|
||||
}
|
||||
return agent.WebSearchOpts{Enabled: on, Backend: backend, BraveKey: braveKey, TavilyKey: tavilyKey, Proxy: proxy}
|
||||
o := agent.WebSearchOpts{Enabled: on, Backend: backend, BraveKey: braveKey, TavilyKey: tavilyKey, Proxy: proxy}
|
||||
if backend == deepSeekWebSearchBackend {
|
||||
o.DeepSeekBaseURL, o.DeepSeekAPIKey, o.DeepSeekModel = m.deepSeekSearchCreds()
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// deepSeekSearchCreds resolves the credentials the "deepseek" search backend
|
||||
// borrows from the active LLM profile (it has no key of its own). Whether that
|
||||
// profile can actually drive server-side search — DeepSeek exposes it only on
|
||||
// the Anthropic-format endpoint — is deliberately NOT validated here: the UI
|
||||
// states the requirement and the user decides. A profile that can't serve it
|
||||
// simply fails at search time (or at the settings page's 测试 button), which is
|
||||
// the same feedback every other backend gives for a bad key.
|
||||
func (m *Manager) deepSeekSearchCreds() (baseURL, apiKey, model string) {
|
||||
p, err := m.pg.ActiveProfile()
|
||||
if err != nil || p == nil {
|
||||
return "", "", ""
|
||||
}
|
||||
return p.BaseURL, p.APIKey, p.Model
|
||||
}
|
||||
|
||||
// SetWebSearch persists and applies the web-search settings. braveKey, tavilyKey, and
|
||||
|
||||
+14
-2
@@ -3413,10 +3413,22 @@ func (s *Server) testWebSearch(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.TrimSpace(req.TavilyKey) != "" {
|
||||
tavilyKey = req.TavilyKey
|
||||
}
|
||||
cfg := actool.WebSearchConfig{Backend: backend, BraveAPIKey: braveKey, TavilyAPIKey: tavilyKey, Proxy: proxy}
|
||||
// Hard cap so a slow/blocked proxy can't hang the request.
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
|
||||
wall := 30 * time.Second
|
||||
// deepseek 的凭据不在表单里,来自当前激活的 LLM 配置;同时它每次搜索都跑一次
|
||||
// 模型推理,30s 的通用上限偏紧,单独放宽。这里不预判配置能不能用——测这一下
|
||||
// 本来就是给用户自己确认的手段,真跑不通时下面的报错比预判更有信息量。
|
||||
probeQuery := "test"
|
||||
if strings.TrimSpace(backend) == deepSeekWebSearchBackend {
|
||||
cfg.DeepSeekBaseURL, cfg.DeepSeekAPIKey, cfg.DeepSeekModel = s.m.deepSeekSearchCreds()
|
||||
wall = 120 * time.Second
|
||||
// 搜索词由 DeepSeek 端的模型自行决定,"test" 太空泛会让它跳过搜索直接作答。
|
||||
probeQuery = "DeepSeek company official website"
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(r.Context(), wall)
|
||||
defer cancel()
|
||||
results, err := actool.WebSearchProbe(ctx, actool.WebSearchConfig{Backend: backend, BraveAPIKey: braveKey, TavilyAPIKey: tavilyKey, Proxy: proxy}, "test", 3)
|
||||
results, err := actool.WebSearchProbe(ctx, cfg, probeQuery, 3)
|
||||
if err != nil {
|
||||
writeJSON(w, 200, map[string]any{"ok": false, "error": err.Error(), "backend": backend})
|
||||
return
|
||||
|
||||
@@ -398,8 +398,9 @@ export default function SystemSettingsPage() {
|
||||
<b>web_search</b>(仅返回标题/链接/摘要,不抓取正文;抓取由 WebFetch 负责)。网络搜索<b>不走</b>
|
||||
记录代理,独立于流量捕获。
|
||||
<br />
|
||||
来源可选 <b>DuckDuckGo(ddgs)</b>(无需 Key)、<b>Brave(免费版)</b>(需填写 Brave API Key)或{" "}
|
||||
<b>Tavily</b>(需填写 Tavily API Key)。总开关关闭时,各 Agent 的网络搜索开关不可用。
|
||||
来源可选 <b>DuckDuckGo(ddgs)</b>(无需 Key)、<b>Brave(免费版)</b>(需填写 Brave API Key)、{" "}
|
||||
<b>Tavily</b>(需填写 Tavily API Key)或 <b>DeepSeek</b>(复用当前 LLM 配置)。总开关关闭时,各
|
||||
Agent 的网络搜索开关不可用。
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
@@ -436,11 +437,31 @@ export default function SystemSettingsPage() {
|
||||
<SelectItem value="ddgs">DuckDuckGo(ddgs · 免费无 Key)</SelectItem>
|
||||
<SelectItem value="brave-free">Brave(免费版 · 需 Key)</SelectItem>
|
||||
<SelectItem value="tavily">Tavily(需 Key)</SelectItem>
|
||||
<SelectItem value="deepseek">DeepSeek(官方)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{webSearch && backend === "deepseek" && (
|
||||
<div className="border-border/60 bg-muted/30 flex flex-col gap-2 rounded-md border p-3">
|
||||
<p className="text-sm font-medium">DeepSeek 官方联网搜索</p>
|
||||
<p className="text-muted-foreground text-xs leading-relaxed">
|
||||
该来源直接复用<b>当前激活的 LLM 配置</b>。因此它
|
||||
<b>仅支持 DeepSeek 官方模型</b>,且该配置<b>必须使用 anthropic 协议</b>
|
||||
——DeepSeek 的 OpenAI 协议端点不支持服务端搜索。切换 LLM 配置后此来源可能失效。
|
||||
</p>
|
||||
<p className="text-muted-foreground text-xs leading-relaxed">
|
||||
与其它来源不同,搜索由 <b>DeepSeek 服务端执行</b>:每次搜索会额外消耗一次模型调用(产生 Token
|
||||
费用),搜索请求<b>不经过上面的出口代理</b>,也<b>不计入流量留痕</b>;返回结果<b>只有标题和链接</b>
|
||||
(无摘要),需要正文时由 WebFetch 抓取。
|
||||
</p>
|
||||
<p className="text-muted-foreground text-xs leading-relaxed">
|
||||
是否满足上述条件由你自行确认,系统不做拦截;可用下方「测试搜索」按钮实际跑一次来验证。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{webSearch && backend === "brave-free" && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor="brave-key" className="text-sm font-normal text-muted-foreground">
|
||||
|
||||
@@ -889,7 +889,7 @@ export interface Settings {
|
||||
// Web search. brave_key_set / tavily_key_set reflect whether a key is stored
|
||||
// (the values are never returned). On PUT, send the corresponding field to set/clear.
|
||||
web_search_enabled: boolean;
|
||||
web_search_backend: string; // "ddgs" | "brave-free" | "tavily"
|
||||
web_search_backend: string; // "ddgs" | "brave-free" | "tavily" | "deepseek"
|
||||
brave_key_set: boolean;
|
||||
tavily_key_set: boolean;
|
||||
// write-only: only sent on PUT to store/clear the key.
|
||||
|
||||
Reference in new issue
Block a user