From 5ffac284d4ec776fe2cdf5418994ae352edf63e7 Mon Sep 17 00:00:00 2001 From: fylorn <249551762+fylorn@users.noreply.github.com> Date: Tue, 13 Oct 2026 09:51:25 +0800 Subject: [PATCH] Docs for Lite 2026.10.19, core 0.73.0 and ThinkWatch 3.8.0 Security is described by protection: Secrets & privacy, Dangerous commands and Content filter, each On, Monitor or Off, with an action per rule. Content rules can check answers and replace matches. Also covers the 0.72.0 fixes: redacted values restored exactly, and the cause of a gateway failure shown in the request's error. Co-Authored-By: Claude Opus 5.5 --- src/content/docs-core/en/overview.md | 6 +- src/content/docs-core/zh-CN/overview.md | 6 +- src/content/docs-lite/en/compare-cc-switch.md | 2 +- src/content/docs-lite/en/features.md | 26 ++++--- .../docs-lite/en/keep-api-keys-from-relays.md | 35 +++++----- src/content/docs-lite/en/overview.md | 2 +- src/content/docs-lite/en/plugins.md | 12 ++-- .../docs-lite/zh-CN/compare-cc-switch.md | 2 +- src/content/docs-lite/zh-CN/features.md | 26 ++++--- .../zh-CN/keep-api-keys-from-relays.md | 35 +++++----- src/content/docs-lite/zh-CN/overview.md | 2 +- src/content/docs-lite/zh-CN/plugins.md | 12 ++-- src/content/docs/_meta.ts | 4 +- src/content/docs/en/api-reference.md | 1 + src/content/docs/en/architecture.md | 2 +- src/content/docs/en/configuration.md | 29 ++++++-- src/content/docs/en/deployment-guide.md | 6 +- src/content/docs/en/overview.md | 2 +- src/content/docs/zh-CN/api-reference.md | 1 + src/content/docs/zh-CN/architecture.md | 2 +- src/content/docs/zh-CN/configuration.md | 33 ++++++--- src/content/docs/zh-CN/deployment-guide.md | 6 +- src/content/docs/zh-CN/overview.md | 2 +- src/data/core-docs/config.md | 68 ++++++++++++------- src/data/core-docs/config.zh-CN.md | 40 +++++++---- src/data/core-docs/manifest.json | 6 +- src/i18n/index.ts | 8 +-- src/i18n/pages/core.ts | 4 +- src/i18n/pages/lite.ts | 12 ++-- 29 files changed, 233 insertions(+), 159 deletions(-) diff --git a/src/content/docs-core/en/overview.md b/src/content/docs-core/en/overview.md index 7b32375..72f535d 100644 --- a/src/content/docs-core/en/overview.md +++ b/src/content/docs-core/en/overview.md @@ -15,9 +15,9 @@ Clients such as Claude Code and Codex send their requests to the gateway, and Co - **Rule-based routing.** Rules match on the model, the gateway key, the input size, the presence of tools or images and other properties of a request, and send it to an upstream or a group, rewrite its parameters or refuse it. When the client and the upstream use different API formats, the request is converted between Anthropic Messages, OpenAI Chat Completions, OpenAI Responses and Gemini. - **Failover before the first byte.** Until the first byte reaches the client, a failing upstream is replaced by the next one without the client noticing. After that point, the failure is reported. A circuit breaker keeps requests away from an upstream that keeps failing. - **Cost accounting.** Token usage and cache hits are priced from a public price table, which the control plane refreshes daily, or from a price sheet in the configuration. Each request records its cost and where the price came from. Estimated amounts are marked as such, and usage that cannot be priced is labelled *unknown* rather than given an invented figure. -- **Outbound redaction.** Credentials and personal information in a request are replaced with placeholders before the request leaves, and restored when the model echoes them back. Field names are not searched, and custom rules also skip the ids, types, roles and names a protocol needs as they are. -- **Tool-call inspection.** Tool calls returned by an upstream are checked against a rule set, and a dangerous call can be cut off mid-stream. -- **Content filter.** The user messages and tool results a client sends are checked by keyword, regular expression or code point, and each rule refuses the request, deletes what it matched or only records it; the built-in rules also catch hidden characters that can carry instructions. Each of the three guards is set to `off`, `observe` or `enforce`, and all start in `observe`. +- **Outbound redaction** (Secrets & privacy in ThinkWatch Lite). Credentials and personal information in a request are replaced with placeholders before the request leaves, and restored exactly as written when the model echoes them back, tool-call arguments included; a rule can instead only record what it finds. Field names are not searched, and custom rules also skip the ids, types, roles and names a protocol needs as they are. +- **Tool-call inspection** (Dangerous commands in ThinkWatch Lite). Tool calls returned by an upstream are checked against a rule set, and a dangerous call can be cut off mid-stream or only recorded. +- **Content filter.** The user messages and tool results a client sends are checked by keyword, regular expression or code point, and a rule can also check the text of the answer as it streams. Each rule refuses the request, deletes what it matched, replaces it with a text of its own or only records it; the built-in rules also catch hidden characters that can carry instructions. Each of the three guards is set to `off`, `observe` or `enforce`, and all start in `observe`; under `enforce` every rule does what its action says. - **An encrypted control plane.** The desktop app and `twcore` commands reach core over a local socket (a loopback port on Windows) and, when it is enabled, a remote control port. Every control connection starts with a Noise handshake keyed by `listen.control.key`; there are no certificates. ## Further reading diff --git a/src/content/docs-core/zh-CN/overview.md b/src/content/docs-core/zh-CN/overview.md index 09e42db..be978a3 100644 --- a/src/content/docs-core/zh-CN/overview.md +++ b/src/content/docs-core/zh-CN/overview.md @@ -15,9 +15,9 @@ Claude Code、Codex 等客户端把请求发往网关后,Core 提供以下功 - **按规则路由。** 规则按模型、网关密钥、输入规模、是否携带工具或图片等请求属性匹配,将请求发往某个上游或策略组、改写其参数,或拒绝请求。客户端与上游的接口格式不同时,请求在 Anthropic Messages、OpenAI Chat Completions、OpenAI Responses 与 Gemini 之间转换。 - **首字节前的故障转移。** 首字节到达客户端之前,出错的上游由下一个上游替换,客户端无从察觉;此后发生的故障如实报告。熔断器使持续出错的上游暂不接收请求。 - **费用核算。** token 用量与缓存命中按公开价目表计价(控制面每天刷新一次),或按配置中的价目表计价;每个请求都记录费用及价格来源。估算的金额另行标注,无法计价的用量标记为「未知」,不会填入虚构的数值。 -- **出站脱敏。** 请求发出之前,其中的凭据和个人信息替换为占位符;模型回显时再恢复原值。字段名不在查找之列,自定义规则还会跳过协议要求原样保留的 id、类型、角色和名称。 -- **工具调用审查。** 上游返回的工具调用按规则集审查,高危调用可在流式传输中途截断。 -- **内容过滤。** 客户端发送的用户消息和工具结果按关键词、正则表达式或码位检查,每条规则可拒绝请求、删除命中的内容或仅记录;内置规则也能查出可夹带指令的隐藏字符。三项防护各可设为 `off`、`observe` 或 `enforce`,出厂均为 `observe`。 +- **出站脱敏**(ThinkWatch Lite 中称为「密钥与隐私」)。请求发出之前,其中的凭据和个人信息替换为占位符;模型回显时按原值的写法如实恢复,工具调用参数中的值也是如此。规则也可以只记录、不替换。字段名不在查找之列,自定义规则还会跳过协议要求原样保留的 id、类型、角色和名称。 +- **工具调用审查**(ThinkWatch Lite 中称为「危险命令」)。上游返回的工具调用按规则集审查,高危调用可在流式传输中途截断,或只作记录。 +- **内容过滤。** 客户端发送的用户消息和工具结果按关键词、正则表达式或码位检查,规则也可以在回答流式输出时检查回答正文。每条规则可拒绝请求、删除命中的内容、替换为指定的文字或仅记录;内置规则也能查出可夹带指令的隐藏字符。三项防护各可设为 `off`、`observe` 或 `enforce`,出厂均为 `observe`;`enforce` 下每条规则按其动作处理。 - **加密的控制面。** 桌面应用与 `twcore` 命令通过本地 socket(Windows 上为回环端口)连接 core,开启后也可经远程控制端口连接。每条控制连接都先以 `listen.control.key` 完成 Noise 握手,不使用证书。 ## 后续阅读 diff --git a/src/content/docs-lite/en/compare-cc-switch.md b/src/content/docs-lite/en/compare-cc-switch.md index 1f621fa..aae982a 100644 --- a/src/content/docs-lite/en/compare-cc-switch.md +++ b/src/content/docs-lite/en/compare-cc-switch.md @@ -24,7 +24,7 @@ A dash means the feature is not described in that product's documentation. | API format conversion | Proxy mode: Claude Code to OpenAI Chat Completions or Responses; Codex to Chat Completions or Anthropic Messages | Among Anthropic Messages, OpenAI Chat Completions, OpenAI Responses and Gemini | | Usage and cost | Requests, tokens, cache hit rate and estimated cost, from proxy logs or the clients' session logs; custom prices, optional sync from models.dev; quota and balance display | Tokens, cost and requests by period, model and upstream; LiteLLM prices refreshed daily, or custom price sheets; estimates marked, unpriced requests counted separately; the balances and quotas that upstreams report | | Request details | Provider, model, tokens, cost, timing and status; parameters, a response summary and errors | Matched rule, each attempt with its status, request and response bodies, cost; full-text search; replay against another upstream | -| Outbound redaction and tool-call inspection | — | API keys, private keys, ID and bank card numbers replaced before a request leaves; tool calls that download and run code or send out credentials cut off. Both start by only recording | +| Secrets & privacy and Dangerous commands | — | API keys, private keys, ID and bank card numbers replaced before a request leaves; tool calls that download and run code or send out credentials cut off. Both start in Monitor, which records and notifies | | MCP and skills | One MCP server list synced to the selected clients; skills installed from GitHub or ZIP files | MCP servers of 13 clients side by side, copied or removed for 4; skills and hooks listed; all scanned for hidden characters, prompt injection, dangerous commands and overly broad permissions | | Prompts | Prompt presets written to `CLAUDE.md`, `AGENTS.md` or `GEMINI.md` | — | | Sessions | Reads the clients' own session files; search, resume in a terminal, delete | Requests that passed through the gateway grouped into sessions and replayed turn by turn | diff --git a/src/content/docs-lite/en/features.md b/src/content/docs-lite/en/features.md index d28c714..9cc29e0 100644 --- a/src/content/docs-lite/en/features.md +++ b/src/content/docs-lite/en/features.md @@ -16,9 +16,9 @@ Until the first request has gone to an upstream, the Overview page shows a get-s ## Traffic and sessions -The Traffic page lists requests as they arrive: status, key, model, upstream, time to first token and total time (with the generation speed on hover), tokens (with the upload and download on hover) and cost, with marks for a converted API format, redacted keys, text deleted by the content filter and a blocked or suspicious tool call. Long upstream, model and key names are cut short, and hovering shows them in full. The list can be searched (path, key, upstream, model and error message), filtered by key, upstream and model, or narrowed to failed or unpriced requests. It holds the latest 2,000 requests, and a search or filter also runs over the stored history, further back on request. With content search on, it also covers what each request newly sent (the last user turn, tool results included) and its answer (tool calls included), for as long as payloads are kept; a match shows its excerpt under the request. The Sessions view groups the requests of one conversation into turns, with the input tokens and the cost of each turn. Each turn also shows how full the model's context window was: the tokens sent to the model over the window, with cache reads as their own segment. Opening a turn shows an estimate of how much the system prompt, the tool definitions, the earlier conversation and the last user message took. A session's Conversation tab replays it turn by turn: the messages each turn added and its answer, with text, folded thinking, tool calls beside their results, and images by type and size. Changes to the system prompt and restarts after compaction are marked, and a turn whose bodies are past retention, were too large to keep whole or cannot be read says so. Each turn opens its request. +The Traffic page lists requests as they arrive: status, key, model, upstream, time to first token and total time (with the generation speed on hover), tokens (with the upload and download on hover) and cost, with marks for a converted API format, redacted keys, text deleted or replaced by the content filter and a blocked or suspicious tool call. Long upstream, model and key names are cut short, and hovering shows them in full. The list can be searched (path, key, upstream, model and error message), filtered by key, upstream and model, or narrowed to failed or unpriced requests. It holds the latest 2,000 requests, and a search or filter also runs over the stored history, further back on request. With content search on, it also covers what each request newly sent (the last user turn, tool results included) and its answer (tool calls included), for as long as payloads are kept; a match shows its excerpt under the request. The Sessions view groups the requests of one conversation into turns, with the input tokens and the cost of each turn. Each turn also shows how full the model's context window was: the tokens sent to the model over the window, with cache reads as their own segment. Opening a turn shows an estimate of how much the system prompt, the tool definitions, the earlier conversation and the last user message took. A session's Conversation tab replays it turn by turn: the messages each turn added and its answer, with text, folded thinking, tool calls beside their results, and images by type and size. Changes to the system prompt and restarts after compaction are marked, and a turn whose bodies are past retention, were too large to keep whole or cannot be read says so. Each turn opens its request. -A request opens into its timeline, its routing (the rule it matched, the group it went through and each attempt with its status and duration), its content, and its usage and cost. The timeline gives the proxy the request went out through (**Egress**, or **Direct**) and how much it sent to its upstreams and received from them (**Upload** and **Download**), measured as it crossed the network: after the gateway's own compression, before decoding, and summed over failover attempts. A request from DeepSeek Harness also shows the size of the session log it carried, the whole conversation the client attaches to every request; the gateway removes it before a request goes to an upstream other than DeepSeek. A finished request can be sent again, unchanged, to another upstream after an estimate of its cost, and the two responses are shown side by side. +A request opens into its timeline, its routing (the rule it matched, the group it went through and each attempt with its status and duration), its content, and its usage and cost. The timeline gives the proxy the request went out through (**Egress**, or **Direct**) and how much it sent to its upstreams and received from them (**Upload** and **Download**), measured as it crossed the network: after the gateway's own compression, before decoding, and summed over failover attempts. A request from DeepSeek Harness also shows the size of the session log it carried, the whole conversation the client attaches to every request; the gateway removes it before a request goes to an upstream other than DeepSeek. A finished request can be sent again, unchanged, to another upstream after an estimate of its cost, and the two responses are shown side by side. When the gateway's own code fails during a request, the request's error says what failed and where. The **Content** tab has two views, **Parsed** and **Raw**, and both are live while the request runs. **Parsed** shows the conversation, with the answer appearing as it streams, thinking and tool-call arguments included. **Raw** shows the request and response lines, headers and bodies, with each streamed event appended as it arrives; **Follow latest** keeps the newest in view. In Raw, **Client side** and **Upstream side** show what the client and the upstream each exchanged with the gateway, which differ when the API format is converted or a plugin rewrites the request. Keys are replaced in both views, as in stored requests. The places a security rule matched are marked in both views, in the colors of the security log, and a folded part that holds one carries a dot. @@ -45,7 +45,7 @@ Usage limits keep one client from using up a budget: each caps the key at a numb ## Upstreams -Upstreams are the services requests are forwarded to: API keys for Anthropic, OpenAI, Google Gemini, DeepSeek or any compatible endpoint, Amazon Bedrock (with an API key, access keys or an AWS profile), a ChatGPT account or a Z.ai / BigModel account signed in from the app, relays such as OpenRouter, Sub2API and New API / One API, a ThinkWatch Enterprise gateway, and local models such as Ollama. When a client and an upstream use different API formats, requests are converted between Anthropic Messages, OpenAI Chat Completions, OpenAI Responses and Gemini, and the fields that cannot be carried over are listed on the request. A model's reasoning survives the conversion: the reasoning a Chat Completions upstream such as DeepSeek, Kimi or GLM returns reaches the client as it is and goes back to that upstream on the next turn, so a conversation with tool calls can continue, and the thought signatures on a Gemini model's tool calls are kept as well. When a Chat Completions model writes a tool call into its answer text, the gateway recognises it as an ordinary tool call, provided the request defined that tool, and it goes through tool-call inspection like any other. A request body a client sends compressed with gzip, deflate or zstd is read as usual, and an answer an upstream sends compressed reaches the client decoded. Clients such as Codex mark no prompt-cache breakpoints; when their requests are converted for an upstream in Anthropic Messages format, or for a Claude model on Bedrock that AWS lists for prompt caching (Claude 3.5 Sonnet v2, Claude 3.7 Sonnet, and Claude 4.5 and later), the gateway marks them, so each turn reads what the previous one cached. An upstream that refuses the marks receives the request again without them. Upstreams can be reached through an outbound proxy and priced with a price sheet of their own; aliases, proxies and price sheets have tabs on the same page. The **Traffic · 24 h** column of the **Proxies** tab gives the upload and download through each proxy over the last 24 hours, with 7 and 30 days on hover. An optional **Concurrency limit** suits relays and accounts that allow only so many requests at once: when the upstream is full, a conversation that stays on it waits for a free slot, other requests go to the next upstream, and when every upstream is full a request waits and then receives a busy error. A streamed request waiting for a slot or for its key's usage window receives keep-alive pings while it waits. **Specs…** in an upstream's model list sets by hand a model's context window, maximum output, and whether it reasons and takes images, for a model the price table lacks or gets wrong; the values set there are used in place of the price table's. A connection test times the DNS lookup and the TCP, TLS and proxy handshakes without incurring any cost; an inference test measures the time to first token and estimates its cost before it runs. +Upstreams are the services requests are forwarded to: API keys for Anthropic, OpenAI, Google Gemini, DeepSeek or any compatible endpoint, Amazon Bedrock (with an API key, access keys or an AWS profile), a ChatGPT account or a Z.ai / BigModel account signed in from the app, relays such as OpenRouter, Sub2API and New API / One API, a ThinkWatch Enterprise gateway, and local models such as Ollama. When a client and an upstream use different API formats, requests are converted between Anthropic Messages, OpenAI Chat Completions, OpenAI Responses and Gemini, and the fields that cannot be carried over are listed on the request. A model's reasoning survives the conversion: the reasoning a Chat Completions upstream such as DeepSeek, Kimi or GLM returns reaches the client as it is and goes back to that upstream on the next turn, so a conversation with tool calls can continue, and the thought signatures on a Gemini model's tool calls are kept as well. When a Chat Completions model writes a tool call into its answer text, the gateway recognises it as an ordinary tool call, provided the request defined that tool, and Dangerous commands checks it like any other. A request body a client sends compressed with gzip, deflate or zstd is read as usual, and an answer an upstream sends compressed reaches the client decoded. Clients such as Codex mark no prompt-cache breakpoints; when their requests are converted for an upstream in Anthropic Messages format, or for a Claude model on Bedrock that AWS lists for prompt caching (Claude 3.5 Sonnet v2, Claude 3.7 Sonnet, and Claude 4.5 and later), the gateway marks them, so each turn reads what the previous one cached. An upstream that refuses the marks receives the request again without them. Upstreams can be reached through an outbound proxy and priced with a price sheet of their own; aliases, proxies and price sheets have tabs on the same page. The **Traffic · 24 h** column of the **Proxies** tab gives the upload and download through each proxy over the last 24 hours, with 7 and 30 days on hover. An optional **Concurrency limit** suits relays and accounts that allow only so many requests at once: when the upstream is full, a conversation that stays on it waits for a free slot, other requests go to the next upstream, and when every upstream is full a request waits and then receives a busy error. A streamed request waiting for a slot or for its key's usage window receives keep-alive pings while it waits. **Specs…** in an upstream's model list sets by hand a model's context window, maximum output, and whether it reasons and takes images, for a model the price table lacks or gets wrong; the values set there are used in place of the price table's. A connection test times the DNS lookup and the TCP, TLS and proxy handshakes without incurring any cost; an inference test measures the time to first token and estimates its cost before it runs. **New upstream** starts with the service. The services are listed in three groups, each with its logo and a one-line description, and can be searched: **Model vendors** (Anthropic, OpenAI, Google Gemini, DeepSeek, Z.ai / BigModel), **Platforms and relays** (Amazon Bedrock, OpenRouter, ThinkWatch, Sub2API, New API / One API) and **Local and custom** (Ollama, Custom). Picking one goes straight to **Connection**, which asks only for what that service needs. **Authentication** offers the methods the service has: an API key or a ChatGPT account for OpenAI, an API key or an account sign-in for Z.ai / BigModel, an API key, access keys or an AWS profile for Bedrock, and an API key or OAuth for custom endpoints, while ThinkWatch, Sub2API and New API / One API take an API key; a service with a single method shows no choice. What the service already decides, such as its address, its protocol or that Ollama takes no key, is filled in or left out. Request headers, client identity forwarding, the behaviour when the proxy is unavailable and the concurrency limit are under **Advanced settings**, which opens by itself when one of them is set. **Next** checks the connection at no cost: when it passes, **Models** opens with the latency, the number of models found and any balance on top; when it fails, the reason is shown with **Retry** and **Continue anyway**, for an upstream that refuses the check but serves requests. A ChatGPT or Z.ai / BigModel account is signed in inside the dialog, once its notes are acknowledged: in the default browser, or in another browser through **Copy link**, and a ChatGPT account also with a device code. Once signed in, the upstream is saved and the dialog goes to **Models**, with the account on top. When the app is connected to a remote core, a ChatGPT account signs in with a device code only, and the verification address and the code can each be copied. @@ -73,17 +73,21 @@ Every request records the rule it matched, the group it went through and each at ## Security -The Security page holds three protections: outbound redaction, tool-call inspection and the content filter. They apply to every upstream and every key alike, and each runs in one of three modes: Off, Observe (detect and record, change nothing) and a third mode named for what it does: Replace for outbound redaction, Cut off for tool-call inspection and Enforce for the content filter. All three start in Observe, so out of the box no request is changed or refused. +The Security page has a **Log** tab and a tab for each of three protections: **Secrets & privacy**, **Dangerous commands** and **Content filter**. They apply to every upstream and every key alike. Each protection is **On**, **Monitor** or **Off**, shown as a dot on its tab. **On** handles each match by the action of the rule that found it. **Monitor** records every match in the log and raises a notification, and changes nothing. **Off** checks nothing. All three start in **Monitor**, so out of the box no request or answer is changed or refused. -- **Outbound redaction** searches the whole request before it leaves, including the system prompt, earlier turns and tool calls, for credentials and personal information: API keys and tokens for Anthropic, OpenAI, GitHub, Slack, AWS, Google, GitLab, Stripe, npm, DigitalOcean and SendGrid, private keys, JWTs and passwords in connection strings, as well as Chinese resident ID numbers and bank card numbers, which count only when their structure and check digit are valid. Field names are not searched, and custom rules leave alone the identifiers a protocol needs as they are, such as item and call ids, types, roles, tool names and model names, so a rule cannot break an id a client sends back. In Replace mode they are replaced with placeholders such as `<>` and restored where the response repeats them. Rules for email addresses, Chinese mainland mobile numbers, internal IP addresses and internal domains are included and start off, and a custom rule can name its own placeholder: `PROJECT` gives `<>`. -- **Tool-call inspection** checks the tool calls a model returns for commands that download or decode code and run it, send out environment variables or credential files, send a credential to a host that is neither local nor the credential's own provider, read private keys or cloud credentials, read or change ThinkWatch's own data directory, or install startup items and scheduled jobs. A path that only appears in text being written, such as a document that mentions the directory, does not count. In Cut off mode such a call cuts the response off, so the client never receives a complete call to run. Deleting the home or root directory, making files world-writable and uploading a local file to an outside host are only recorded by default. -- **Content filter** checks the user messages and tool results in each request, context compaction included. A rule matches a keyword, a regular expression or code points such as `U+E0000–U+E007F`, and in Enforce mode it refuses the request, deletes the matched text and sends the rest, or only records. Built-in rules delete Unicode tag characters and bidirectional controls, which can hide instructions from people but not from a model, and refuse explicit "ignore previous instructions" phrasing. Rules for zero-width and private-use characters, which emoji, Persian text and icon fonts also use, and for jailbreaks, persona manipulation, prompt extraction and their Chinese counterparts start off and can be switched on. +- **Secrets & privacy** searches the whole request before it leaves, including the system prompt, earlier turns and tool calls, for credentials and personal information: API keys and tokens for Anthropic, OpenAI, GitHub, Slack, AWS, Google, GitLab, Stripe, npm, DigitalOcean and SendGrid, private keys, JWTs and passwords in connection strings, as well as Chinese resident ID numbers and bank card numbers, which count only when their structure and check digit are valid. Field names are not searched, and custom rules leave alone the identifiers a protocol needs as they are, such as item and call ids, types, roles, tool names and model names, so a rule cannot break an id a client sends back. A rule either replaces what it finds with a placeholder such as `<>`, or records it and sends it unchanged. A placeholder the answer repeats is restored exactly as the value was written: a private key keeps its line breaks, and a value inside a tool call's arguments or Codex's freeform tool input, such as `apply_patch`, comes back so the client can use it. Rules for email addresses, Chinese mainland mobile numbers, internal IP addresses and internal domains are included and start off, and a custom rule can name its own placeholder: `PROJECT` gives `<>`. +- **Dangerous commands** checks the tool calls a model returns for commands that download or decode code and run it, send out environment variables or credential files, send a credential to a host that is neither local nor the credential's own provider, read private keys or cloud credentials, read or change ThinkWatch's own data directory, or install startup items and scheduled jobs. A path that only appears in text being written, such as a document that mentions the directory, does not count. A rule either cuts the answer off, so the client never receives a complete call to run, or only records the call. Deleting the home or root directory, making files world-writable and uploading a local file to an outside host are only recorded by default. +- **Content filter** checks requests and, rule by rule, the model's answers. In a request it checks the user messages and tool results, context compaction included. In an answer it checks the text the model writes, including Codex's freeform tool input; tool calls are left to Dangerous commands, and thinking is not checked. A rule matches a keyword, a regular expression or code points such as `U+E0000–U+E007F`, and refuses the request, deletes the match without leaving a marker, replaces it with the rule's replacement text (`***` by default), or only records it. A replacement is not undone in the answer. Answers keep streaming: only the few characters at the end that could still become a match are held back. While a rule on answers can delete or replace, token probabilities (logprobs) are left out of streamed answers. Built-in rules check requests: they delete Unicode tag characters and bidirectional controls, which can hide instructions from people but not from a model, and refuse explicit "ignore previous instructions" phrasing. Rules for zero-width and private-use characters, which emoji, Persian text and icon fonts also use, and for jailbreaks, persona manipulation, prompt extraction and their Chinese counterparts start off and can be switched on. -The page lists every rule, the built-in ones grouped by kind. Built-in rules can be switched on or off one at a time; a built-in tool-call rule can be set to cut off or only record, and a built-in content rule to refuse, delete or only record. A custom redaction rule looks for its text as written (**Contains**, the default) or takes a regular expression (**Regex**), and ignores case unless **Match case** is on; a custom content rule matches a keyword, a regular expression or code points, and a custom tool-call rule is a regular expression. Any rule can be tried on a sample text first; for redaction and the content filter, the test also shows the text as it would be sent. Everything the protections find is kept in the log on the first tab, together with the request it came from; when hidden characters spell out text, the log shows that text. +Every rule has its own switch and its own action, both set directly in the list: Secrets & privacy rules **Replace with placeholder** or **Record only**; Dangerous commands rules **Cut off** or **Record only**; Content filter rules **Refuse**, **Delete**, **Replace** or **Record only**. While a protection is in **Monitor**, each rule shows its action with **Monitoring** next to it. Built-in rules are grouped by category, with a checkbox on each group that switches all of its rules at once, and a search box filters rules by name and pattern. -An entry in the log opens in place. It lists every place the rule matched, up to 50 with the number of the rest: the part of the request or answer it was in (the system prompt, a message with its number and role, a tool call or tool result with the tool's name, or the answer text), its JSON path, and up to 80 characters of context on either side, with credentials masked. It gives the rule as it was when it matched, a custom rule's pattern and how it matches, or a built-in rule's name with the core version that evaluated it, so the entry stays readable after the rule is changed or deleted. It states exactly what was done: the placeholder a value was replaced with, the tool call that was cut off and the notice the client received instead, the reply the client received for a refused request, or how many matched segments were deleted. The session and, when it differs from the model requested, the model sent to the upstream are given as well. The entries in a request's timeline open the same way. **Export** saves every entry of the selected period as JSON (full detail) or CSV (one row per entry). The log is kept as long as the request records, and changes to the protections' settings are not written to it. +A custom Secrets & privacy rule looks for its text as written (**Contains**, the default) or takes a regular expression (**Regex**), and ignores case unless **Match case** is on. A custom content rule says what it **Checks**: **Request**, **Answer** or **Request and answer**. It matches a keyword, a regular expression or code points, and ignores case unless **Match case** is on. A rule on answers cannot refuse and cannot match code points; the dialog shows those options as unavailable, with the reason. A custom Dangerous commands rule is a regular expression. Any rule can be tried on a sample text first, and for Secrets & privacy and the content filter the test also shows the text after processing; a content sample can be tried as a request or as an answer. -The protections act on requests and answers passing through the gateway, not on files on disk. The configuration file holds keys in plain text and only its owner can read it, which keeps out other users but not programs running as the same user; outbound redaction protects what leaves the machine, not the file. +**Record only**, and every rule while its protection is in **Monitor**, writes the match to the log and raises a system notification that names the rule and the upstream, never the matched text. The same rule notifies at most once every 5 minutes, and matches that arrive together are merged into one notification. Everything the protections find is kept in the log on the first tab, together with the request it came from; when hidden characters spell out text, the log shows that text. + +An entry in the log opens in place. It lists every place the rule matched, up to 50 with the number of the rest: the part of the request or answer it was in (the system prompt, a message with its number and role, a tool call or tool result with the tool's name, or the answer text), its JSON path, and up to 80 characters of context on either side, with credentials masked. It gives the rule as it was when it matched, a custom rule's pattern and how it matches, or a built-in rule's name with the core version that evaluated it, so the entry stays readable after the rule is changed or deleted. It states exactly what was done: the placeholder a value was replaced with, the tool call that was cut off and the notice the client received instead, the reply the client received for a refused request, or how many places were deleted or replaced, and with what text. The session and, when it differs from the model requested, the model sent to the upstream are given as well. The entries in a request's timeline open the same way. **Export** saves every entry of the selected period as JSON (full detail) or CSV (one row per entry). The log is kept as long as the request records, and changes to the protections' settings are not written to it. + +The protections act on requests and answers passing through the gateway, not on files on disk. The configuration file holds keys in plain text and only its owner can read it, which keeps out other users but not programs running as the same user; Secrets & privacy protects what leaves the machine, not the file. ## MCP @@ -115,4 +119,4 @@ On Windows the icon sits in the notification area. Hovering over it shows the ga On Linux the icon sits in the system tray. Clicking it opens the same menu, with the Today block and the quota bars written out as text as on Windows; its first item, Open ThinkWatch Lite, brings up the main window. -System notifications, native on macOS and Windows and sent through the desktop's notification service on Linux, report when the gateway stops forwarding or keeps restarting, the connection to a remote core drops, a subscription quota runs out, a sign-in expires or an upstream rejects its credential, a proxy cannot be reached, the configuration file fails validation, a tool call matches a rule that cuts the response off, a key nears or reaches a daily, weekly or monthly usage limit, or suspicious content appears in a client's configuration. A new version found by the automatic check is listed among the notices, in grey, and announced the same way (see [Updates](/docs/lite/install#updates)). An unreachable upstream, which a fallback usually covers, is only listed in the app. Notices as a whole can be set to system notifications, in-app only, or off. Marking a notice as read stops the bell from counting it; the notice stays in the list until the problem behind it clears or the list is cleared. +System notifications, native on macOS and Windows and sent through the desktop's notification service on Linux, report when the gateway stops forwarding or keeps restarting, the connection to a remote core drops, a subscription quota runs out, a sign-in expires or an upstream rejects its credential, a proxy cannot be reached, the configuration file fails validation, a tool call is cut off, a security rule records a match (see [Security](#security)), a key nears or reaches a daily, weekly or monthly usage limit, or suspicious content appears in a client's configuration. A new version found by the automatic check is listed among the notices, in grey, and announced the same way (see [Updates](/docs/lite/install#updates)). An unreachable upstream, which a fallback usually covers, is only listed in the app. Notices as a whole can be set to system notifications, in-app only, or off. Marking a notice as read stops the bell from counting it; the notice stays in the list until the problem behind it clears or the list is cleared. diff --git a/src/content/docs-lite/en/keep-api-keys-from-relays.md b/src/content/docs-lite/en/keep-api-keys-from-relays.md index e9e8334..f3eff5d 100644 --- a/src/content/docs-lite/en/keep-api-keys-from-relays.md +++ b/src/content/docs-lite/en/keep-api-keys-from-relays.md @@ -1,35 +1,36 @@ # Keep the API keys in requests away from relays, and block dangerous tool calls -A relay receives every request in full, including keys that end up in the conversation, such as a pasted `.env` file or a configuration file a tool has read. ThinkWatch Lite's outbound redaction finds such credentials before a request leaves the machine and, in **Replace** mode, sends placeholders such as `<>` in their place, restoring the real values where the answer repeats them. Tool-call inspection checks the tool calls that come back and, in **Cut off** mode, stops those that download and run code or send credentials out before the client can run them. +A relay receives every request in full, including keys that end up in the conversation, such as a pasted `.env` file or a configuration file a tool has read. ThinkWatch Lite's **Secrets & privacy** protection finds such credentials before a request leaves the machine and sends placeholders such as `<>` in their place, restoring the real values where the answer repeats them. **Dangerous commands** checks the tool calls that come back and cuts off those that download and run code or send credentials out before the client can run them. ## Before you start -- ThinkWatch Lite, [installed](/lite/#install), with clients connected to the gateway. This guide follows version 2026.10.17. -- Both protections start in **Observe**: they record what they find and change nothing. **Off** checks nothing. +- ThinkWatch Lite, [installed](/lite/#install), with clients connected to the gateway. This guide follows version 2026.10.19. +- Both protections start in **Monitor**: they record what they find, raise a notification and change nothing. **On** handles each match by its rule's action, and **Off** checks nothing. ## Steps -1. Open the Security page. The **Log** tab lists every finding with its request; since both modes use the same rules, a few days in **Observe** show what **Replace** would change. -2. Open **Redaction**. Built-in rules turn on or off one at a time, and **Test…** shows **What is sent** for a pasted text. -3. For a key format the built-in rules do not cover, choose **New rule** and enter a **Name**. Under **Match by**, **Contains** looks for the text exactly as written, so `.` and `*` have no special meaning, and **Regex** takes a regular expression; **Match case**, off by default, tells capital letters from small ones. Enter the text or the pattern and a **Placeholder name** such as `INTERNAL` (giving `<>`), then choose **Create**. -4. Set the mode at the top of the tab to **Replace**. -5. Open **Tool calls**. Each built-in rule is marked **Cut off** or **Record only**, which **View rule** can change. Set the mode to **Cut off**. -6. The log's **Action** column then shows **Replaced** or **Cut off**, and a cut-off call also raises a system notification. From ThinkWatch Lite 2026.10.12, an entry opens in place to show where the value was found and the placeholder it was replaced with, or the tool call that was cut off and the notice the client received. +1. Open the Security page. The **Log** tab lists every match with its request; since both states use the same rules, a few days in **Monitor** show what **On** would change. +2. Open **Secrets & privacy**. Each rule has its own switch and action in the list: **Replace with placeholder** or **Record only**. Built-in rules are grouped by category, and the search box finds a rule by name or pattern. **Test…** shows a pasted text **After processing**. +3. For a key format the built-in rules do not cover, choose **New rule** and enter a **Name**. Under **Match by**, **Contains** looks for the text exactly as written, so `.` and `*` have no special meaning, and **Regex** takes a regular expression; **Match case**, off by default, tells capital letters from small ones. Enter the text or the pattern and a **Placeholder name** such as `INTERNAL` (giving `<>`), keep the action **Replace with placeholder**, then choose **Create**. +4. Set the state at the top of the tab to **On**. +5. Open **Dangerous commands**. Each built-in rule is set to **Cut off** or **Record only**, which can be changed in the list. Set the state to **On**. +6. The log's **Action** column then shows **Replaced** or **Cut off**, and a cut-off call also raises a system notification. An entry opens in place to show where the value was found and the placeholder it was replaced with, or the tool call that was cut off and the notice the client received. ## Notes -| Mode | Outbound redaction | Tool-call inspection | +| State | Secrets & privacy | Dangerous commands | |---|---|---| -| **Observe** (default) | Findings are recorded; the request is sent unchanged. | Matching calls are recorded and returned as usual. | -| **Replace** / **Cut off** | Findings are replaced with placeholders before sending and restored in the response. | Calls matching a **Cut off** rule never fully reach the client; **Record only** rules still only record. | +| **Monitor** (default) | Matches are recorded and notified; the request is sent unchanged. | Matching calls are recorded, notified and returned as usual. | +| **On** | Matches of a **Replace with placeholder** rule are replaced before sending and restored in the answer; **Record only** rules record, notify and send the value unchanged. | Calls matching a **Cut off** rule never fully reach the client; **Record only** rules record, notify and return the call. | -- **What redaction covers.** The whole request, system prompt, earlier turns and tool calls included, except field names and base64 data such as images. Custom rules also leave alone the identifiers a protocol needs as they are: item and call ids, types, roles, tool names and model names; built-in rules still search them. Built-in rules find API keys and tokens for Anthropic, OpenAI, GitHub, Slack, AWS (access key IDs), Google, GitLab, Stripe, npm, DigitalOcean and SendGrid, private keys, JWTs, passwords in connection strings, and Chinese resident ID and bank card numbers whose structure and check digit are valid. The rules for email addresses, Chinese mainland mobile numbers, internal IP addresses and internal domains start off. +- **What Secrets & privacy covers.** The whole request, system prompt, earlier turns and tool calls included, except field names and base64 data such as images. Custom rules also leave alone the identifiers a protocol needs as they are: item and call ids, types, roles, tool names and model names; built-in rules still search them. Built-in rules find API keys and tokens for Anthropic, OpenAI, GitHub, Slack, AWS (access key IDs), Google, GitLab, Stripe, npm, DigitalOcean and SendGrid, private keys, JWTs, passwords in connection strings, and Chinese resident ID and bank card numbers whose structure and check digit are valid. The rules for email addresses, Chinese mainland mobile numbers, internal IP addresses and internal domains start off. - **Rules from before 2026.10.17.** A custom rule saved by an earlier version was a case-sensitive regular expression; it now looks for its text as written and ignores case. A rule that relies on a regular expression still loads but stops matching, with nothing reported, so open each one and choose **Regex**, and **Match case** where capital letters matter. -- **How values come back.** A value keeps one placeholder throughout a request, on every upstream. Placeholders the model writes back, in text or tool-call arguments, are restored before the client receives them: a command using the key runs locally with the real value, while the relay sees only the placeholder. +- **How values come back.** A value keeps one placeholder throughout a request, on every upstream. Placeholders the model writes back, in text, tool-call arguments or Codex's freeform tool input such as `apply_patch`, are restored before the client receives them, exactly as the value was written: a private key keeps its line breaks, and tool-call arguments still parse. A command using the key runs locally with the real value, while the relay sees only the placeholder. - **What is cut off.** Calls that download or decode code and run it, send out environment variables or credential files, read private keys or cloud credentials, send a credential to an unknown host, or install startup items or scheduled jobs. Built-in rules for deleting home or root, world-writable permissions and uploading a local file only record. - **What the relay still sees.** The key configured for its upstream in the app, and the rest of the request as written: code, file contents, the conversation. The key a client uses for the gateway is not forwarded, and neither is the client's identity unless **Forward client identity** is on for that upstream. -- **Rules, not judgement.** Only values that match a rule are replaced; a credential without a recognizable prefix, such as an AWS secret access key, needs a custom rule. A dangerous command written in a form no rule matches passes tool-call inspection. +- **Rules, not judgement.** Only values that match a rule are replaced; a credential without a recognizable prefix, such as an AWS secret access key, needs a custom rule. A dangerous command written in a form no rule matches is not caught. - **Nothing beyond the gateway.** What a relay does on its own servers, such as keeping requests or answering with another model, is out of sight; a mark such as **Model name differs** next to an upstream on the Upstreams page can show signs of the latter, not prove it. -- **The cost of acting.** Changed request content may miss the upstream's prompt cache, and a false match in **Cut off** stops the answer at that call. +- **Notifications.** A notification for a recorded match names the rule and the upstream, never the matched text. The same rule notifies at most once every 5 minutes, and matches that arrive together are merged into one notification. +- **The cost of acting.** Changed request content may miss the upstream's prompt cache, and a false match by a **Cut off** rule stops the answer at that call. -Related: [Features](/docs/lite/features/#security), including the third protection, the content filter; [Install and update](/docs/lite/install/). +Related: [Features](/docs/lite/features/#security), including the third protection, the content filter, which can also delete or replace chosen words in answers; [Install and update](/docs/lite/install/). diff --git a/src/content/docs-lite/en/overview.md b/src/content/docs-lite/en/overview.md index a167413..f8f38d7 100644 --- a/src/content/docs-lite/en/overview.md +++ b/src/content/docs-lite/en/overview.md @@ -7,7 +7,7 @@ ThinkWatch Lite is a local gateway for Claude Code, Codex and other AI clients, ## Highlights - **Connect once, switch freely.** Twelve clients are pointed at the gateway in one step, with the change previewed and the original backed up; Cursor, Continue and Antigravity CLI come with instructions. -- **Protection against relays.** A relay sees every request and can rewrite every answer. Outbound redaction can replace credentials, ID numbers and bank card numbers before a request leaves, and tool-call inspection can cut off an answer that carries a dangerous tool call, such as download-and-run or sending out credential files, before the client runs it. The content filter can delete hidden characters that smuggle instructions into what the client sends, and all three protections start out only recording. +- **Protection against relays.** A relay sees every request and can rewrite every answer. Secrets & privacy can replace credentials, ID numbers and bank card numbers before a request leaves, and Dangerous commands can cut off an answer that carries a dangerous tool call, such as download-and-run or sending out credential files, before the client runs it. The content filter can delete hidden characters that smuggle instructions into what the client sends, and can delete or replace chosen words in requests and answers. All three protections start in Monitor, which records and notifies, and every rule has its own action. - **MCP servers, skills and hooks, scanned.** The MCP servers of thirteen clients side by side, and a scan of client configuration for hidden characters, prompt injection, dangerous commands and overly broad permissions. - **Plugins.** Short JavaScript plugins adjust requests and answers, such as asking for answers in a chosen language or converting file paths between WSL and Windows. They run in a sandbox, see placeholders instead of keys, and every change they make is recorded. - **Every request traceable.** The matched rule, each attempt, any format conversion and the cost, with replay against another upstream; the whole history can be searched, including the text of requests and answers. diff --git a/src/content/docs-lite/en/plugins.md b/src/content/docs-lite/en/plugins.md index 2e04cc1..a69a062 100644 --- a/src/content/docs-lite/en/plugins.md +++ b/src/content/docs-lite/en/plugins.md @@ -26,13 +26,13 @@ A request is routed first, on what the client sent: the routing rules, a rule's 1. Keys in the request are replaced with placeholders. 2. The request hooks in scope for this attempt run in list order, starting from the request as the client sent it. The placeholders are restored after them. 3. If a plugin changed the request, the content filter checks it again, hidden-character rules included, and reports only what the plugins added. A block refuses the whole request; it is not tried on another upstream. -4. The request is converted to the upstream's format if needed, outbound redaction applies, and it is sent. +4. The request is converted to the upstream's format if needed, Secrets & privacy applies, and it is sent. When an attempt fails and the request moves to another upstream, the hooks run again from the request as the client sent it, so changes made for one upstream never reach another. A retry to the same upstream, such as the one after a sign-in token is refreshed, reuses what the hooks produced. A plugin that changes the model renames only what is sent to the upstream of this attempt, like a routing rule's rename, and replaces any name a rule set. The request is not routed again and the upstream's model list is not checked again, but the models the key may use still apply: a model outside them refuses the request. -On the answer side, the hooks run after the answer is converted to the client's format and before the tool-call inspection. +On the answer side, the hooks run after the answer is converted to the client's format. The content filter's rules on answers and Dangerous commands then check what the hooks produced. ## Adding and editing a plugin @@ -238,7 +238,7 @@ A permission decides both what a plugin sees and what it may change. Sections th | `tools` | Tool definitions | Changes which tools the model can use | | `params` | Model, `max_tokens`, `temperature`, `top_p`, `stop`; for embeddings, the model only | Can change the model sent to the upstream, and so what the request costs | | `reply.text` | The text of answers | | -| `reply.tool_calls` | The tool calls in answers: change, remove, add | High risk, shown in red: a plugin can change what the client runs. The tool-call inspection still checks the result, and installing such a plugin, turning it on, changing its code and approving a change to its file are confirmed in a system dialog. | +| `reply.tool_calls` | The tool calls in answers: change, remove, add | High risk, shown in red: a plugin can change what the client runs. Dangerous commands still checks the result, and installing such a plugin, turning it on, changing its code and approving a change to its file are confirmed in a system dialog. | ## When a plugin fails @@ -264,8 +264,8 @@ Across the gateway, at most 32 answer-hook instances run at the same time. Each - **A sandbox with nothing in it.** Plugins run in QuickJS compiled to WebAssembly and executed by Wasmtime inside core. Plugin code never runs in the app's window and never runs as native code. The sandbox has no network, files, environment variables or processes; even a flaw in the JavaScript engine reaches only the sandbox's own memory, not the keys and tokens in core's memory. - **Nothing is kept.** Every request-hook call runs in a new instance. For each answer, a plugin gets one instance, shared by its hooks for that answer and discarded when the answer ends. Plugins share nothing with each other. -- **Placeholders instead of keys.** Keys that the outbound redaction rules recognize are replaced with placeholders before a plugin sees them and restored after it, on the request and on the answer, whatever mode the protection is in. The answer side matters as much as the request: answers become part of the conversation and are sent upstream again with the next request, so a plugin that could see a real key could hide it, encoded, in an answer. -- **The protections still apply.** Request hooks run after routing, and a request they change is checked again by the content filter before outbound redaction; answer hooks run before the tool-call inspection. Whatever a plugin writes is checked like anything else, and plugins cannot change where a request is routed or switch to a model the key may not use. +- **Placeholders instead of keys.** Keys that the Secrets & privacy rules replace with placeholders are replaced before a plugin sees them and restored after it, on the request and on the answer, whatever state the protection is in. The answer side matters as much as the request: answers become part of the conversation and are sent upstream again with the next request, so a plugin that could see a real key could hide it, encoded, in an answer. +- **The protections still apply.** Request hooks run after routing, and a request they change is checked again by the content filter before Secrets & privacy applies; answer hooks run before the content filter's rules on answers and before Dangerous commands. Whatever a plugin writes is checked like anything else, and plugins cannot change where a request is routed or switch to a model the key may not use. - **Approved code only.** A plugin runs only while its file matches the approved SHA-256 hash, and a save in the app updates the file and the hash together. Installing a plugin that may change tool calls, turning it on, changing its code and approving a change to its file are confirmed in a system dialog outside the page, as described in [Confirmation in a system dialog](#confirmation-in-a-system-dialog). - **Every change is visible.** Each run is recorded on the request, a changed request is stored as it was sent to the upstream that answered (with keys replaced, like every stored request), and requests changed by plugins are marked on the Traffic page. - **Bounded.** Every call has limits on CPU time, memory, output and log volume, and the number of answer instances alive at once is capped. Plugins run in a separate thread pool, so a slow plugin does not hold up the gateway's own work. @@ -273,7 +273,7 @@ Across the gateway, at most 32 answer-hook instances run at the same time. Each ## What the sandbox cannot prevent -A plugin is allowed to change content, and the sandbox cannot judge whether a change is honest. A plugin with `system` or `messages` can write instructions into the prompt, and one with `reply.text` can make an answer misleading. A plugin with `params` can switch to a more expensive model among those the key may use. A plugin with `reply.tool_calls` can change what the client runs; the tool-call inspection catches only the patterns in its rules. Keys that the outbound redaction rules do not recognize are visible to plugins; they are also sent to the upstream as they are, and a custom rule on the Security page covers such a format. +A plugin is allowed to change content, and the sandbox cannot judge whether a change is honest. A plugin with `system` or `messages` can write instructions into the prompt, and one with `reply.text` can make an answer misleading. A plugin with `params` can switch to a more expensive model among those the key may use. A plugin with `reply.tool_calls` can change what the client runs; Dangerous commands catches only the patterns in its rules. Keys that the Secrets & privacy rules do not recognize, or that a **Record only** rule finds, are visible to plugins; they are also sent to the upstream as they are, and a custom rule on the Security page covers such a format. These risks are limited by granting a plugin only the permissions it needs, by reading its code before installing it, and by comparing the request before and after the plugins in the request's detail. diff --git a/src/content/docs-lite/zh-CN/compare-cc-switch.md b/src/content/docs-lite/zh-CN/compare-cc-switch.md index 37f01c1..106586b 100644 --- a/src/content/docs-lite/zh-CN/compare-cc-switch.md +++ b/src/content/docs-lite/zh-CN/compare-cc-switch.md @@ -24,7 +24,7 @@ ThinkWatch Lite 在本机运行网关 ThinkWatch Core。在客户端页把每个 | API 格式转换 | 代理模式下:Claude Code 接 OpenAI Chat Completions 或 Responses 的供应商;Codex 接 Chat Completions 或 Anthropic Messages 的供应商 | 在 Anthropic Messages、OpenAI Chat Completions、OpenAI Responses 与 Gemini 之间转换 | | 用量与费用 | 请求数、token、缓存命中率与估算费用,数据来自代理日志或客户端的会话日志;自定义价格,可选从 models.dev 同步价格;显示订阅额度与余额 | 按区间、模型、上游统计 token、费用与请求数;价格取自每天更新的 LiteLLM 价目表或自定义价目表;估算部分单独标出,无法计价的请求单独计数;显示上游报告的余额与额度 | | 请求详情 | 供应商、模型、token、费用、耗时与状态;可查看请求参数、响应摘要与错误信息 | 命中的规则、每一次尝试及其状态、请求与响应正文、费用;可全文搜索;可在另一个上游重放 | -| 出站脱敏与工具调用审查 | — | 请求发出前把 API 密钥、私钥、身份证号与银行卡号替换为占位符;回答中含下载并执行代码、外发凭据等工具调用时切断响应。两项出厂均为「观察」,只记录、不改动 | +| 「密钥与隐私」与「危险命令」 | — | 请求发出前把 API 密钥、私钥、身份证号与银行卡号替换为占位符;回答中含下载并执行代码、外发凭据等工具调用时切断响应。两项出厂均为「监控」,只记录并发出通知、不改动 | | MCP 与技能 | 统一的 MCP 服务器列表,同步到选定的客户端;从 GitHub 仓库或 ZIP 文件安装技能 | 并排列出 13 个客户端的 MCP 服务器,其中 4 个可复制或移除;列出技能与钩子;扫描隐藏字符、提示注入、危险命令与过宽权限 | | 提示词 | 提示词预设写入 `CLAUDE.md`、`AGENTS.md` 或 `GEMINI.md` | — | | 会话 | 读取客户端自己的会话文件;可搜索、在终端中恢复、删除 | 把经过网关的请求归为会话,按轮还原对话 | diff --git a/src/content/docs-lite/zh-CN/features.md b/src/content/docs-lite/zh-CN/features.md index fdcc5aa..e9ce248 100644 --- a/src/content/docs-lite/zh-CN/features.md +++ b/src/content/docs-lite/zh-CN/features.md @@ -16,9 +16,9 @@ ## 流量与会话 -流量页实时列出请求:状态、密钥、模型、上游、首 token 时间与总耗时(悬停时显示生成速度)、token(悬停时显示上传与下载)和费用,并标出格式转换、被脱敏的密钥、被内容过滤删除的文字,以及被拦截或可疑的工具调用。上游、模型和密钥的名称过长时截断显示,悬停可查看全名。列表可以搜索(路径、密钥、上游、模型与错误信息),可以按密钥、上游和模型筛选,或只看失败、无法计价的请求。列表装有最近 2,000 条请求,搜索与筛选同时在全部请求记录中进行,可以继续向更早的记录搜索。打开「搜索内容」后,还会搜索每个请求新发送的内容(最后一轮用户消息,含工具结果)及其回答(含工具调用),范围以报文仍保留的请求为限;命中的片段显示在对应请求的下方。「会话」视图把同一段对话的请求归为若干轮次,给出每一轮的输入 token 与费用。每一轮还标出模型的上下文窗口用了多少:发给模型的 token 相对上下文窗口的比例,其中缓存读取单独成段;打开一轮,可以看到系统提示、工具定义、此前的对话与最后一条用户消息各占多少的估算。会话的「对话」页按轮还原整段对话:每一轮新加入的消息和回答,包括文字、折叠的思考、工具调用及其结果,图片只显示类型和大小。系统提示词的变化和压缩上下文之后的重新开始会标出;报文已过保留期、过大未能完整保存或无法读取的轮次会注明原因。每一轮都可以打开对应的请求。 +流量页实时列出请求:状态、密钥、模型、上游、首 token 时间与总耗时(悬停时显示生成速度)、token(悬停时显示上传与下载)和费用,并标出格式转换、被脱敏的密钥、被内容过滤删除或替换的文字,以及被拦截或可疑的工具调用。上游、模型和密钥的名称过长时截断显示,悬停可查看全名。列表可以搜索(路径、密钥、上游、模型与错误信息),可以按密钥、上游和模型筛选,或只看失败、无法计价的请求。列表装有最近 2,000 条请求,搜索与筛选同时在全部请求记录中进行,可以继续向更早的记录搜索。打开「搜索内容」后,还会搜索每个请求新发送的内容(最后一轮用户消息,含工具结果)及其回答(含工具调用),范围以报文仍保留的请求为限;命中的片段显示在对应请求的下方。「会话」视图把同一段对话的请求归为若干轮次,给出每一轮的输入 token 与费用。每一轮还标出模型的上下文窗口用了多少:发给模型的 token 相对上下文窗口的比例,其中缓存读取单独成段;打开一轮,可以看到系统提示、工具定义、此前的对话与最后一条用户消息各占多少的估算。会话的「对话」页按轮还原整段对话:每一轮新加入的消息和回答,包括文字、折叠的思考、工具调用及其结果,图片只显示类型和大小。系统提示词的变化和压缩上下文之后的重新开始会标出;报文已过保留期、过大未能完整保存或无法读取的轮次会注明原因。每一轮都可以打开对应的请求。 -打开一个请求可以查看时间线、路由(命中的规则、经过的策略组,以及每一次尝试的状态与耗时)、内容、用量与费用。时间线给出请求经由的代理(「出口」,未经代理时为「直连」),以及请求发往上游与从上游收到的数据量(「上传」与「下载」),按网络上实际传输的大小计算:在网关自身的压缩之后、解码之前,故障转移的各次尝试合计在内。DeepSeek Harness 发出的请求还会显示所带会话日志的大小:这是客户端随每个请求附带的整段对话记录,发往 DeepSeek 以外的上游之前由网关去除。已结束的请求可以在预估费用后原样发送到另一个上游,两次的响应并排对照。 +打开一个请求可以查看时间线、路由(命中的规则、经过的策略组,以及每一次尝试的状态与耗时)、内容、用量与费用。时间线给出请求经由的代理(「出口」,未经代理时为「直连」),以及请求发往上游与从上游收到的数据量(「上传」与「下载」),按网络上实际传输的大小计算:在网关自身的压缩之后、解码之前,故障转移的各次尝试合计在内。DeepSeek Harness 发出的请求还会显示所带会话日志的大小:这是客户端随每个请求附带的整段对话记录,发往 DeepSeek 以外的上游之前由网关去除。已结束的请求可以在预估费用后原样发送到另一个上游,两次的响应并排对照。网关自身的代码在请求过程中出错时,请求的错误信息写明出错的内容与位置。 「内容」标签页有「解析」与「原始报文」两种视图,请求进行中时两者都实时更新。「解析」以对话的形式显示,回答随流式输出逐步出现,思考与工具调用的参数同样实时显示。「原始报文」显示请求行与状态行、报文头和正文,流式返回的每个事件到达后依次追加;「跟随最新」使最新的内容保持在视野内。「原始报文」中的「客户端一侧」与「上游一侧」分别显示客户端和上游与网关之间收发的内容,转换 API 格式或插件改写请求时两者不同。两种视图中的密钥与存下的请求一样已被替换。安全规则命中之处在两种视图中都以安全日志的颜色标出,折叠的部分中含有命中时,折叠处带有一个圆点。 @@ -45,7 +45,7 @@ WSL 2 默认使用 NAT 网络,此时 Windows 上的网关无法从 WSL 内访 ## 上游 -上游是网关转发请求的目标:Anthropic、OpenAI、Google Gemini、DeepSeek 或任何兼容接口的 API 密钥,Amazon Bedrock(API 密钥、访问密钥或 AWS profile),在应用内登录的 ChatGPT 账号或 Z.ai / BigModel 账号,OpenRouter、Sub2API、New API / One API 等中转服务,ThinkWatch 企业版网关,以及 Ollama 等本机模型。客户端与上游的 API 格式不同时,请求在 Anthropic Messages、OpenAI Chat Completions、OpenAI Responses 与 Gemini 之间自动转换,无法转换的字段会在请求上逐一列出。模型的思考在转换中保留:DeepSeek、Kimi、GLM 等 Chat Completions 格式上游返回的思考内容原样交给客户端,下一轮送回同一上游,带工具调用的对话因此能继续;Gemini 模型工具调用上的思考签名同样保留。Chat Completions 格式的模型把工具调用写进回答正文时,只要请求定义了这个工具,网关就把它识别为普通的工具调用,并与其他工具调用一样经过工具调用审查。客户端以 gzip、deflate 或 zstd 压缩发送的请求正文照常读取,上游压缩返回的回答解码后交给客户端。Codex 等不标注提示缓存断点的客户端,请求转换后发往 Anthropic Messages 格式的上游,或 Bedrock 上 AWS 列为支持提示缓存的 Claude 模型(Claude 3.5 Sonnet v2、Claude 3.7 Sonnet 以及 Claude 4.5 起的模型)时,由网关标注断点,每一轮都能读取上一轮写入的缓存。上游拒绝这些标注时,网关去掉标注重新发送一次。上游可以经出站代理访问,也可以使用单独的价目表计价,别名、代理与价目表在同一页的标签中管理。「代理」标签页的「流量 · 24 小时」一列给出经过每个代理的上传与下载,悬停可查看 7 天与 30 天的数据。可选的「并发上限」适用于限制并发的中转站或账号:上游已满时,留在它上面的对话等待空位,其他请求交给下一个上游;所有上游都满时,请求先等待,仍无空位则返回繁忙错误。流式请求等待空位或密钥的用量窗口期间,客户端会收到保活心跳。在上游的模型列表中选择「规格…」,可以手动设置模型的上下文窗口、输出上限,以及是否支持推理与图片输入,适用于价目表中没有或数值有误的模型,手动设置的值优先于价目表。链路测速测量 DNS 解析以及 TCP、TLS、代理握手的耗时,不产生费用;推理测速测量首个 token 的时间,运行前先给出费用预估。 +上游是网关转发请求的目标:Anthropic、OpenAI、Google Gemini、DeepSeek 或任何兼容接口的 API 密钥,Amazon Bedrock(API 密钥、访问密钥或 AWS profile),在应用内登录的 ChatGPT 账号或 Z.ai / BigModel 账号,OpenRouter、Sub2API、New API / One API 等中转服务,ThinkWatch 企业版网关,以及 Ollama 等本机模型。客户端与上游的 API 格式不同时,请求在 Anthropic Messages、OpenAI Chat Completions、OpenAI Responses 与 Gemini 之间自动转换,无法转换的字段会在请求上逐一列出。模型的思考在转换中保留:DeepSeek、Kimi、GLM 等 Chat Completions 格式上游返回的思考内容原样交给客户端,下一轮送回同一上游,带工具调用的对话因此能继续;Gemini 模型工具调用上的思考签名同样保留。Chat Completions 格式的模型把工具调用写进回答正文时,只要请求定义了这个工具,网关就把它识别为普通的工具调用,并与其他工具调用一样经过「危险命令」检查。客户端以 gzip、deflate 或 zstd 压缩发送的请求正文照常读取,上游压缩返回的回答解码后交给客户端。Codex 等不标注提示缓存断点的客户端,请求转换后发往 Anthropic Messages 格式的上游,或 Bedrock 上 AWS 列为支持提示缓存的 Claude 模型(Claude 3.5 Sonnet v2、Claude 3.7 Sonnet 以及 Claude 4.5 起的模型)时,由网关标注断点,每一轮都能读取上一轮写入的缓存。上游拒绝这些标注时,网关去掉标注重新发送一次。上游可以经出站代理访问,也可以使用单独的价目表计价,别名、代理与价目表在同一页的标签中管理。「代理」标签页的「流量 · 24 小时」一列给出经过每个代理的上传与下载,悬停可查看 7 天与 30 天的数据。可选的「并发上限」适用于限制并发的中转站或账号:上游已满时,留在它上面的对话等待空位,其他请求交给下一个上游;所有上游都满时,请求先等待,仍无空位则返回繁忙错误。流式请求等待空位或密钥的用量窗口期间,客户端会收到保活心跳。在上游的模型列表中选择「规格…」,可以手动设置模型的上下文窗口、输出上限,以及是否支持推理与图片输入,适用于价目表中没有或数值有误的模型,手动设置的值优先于价目表。链路测速测量 DNS 解析以及 TCP、TLS、代理握手的耗时,不产生费用;推理测速测量首个 token 的时间,运行前先给出费用预估。 「新建上游」先选择服务。服务分为「模型厂商」(Anthropic、OpenAI、Google Gemini、DeepSeek、Z.ai / BigModel)、「平台与中转」(Amazon Bedrock、OpenRouter、ThinkWatch、Sub2API、New API / One API)与「本机与自定义」(Ollama、自定义)三组,各带标志和一句介绍,可以搜索。选定后直接进入「连接」,只询问该服务需要的内容。「认证方式」按服务给出:OpenAI 为 API 密钥或 ChatGPT 账号,Z.ai / BigModel 为 API 密钥或账号登录,Bedrock 为 API 密钥、访问密钥或 AWS profile,自定义为 API 密钥或 OAuth,ThinkWatch、Sub2API 与 New API / One API 为 API 密钥;只有一种方式的服务不显示这一项。服务已经决定的内容,例如地址、接口协议,或 Ollama 不需要密钥,直接填好或不再显示。请求头、转发客户端身份、代理不可用时的处理与并发上限收在「高级设置」中,其中任何一项有设置时自动展开。点击「下一步」即检测连接,不产生费用:通过后进入「模型」,顶部显示响应时间、发现的模型数和余额(如有);没有通过时写明原因,可以「重试」,也可以「仍然继续」,适用于拒绝检测但能正常转发的上游。ChatGPT 与 Z.ai / BigModel 账号在对话框内登录,阅读说明后,可以在默认浏览器中登录,也可以「复制链接」到常用的浏览器中打开;ChatGPT 账号还可以用设备码登录。登录后上游即写入配置,对话框直接进入「模型」,顶部显示登录的账号。连接远程 core 时,ChatGPT 账号只能用设备码登录,验证网址和设备码都可以复制。 @@ -73,17 +73,21 @@ API 密钥和请求头的值可以写成 `${变量名}`,读取系统环境变 ## 安全 -安全页有三项防护:出站脱敏、工具调用审查和内容过滤,对所有上游和所有密钥统一生效。每项都有三档:「关闭」「观察」,以及按作用命名的第三档,出站脱敏为「替换」,工具调用审查为「切断」,内容过滤为「处置」;其中「观察」只检测和记录,不做任何改动。三项出厂均为「观察」,因此默认不会改动或拒绝任何请求。 +安全页包括「日志」标签页,以及三项防护各自的标签页:「密钥与隐私」「危险命令」「内容过滤」。三项防护对所有上游和所有密钥统一生效。每项防护处于「开启」「监控」「关闭」三种状态之一,状态以圆点标在标签上。「开启」时,命中内容按命中规则的动作处理;「监控」时,命中内容记入日志并发出通知,不做任何改动;「关闭」时不检查。三项出厂均为「监控」,因此默认不会改动或拒绝任何请求和回答。 -- **出站脱敏**:请求发出之前查找整个请求(含系统提示、之前的对话和工具调用)中的凭据和个人信息,包括 Anthropic、OpenAI、GitHub、Slack、AWS、Google、GitLab、Stripe、npm、DigitalOcean、SendGrid 的 API 密钥与令牌,以及私钥、JWT 和连接串中的口令,还有身份证号与银行卡号(号码结构与校验位都正确才算)。字段名不在查找之列;自定义规则还会跳过协议要求原样保留的标识,如条目与调用的 id、类型、角色、工具名和模型名,因此规则不会改坏客户端回传的 id。「替换」档下把它们替换为 `<>` 这样的占位符,响应中回显时再还原。邮箱地址、中国大陆手机号、内网 IP 地址和内网域名四条规则出厂为停用,可以按需启用;自定义规则可以指定占位符名称,如 `PROJECT` 替换为 `<>`。 -- **工具调用审查**:检查模型返回的工具调用中是否含有下载或解码后执行代码、外发环境变量或凭据文件、把凭据发往本机和其服务商以外的主机、读取私钥或云服务凭据、读写 ThinkWatch 自己的数据目录、写入启动项或定时任务等命令。只出现在要写入的文字里的路径(例如提到这个目录的文档)不算。「切断」档下命中即切断响应,客户端收不到一个完整、可执行的调用。删除主目录或根目录、设置全员可写权限、把本地文件上传到外部主机三条规则出厂只记录。 -- **内容过滤**:检查每个请求中的用户消息和工具结果,压缩上下文的请求也在其内。规则按关键词、正则表达式或码位(如 `U+E0000–U+E007F`)匹配,「处置」档下按规则拒绝请求、删除命中的文字后发出,或仅记录。内置规则删除 Unicode 标签字符和双向控制符(人看不见、模型读得到,可用于隐藏指令),拒绝明确要求「忽略先前指令」的请求。零宽字符、私用区字符两条规则(表情符号、波斯文和图标字体也会用到这些字符),以及越狱、身份操纵、套取提示词等规则及其中文版本出厂为停用,可以按需启用。 +- **密钥与隐私**:请求发出之前查找整个请求(含系统提示、之前的对话和工具调用)中的凭据和个人信息,包括 Anthropic、OpenAI、GitHub、Slack、AWS、Google、GitLab、Stripe、npm、DigitalOcean、SendGrid 的 API 密钥与令牌,以及私钥、JWT 和连接串中的口令,还有身份证号与银行卡号(号码结构与校验位都正确才算)。字段名不在查找之列;自定义规则还会跳过协议要求原样保留的标识,如条目与调用的 id、类型、角色、工具名和模型名,因此规则不会改坏客户端回传的 id。每条规则把命中的内容替换为 `<>` 这样的占位符,或只作记录、原样发出。回答中出现的占位符按原值的写法如实还原:私钥保留换行,工具调用参数和 Codex `apply_patch` 等自由格式工具输入中的值还原后仍可正常使用。邮箱地址、中国大陆手机号、内网 IP 地址和内网域名四条规则出厂为停用,可以按需启用;自定义规则可以指定占位符名称,如 `PROJECT` 替换为 `<>`。 +- **危险命令**:检查模型返回的工具调用中是否含有下载或解码后执行代码、外发环境变量或凭据文件、把凭据发往本机和其服务商以外的主机、读取私钥或云服务凭据、读写 ThinkWatch 自己的数据目录、写入启动项或定时任务等命令。只出现在要写入的文字里的路径(例如提到这个目录的文档)不算。每条规则切断回答,使客户端收不到一个完整、可执行的调用,或只作记录。删除主目录或根目录、设置全员可写权限、把本地文件上传到外部主机三条规则出厂只记录。 +- **内容过滤**:检查请求,并可按规则检查模型的回答。在请求中,检查用户消息和工具结果,压缩上下文的请求也在其内。在回答中,检查模型输出的正文,包括 Codex 的自由格式工具输入;工具调用由「危险命令」负责,思考过程不检查。规则按关键词、正则表达式或码位(如 `U+E0000–U+E007F`)匹配,命中时拒绝请求、删除命中内容(不留任何标记)、替换为规则指定的替换文本(默认 `***`),或只作记录。替换后的文字在回答中不还原。回答照常流式输出,只暂缓末尾可能构成命中的少量字符。有检查回答的规则可以删除或替换时,流式回答中不再附带 token 概率(logprobs)。内置规则只检查请求:删除 Unicode 标签字符和双向控制符(人看不见、模型读得到,可用于隐藏指令),拒绝明确要求「忽略先前指令」的请求。零宽字符、私用区字符两条规则(表情符号、波斯文和图标字体也会用到这些字符),以及越狱、身份操纵、套取提示词等规则及其中文版本出厂为停用,可以按需启用。 -安全页列出全部规则,内置规则按类别分组。内置规则可以逐条启用或停用;工具调用审查的内置规则可以设为切断或仅记录,内容过滤的内置规则可以设为拒绝、删除或仅记录。出站脱敏的自定义规则按原样查找文字(「包含」,默认)或按正则表达式匹配(「正则」),默认不区分大小写,打开「区分大小写」后区分;内容过滤的自定义规则使用关键词、正则表达式或码位,工具调用审查的自定义规则为正则表达式。任何规则都可以先用一段文本测试,出站脱敏和内容过滤的测试还会显示发出时的文本。各项防护检出的内容都记入第一个标签页的日志,并注明所属的请求;隐藏字符拼出文字时,日志中一并显示这段文字。 +每条规则都有自己的开关和动作,直接在列表中设置:「密钥与隐私」的规则可选「替换为占位符」或「仅记录」;「危险命令」的规则可选「切断」或「仅记录」;「内容过滤」的规则可选「拒绝」「删除」「替换」或「仅记录」。防护处于「监控」时,各条规则的动作旁注明「监控中」。内置规则按类别分组,每组带一个复选框,可一次启用或停用组内全部规则;检索框按名称和匹配内容筛选规则。 -日志中的记录可以在原处展开。展开后列出规则命中的每一处,最多 50 处,其余注明处数:所在的部分(系统提示、第几条消息及其角色、工具调用或工具结果及工具名称、回答正文)、JSON 路径,以及前后各最多 80 个字符的上下文,其中的凭据以掩码显示。展开的内容给出命中时的规则:自定义规则的写法与匹配方式,或内置规则的名称及作出判定的 core 版本,因此规则修改或删除之后,记录仍然可读。展开的内容还写明具体的处置:凭据替换成的占位符,被切断的工具调用及客户端收到的提示,请求被拒绝时客户端收到的回复,或删除了几处命中的内容。所属的会话,以及与客户端请求的模型不同时实际发往上游的模型,也一并列出。请求时间线中的防护记录以同样的方式展开。「导出」把所选区间内的全部记录保存为 JSON(完整细节)或 CSV(每条一行)。日志的保留期限与请求记录相同,防护设置的改动不记入日志。 +「密钥与隐私」的自定义规则按原样查找文字(「包含」,默认)或按正则表达式匹配(「正则」),默认不区分大小写,打开「区分大小写」后区分。内容过滤的自定义规则须选定「检查对象」:「请求」「回答」或「请求和回答」;按关键词、正则表达式或码位匹配,默认不区分大小写,打开「区分大小写」后区分。检查回答的规则不能拒绝,也不能按码位匹配,对话框中这两项不可选,并注明原因。「危险命令」的自定义规则为正则表达式。任何规则都可以先用一段文本测试,「密钥与隐私」和内容过滤的测试还会显示处理后的文本;内容过滤的测试可按请求或按回答进行。 -各项防护作用于经过网关的请求和回答,不作用于磁盘上的文件。配置文件以明文保存密钥,只有所有者可读:挡得住其他用户,挡不住以同一用户身份运行的程序;出站脱敏保护的是带出本机的内容,不是这份文件。 +规则的动作为「仅记录」,或防护处于「监控」时,命中内容记入日志并发出系统通知。通知只写规则名称和上游,不含命中的原文;同一条规则 5 分钟内至多通知一次,同时到达的多处命中合并为一条通知。各项防护检出的内容都记入第一个标签页的日志,并注明所属的请求;隐藏字符拼出文字时,日志中一并显示这段文字。 + +日志中的记录可以在原处展开。展开后列出规则命中的每一处,最多 50 处,其余注明处数:所在的部分(系统提示、第几条消息及其角色、工具调用或工具结果及工具名称、回答正文)、JSON 路径,以及前后各最多 80 个字符的上下文,其中的凭据以掩码显示。展开的内容给出命中时的规则:自定义规则的写法与匹配方式,或内置规则的名称及作出判定的 core 版本,因此规则修改或删除之后,记录仍然可读。展开的内容还写明具体的处置:凭据替换成的占位符,被切断的工具调用及客户端收到的提示,请求被拒绝时客户端收到的回复,或删除、替换了几处命中的内容及替换成的文字。所属的会话,以及与客户端请求的模型不同时实际发往上游的模型,也一并列出。请求时间线中的防护记录以同样的方式展开。「导出」把所选区间内的全部记录保存为 JSON(完整细节)或 CSV(每条一行)。日志的保留期限与请求记录相同,防护设置的改动不记入日志。 + +各项防护作用于经过网关的请求和回答,不作用于磁盘上的文件。配置文件以明文保存密钥,只有所有者可读:挡得住其他用户,挡不住以同一用户身份运行的程序;「密钥与隐私」保护的是带出本机的内容,不是这份文件。 ## MCP @@ -115,4 +119,4 @@ Windows 上图标位于通知区域:悬停显示网关状态与今日 token、 Linux 上图标位于系统托盘:点击打开同一份菜单,「今日」一栏与额度条同样改为文字;第一项「打开主界面」用于打开主窗口。 -以下情况会发送系统通知(macOS 与 Windows 使用原生通知,Linux 通过桌面环境的通知服务):网关停止转发或反复重启、与远程 core 的连接断开、订阅额度用完、账号登录失效或上游拒绝当前凭据、代理不通、配置文件未通过校验、工具调用命中切断类规则、密钥的每日、每周或每月用量接近或达到上限、客户端配置中出现可疑内容。自动检查到新版本时,也会以灰色列入提醒,并同样以系统通知告知(见[更新](/zh-CN/docs/lite/install#更新))。上游无法连接时通常由回退上游承接,因此只记录在应用内。提醒可以整体设为系统通知、仅在应用内显示或关闭。标为已读的提醒不再计入铃铛上的数字,但在问题解决或清空列表之前仍留在列表中。 +以下情况会发送系统通知(macOS 与 Windows 使用原生通知,Linux 通过桌面环境的通知服务):网关停止转发或反复重启、与远程 core 的连接断开、订阅额度用完、账号登录失效或上游拒绝当前凭据、代理不通、配置文件未通过校验、工具调用被切断、安全规则记录了一处命中(见[安全](#安全))、密钥的每日、每周或每月用量接近或达到上限、客户端配置中出现可疑内容。自动检查到新版本时,也会以灰色列入提醒,并同样以系统通知告知(见[更新](/zh-CN/docs/lite/install#更新))。上游无法连接时通常由回退上游承接,因此只记录在应用内。提醒可以整体设为系统通知、仅在应用内显示或关闭。标为已读的提醒不再计入铃铛上的数字,但在问题解决或清空列表之前仍留在列表中。 diff --git a/src/content/docs-lite/zh-CN/keep-api-keys-from-relays.md b/src/content/docs-lite/zh-CN/keep-api-keys-from-relays.md index 6092072..53f7860 100644 --- a/src/content/docs-lite/zh-CN/keep-api-keys-from-relays.md +++ b/src/content/docs-lite/zh-CN/keep-api-keys-from-relays.md @@ -1,35 +1,36 @@ # 防止中转站拿到请求中的 API 密钥,并拦截危险的工具调用 -中转站能看到请求的全部内容,包括混进对话中的密钥,例如粘贴进来的 `.env` 文件、工具读取的配置文件。ThinkWatch Lite 的出站脱敏在请求离开本机之前查找这些凭据,在「替换」档下改为发送 `<>` 这样的占位符,回答中出现占位符时再还原为原值。工具调用审查检查上游返回的工具调用,在「切断」档下,下载即执行、外发凭据之类的调用在客户端执行之前即被拦下。 +中转站能看到请求的全部内容,包括混进对话中的密钥,例如粘贴进来的 `.env` 文件、工具读取的配置文件。ThinkWatch Lite 的「密钥与隐私」在请求离开本机之前查找这些凭据,改为发送 `<>` 这样的占位符,回答中出现占位符时再还原为原值。「危险命令」检查上游返回的工具调用,下载即执行、外发凭据之类的调用在客户端执行之前即被切断。 ## 准备 -- 已[安装](/zh-CN/lite/#install) ThinkWatch Lite,并已接管客户端,请求经过网关。本文按 2026.10.17 版编写。 -- 两项防护出厂均为「观察」:只记录检出的内容,不做任何改动。「关闭」档不检查也不记录。 +- 已[安装](/zh-CN/lite/#install) ThinkWatch Lite,并已接管客户端,请求经过网关。本文按 2026.10.19 版编写。 +- 两项防护出厂均为「监控」:只记录检出的内容并发出通知,不做任何改动。「开启」时按每条规则的动作处理,「关闭」时不检查也不记录。 ## 步骤 -1. 打开安全页。「日志」标签列出各项防护检出的内容及其所属的请求;两档使用同一套规则,因此先在「观察」档下运行几天,即可看出切换到「替换」后会改动哪些内容。 -2. 打开「出站脱敏」标签。内置规则可以逐条启用或停用,「测试…」对粘贴的文本显示「发出的内容」。 -3. 内置规则未覆盖的密钥格式,选择「新建规则」,填写「名称」。「匹配方式」中,「包含」按原样查找文字,`.`、`*` 等字符没有特殊含义;「正则」按正则表达式匹配。「区分大小写」默认关闭。填写要查找的文字或正则表达式,以及「占位符名称」(例如 `INTERNAL`,替换为 `<>`),然后选择「创建」。 -4. 把标签顶部的档位切换到「替换」。 -5. 打开「工具调用审查」标签。每条内置规则的处置为「切断」或「仅记录」,可以在「查看规则」中修改。把档位切换到「切断」。 -6. 此后日志的「处置」一栏显示「已替换」或「已切断」;调用被切断时还会发送系统通知。自 ThinkWatch Lite 2026.10.12 起,记录可以在原处展开,显示命中的位置与替换成的占位符,或被切断的工具调用及客户端收到的提示。 +1. 打开安全页。「日志」标签列出各项防护检出的内容及其所属的请求;两种状态使用同一套规则,因此先在「监控」状态下运行几天,即可看出切换到「开启」后会改动哪些内容。 +2. 打开「密钥与隐私」标签。每条规则的开关和动作(「替换为占位符」或「仅记录」)都在列表中直接设置;内置规则按类别分组,检索框按名称或匹配内容查找规则。「测试…」对粘贴的文本显示「处理后」的结果。 +3. 内置规则未覆盖的密钥格式,选择「新建规则」,填写「名称」。「匹配方式」中,「包含」按原样查找文字,`.`、`*` 等字符没有特殊含义;「正则」按正则表达式匹配。「区分大小写」默认关闭。填写要查找的文字或正则表达式,以及「占位符名称」(例如 `INTERNAL`,替换为 `<>`),动作保持「替换为占位符」,然后选择「创建」。 +4. 把标签顶部的状态切换到「开启」。 +5. 打开「危险命令」标签。每条内置规则的动作为「切断」或「仅记录」,可以在列表中修改。把状态切换到「开启」。 +6. 此后日志的「处置」一栏显示「已替换」或「已切断」;调用被切断时还会发送系统通知。记录可以在原处展开,显示命中的位置与替换成的占位符,或被切断的工具调用及客户端收到的提示。 ## 说明 -| 档位 | 出站脱敏 | 工具调用审查 | +| 状态 | 密钥与隐私 | 危险命令 | |---|---|---| -| 「观察」(出厂) | 检出的内容记入日志,请求原样发出。 | 命中的调用记入日志,照常返回。 | -| 「替换」/「切断」 | 检出的内容替换为占位符后发出,响应中的占位符还原为原值。 | 命中「切断」规则的调用不会完整到达客户端;「仅记录」规则仍只记录。 | +| 「监控」(出厂) | 检出的内容记入日志并发出通知,请求原样发出。 | 命中的调用记入日志并发出通知,照常返回。 | +| 「开启」 | 「替换为占位符」规则检出的内容替换为占位符后发出,回答中的占位符还原为原值;「仅记录」规则只记录并通知,原样发出。 | 命中「切断」规则的调用不会完整到达客户端;「仅记录」规则只记录并通知,照常返回。 | -- **出站脱敏的范围。**查找整个请求,包括系统提示、之前的对话和工具调用,但不查找字段名和图片等 base64 数据。自定义规则还会跳过协议要求原样保留的标识:条目与调用的 id、类型、角色、工具名和模型名;内置规则照常查找这些值。内置规则覆盖 Anthropic、OpenAI、GitHub、Slack、AWS(访问密钥 ID)、Google、GitLab、Stripe、npm、DigitalOcean、SendGrid 的 API 密钥与令牌,私钥、JWT、连接串中的口令,以及号码结构与校验位都正确的身份证号和银行卡号。邮箱地址、中国大陆手机号、内网地址、内部域名四条规则出厂为停用。 +- **「密钥与隐私」的范围。**查找整个请求,包括系统提示、之前的对话和工具调用,但不查找字段名和图片等 base64 数据。自定义规则还会跳过协议要求原样保留的标识:条目与调用的 id、类型、角色、工具名和模型名;内置规则照常查找这些值。内置规则覆盖 Anthropic、OpenAI、GitHub、Slack、AWS(访问密钥 ID)、Google、GitLab、Stripe、npm、DigitalOcean、SendGrid 的 API 密钥与令牌,私钥、JWT、连接串中的口令,以及号码结构与校验位都正确的身份证号和银行卡号。邮箱地址、中国大陆手机号、内网地址、内部域名四条规则出厂为停用。 - **2026.10.17 之前保存的规则。**此前版本保存的自定义规则按区分大小写的正则表达式匹配,现在改为按原样查找文字、不区分大小写。依赖正则表达式的规则仍可加载,但不再命中,也没有任何提示;应逐条打开,选择「正则」,需要区分大小写的再打开「区分大小写」。 -- **原值如何还原。**同一个值在整个请求中只对应一个占位符,无论发往哪个上游都不变。模型在文字或工具调用参数中写回的占位符,在交给客户端之前还原:用到这把密钥的命令在本机以原值执行,中转站始终只看到占位符。 +- **原值如何还原。**同一个值在整个请求中只对应一个占位符,无论发往哪个上游都不变。模型在文字、工具调用参数或 Codex `apply_patch` 等自由格式工具输入中写回的占位符,在交给客户端之前按原值的写法如实还原:私钥保留换行,工具调用参数仍可正常解析。用到这把密钥的命令在本机以原值执行,中转站始终只看到占位符。 - **哪些调用会被切断。**下载或解码后执行代码、外发环境变量或凭据文件、读取私钥或云凭据、把凭据发往陌生主机、写入启动项或安装定时任务的调用。删除主目录或根目录、开放全部写权限、上传本地文件三类内置规则出厂只记录。 - **中转站仍能看到的内容。**应用中为该上游配置的密钥,以及请求的其余内容,例如代码、文件内容和对话,均按原样发给中转站。客户端连接网关所用的密钥不会转发;客户端的身份信息也不转发,除非在该上游上打开「转发客户端身份」。 -- **只按规则匹配。**只有命中规则的值才会被替换;没有固定前缀的凭据(例如 AWS 私有访问密钥)需要自定义规则。写法不在任何规则之内的危险命令,工具调用审查拦不住。 +- **只按规则匹配。**只有命中规则的值才会被替换;没有固定前缀的凭据(例如 AWS 私有访问密钥)需要自定义规则。写法不在任何规则之内的危险命令拦不住。 - **看不到网关之外。**中转站在自己的服务器上做了什么,例如留存请求、换用其他模型作答,各项防护无从得知。上游页在上游名称旁标出的「模型名不符」等偏差可以显示后者的迹象,但不能证明。 -- **动手的代价。**请求内容改变后,上游的提示缓存可能无法命中;「切断」档下误判时,回答会在该调用处中断。 +- **通知。**记录命中时发出的通知只写规则名称和上游,不含命中的原文;同一条规则 5 分钟内至多通知一次,同时到达的多处命中合并为一条通知。 +- **动手的代价。**请求内容改变后,上游的提示缓存可能无法命中;「切断」规则误判时,回答会在该调用处中断。 -相关文档:[功能详解](/zh-CN/docs/lite/features/#安全)(含第三项防护内容过滤)、[安装与更新](/zh-CN/docs/lite/install/)。 +相关文档:[功能详解](/zh-CN/docs/lite/features/#安全)(含第三项防护「内容过滤」,可删除或替换回答中的指定词语)、[安装与更新](/zh-CN/docs/lite/install/)。 diff --git a/src/content/docs-lite/zh-CN/overview.md b/src/content/docs-lite/zh-CN/overview.md index 5aec106..e3f780f 100644 --- a/src/content/docs-lite/zh-CN/overview.md +++ b/src/content/docs-lite/zh-CN/overview.md @@ -7,7 +7,7 @@ ThinkWatch Lite 是 Claude Code、Codex 等 AI 客户端的本地网关,支持 ## 要点 - **一次接入,随时切换。** 十二款客户端可一键指向网关,写入前预览改动并备份原文件;Cursor、Continue 与 Antigravity CLI 提供配置说明。 -- **防范中转站。** 中转站能看到每个请求,也能改写每一次回答。出站脱敏可在请求发出前替换其中的凭据、身份证号与银行卡号;回答中出现下载即执行、外发凭据文件之类的危险工具调用时,工具调用审查可在客户端执行前切断回答。内容过滤可删除客户端发送内容中夹带指令的隐藏字符;三项防护出厂均只记录。 +- **防范中转站。** 中转站能看到每个请求,也能改写每一次回答。「密钥与隐私」可在请求发出前替换其中的凭据、身份证号与银行卡号;回答中出现下载即执行、外发凭据文件之类的危险工具调用时,「危险命令」可在客户端执行前切断回答。「内容过滤」可删除客户端发送内容中夹带指令的隐藏字符,也可删除或替换请求和回答中的指定词语。三项防护出厂均为「监控」,只记录并发出通知;每条规则可单独设定动作。 - **扫描 MCP、技能与钩子。** 十三款客户端的 MCP 服务器并列显示,并扫描客户端配置中的隐藏字符、提示注入、危险命令与过宽权限。 - **插件。** 用简短的 JavaScript 插件调整请求与回答,例如要求用指定的语言回答、在 WSL 与 Windows 之间转换路径。插件在沙箱中运行,只看到占位符而看不到密钥,每一处改动都有记录。 - **每个请求都可追溯。** 命中的规则、每一次尝试、格式转换与费用都有记录,也可以重放到另一个上游对比;全部请求记录都可以搜索,包括请求与回答的内容。 diff --git a/src/content/docs-lite/zh-CN/plugins.md b/src/content/docs-lite/zh-CN/plugins.md index 1337f19..3009fce 100644 --- a/src/content/docs-lite/zh-CN/plugins.md +++ b/src/content/docs-lite/zh-CN/plugins.md @@ -26,13 +26,13 @@ core 按客户端自己的格式写回改动,只动改过的条目,缓存标 1. 把请求里的密钥替换为占位符; 2. 从客户端发来的原始请求开始,按列表顺序运行适用范围覆盖这一次发送的请求钩子,运行之后换回占位符; 3. 插件改动了请求时,内容过滤(包括隐藏字符规则)再检查一遍,只报告插件加入的内容;拦截时整个请求被拒绝,不会转到别的上游; -4. 需要时转换为上游的格式,经过出站脱敏后发出。 +4. 需要时转换为上游的格式,经过「密钥与隐私」处理后发出。 一次发送失败、请求转到另一个上游时,请求钩子从客户端的原始请求重新运行,为一个上游做的改动不会带到另一个上游。向同一个上游重发(例如登录令牌刷新后的重试)时,沿用请求钩子已有的结果。 插件修改模型时,只改变这一次发往上游的模型名,效果与路由规则改名相同,并取代规则改过的名字。请求不会重新路由,也不再核对上游的模型列表,但密钥的可用模型依然有效:改成密钥不可用的模型时,请求被拒绝。 -回答一侧,回答钩子在回答转换为客户端的格式之后、工具调用审查之前运行。 +回答一侧,回答钩子在回答转换为客户端的格式之后运行,其结果再由内容过滤中检查回答的规则和「危险命令」检查。 ## 添加与编辑插件 @@ -238,7 +238,7 @@ type Ctx = { | `tools` | 工具定义 | 会改变模型能使用的工具 | | `params` | 模型、`max_tokens`、`temperature`、`top_p`、`stop`;嵌入只有模型 | 可能改变发往上游的模型,以及因此产生的费用 | | `reply.text` | 回答中的文字 | | -| `reply.tool_calls` | 回答中的工具调用:修改、删除、新增 | 高风险,以红字提示:插件可以改动客户端要执行的操作。改动后的工具调用仍经过工具调用审查;安装这类插件、打开它、更改它的代码和确认它的文件变更,都要在系统对话框中确认。 | +| `reply.tool_calls` | 回答中的工具调用:修改、删除、新增 | 高风险,以红字提示:插件可以改动客户端要执行的操作。改动后的工具调用仍经过「危险命令」检查;安装这类插件、打开它、更改它的代码和确认它的文件变更,都要在系统对话框中确认。 | ## 插件出错时 @@ -264,8 +264,8 @@ type Ctx = { - **沙箱里什么都没有。** 插件在 QuickJS 中运行,QuickJS 编译成 WebAssembly,由 core 内部的 Wasmtime 执行。插件代码从不在应用窗口中运行,也从不以原生代码运行。沙箱里没有网络、文件、环境变量和进程;即使 JavaScript 引擎本身有漏洞,也只能破坏沙箱自己的内存,碰不到 core 进程中的密钥与令牌。 - **不留任何数据。** 每次调用请求钩子都使用新实例。每个回答中,一个插件使用一个实例,由它在这个回答上的各个钩子共用,回答结束即丢弃。插件之间不共享任何东西。 -- **只看到占位符。** 出站脱敏规则能识别的密钥,在交给插件之前替换为占位符,插件处理之后再换回;请求与回答两个方向都是如此,与这项防护处于哪一档无关。回答一侧同样重要:回答会进入对话历史,随下一次请求再次发往上游;插件如果看得到真实的密钥,就能把它编码后藏进回答里带出去。 -- **防护照常生效。** 请求钩子在路由之后运行,被它改动的请求在出站脱敏之前再经过内容过滤;回答钩子在工具调用审查之前运行。插件写入的内容和其他内容一样受检,插件既改变不了请求的路由,也不能换用密钥不可用的模型。 +- **只看到占位符。** 「密钥与隐私」中替换为占位符的规则所识别的密钥,在交给插件之前替换为占位符,插件处理之后再换回;请求与回答两个方向都是如此,与这项防护处于哪种状态无关。回答一侧同样重要:回答会进入对话历史,随下一次请求再次发往上游;插件如果看得到真实的密钥,就能把它编码后藏进回答里带出去。 +- **防护照常生效。** 请求钩子在路由之后运行,被它改动的请求在「密钥与隐私」处理之前再经过内容过滤;回答钩子在内容过滤检查回答之前、「危险命令」检查之前运行。插件写入的内容和其他内容一样受检,插件既改变不了请求的路由,也不能换用密钥不可用的模型。 - **只运行确认过的代码。** 插件文件与确认过的 SHA-256 哈希一致才会运行,在应用中保存时,文件与哈希一同更新。能改动工具调用的插件,安装、打开、更改代码和确认文件变更,都要在页面之外的系统对话框中确认,见[在系统对话框中确认](#在系统对话框中确认)。 - **改动都有记录。** 每次运行都记录在请求上;被改动的请求另存一份发往作答上游的版本,和所有存下的请求一样替换掉了密钥;「流量」页为被插件改动的请求加上标记。 - **用量有上限。** 每次调用都有 CPU 时间、内存、输出和日志量的上限,同时存在的回答实例也有数量上限。插件在单独的线程池中运行,运行缓慢的插件不会拖住网关本身的工作。 @@ -273,7 +273,7 @@ type Ctx = { ## 沙箱无法防范的情况 -插件本来就有权改动内容,沙箱无法判断一处改动是否正当。拥有 `system` 或 `messages` 权限的插件可以往提示词里写入指令;拥有 `reply.text` 的插件可以把回答改得误导人;拥有 `params` 的插件可以在密钥的可用模型中换用更贵的模型;拥有 `reply.tool_calls` 的插件可以改动客户端要执行的操作,而工具调用审查只能拦下其规则覆盖的写法。出站脱敏规则识别不了的密钥,插件看得到;这类密钥本来也会原样发往上游,可以在安全页添加自定义规则覆盖它的格式。 +插件本来就有权改动内容,沙箱无法判断一处改动是否正当。拥有 `system` 或 `messages` 权限的插件可以往提示词里写入指令;拥有 `reply.text` 的插件可以把回答改得误导人;拥有 `params` 的插件可以在密钥的可用模型中换用更贵的模型;拥有 `reply.tool_calls` 的插件可以改动客户端要执行的操作,而「危险命令」只能拦下其规则覆盖的写法。「密钥与隐私」规则识别不了的密钥,以及「仅记录」规则检出的密钥,插件看得到;这类密钥本来也会原样发往上游,可以在安全页添加自定义规则覆盖它的格式。 降低这些风险的办法:只授予插件所需的权限,安装前通读代码,并在请求详情中对照经过插件前后的请求。 diff --git a/src/content/docs/_meta.ts b/src/content/docs/_meta.ts index 77a8733..04108aa 100644 --- a/src/content/docs/_meta.ts +++ b/src/content/docs/_meta.ts @@ -255,8 +255,8 @@ export const products: Product[] = [ locales: both, group: "guides", summary: { - en: "Outbound redaction swaps keys in requests for placeholders before a relay sees them; tool-call inspection cuts off dangerous calls.", - "zh-CN": "出站脱敏在中转站看到请求之前把其中的密钥换成占位符,工具调用审查切断危险的工具调用。", + en: "Secrets & privacy swaps keys in requests for placeholders before a relay sees them; Dangerous commands cuts off dangerous tool calls.", + "zh-CN": "「密钥与隐私」在中转站看到请求之前把其中的密钥换成占位符,「危险命令」切断危险的工具调用。", }, }, { diff --git a/src/content/docs/en/api-reference.md b/src/content/docs/en/api-reference.md index 9083fb6..c7c8e1a 100644 --- a/src/content/docs/en/api-reference.md +++ b/src/content/docs/en/api-reference.md @@ -2054,6 +2054,7 @@ Search audit log entries. Backed by ClickHouse for SQL-based search and analytic | Parameter | Type | Required | Default | Description | | --------- | ------- | -------- | ------- | -------------------------------------- | | `q` | string | No | — | Full-text search query | +| `action` | string | No | — | One action, or several separated by commas (the first 32 are used); an entry matches any of them | | `from` | string | No | — | Start datetime (ISO 8601) | | `to` | string | No | — | End datetime (ISO 8601) | | `limit` | integer | No | 50 | Number of results (max 1000) | diff --git a/src/content/docs/en/architecture.md b/src/content/docs/en/architecture.md index 545cb35..8c3ae1e 100644 --- a/src/content/docs/en/architecture.md +++ b/src/content/docs/en/architecture.md @@ -324,7 +324,7 @@ Authentication and authorization library. Contains: Shared infrastructure used by all other crates. Contains: - **`config.rs`** -- `AppConfig` struct loaded from environment variables. -- **`dynamic_config.rs`** -- `DynamicConfig` system that loads settings from the `system_settings` database table. Supports multi-instance sync via Redis Pub/Sub and in-memory caching. Covers JWT TTLs, cache TTL, the policies of the request guards (outbound redaction, tool-call inspection and the content filter), budget thresholds, API key policies, and data retention settings. +- **`dynamic_config.rs`** -- `DynamicConfig` system that loads settings from the `system_settings` database table. Supports multi-instance sync via Redis Pub/Sub and in-memory caching. Covers JWT TTLs, cache TTL, the policies of the request guards (`security.redact`, `security.inspect_tools` and `security.content`: Secrets & privacy, Dangerous commands and the content filter in the console), budget thresholds, API key policies, and data retention settings. - **`db.rs`** -- PostgreSQL connection pool setup using `sqlx`. - **`models/`** -- Database model structs (one per domain entity): `user.rs`, `team.rs`, `api_key.rs`, `provider.rs`, `mcp_server.rs`, `usage.rs`, `audit_log.rs`. - **`dto/`** -- Data transfer objects for API request/response serialization. diff --git a/src/content/docs/en/configuration.md b/src/content/docs/en/configuration.md index c8d2bed..eb560c4 100644 --- a/src/content/docs/en/configuration.md +++ b/src/content/docs/en/configuration.md @@ -495,29 +495,46 @@ Changes to dynamic settings take effect immediately without requiring a server r | ---------------------------- | ------- | ---------------------------------------------------- | | `signature_drift_seconds` | `300` | Maximum allowed clock drift for signed requests | | `nonce_ttl_seconds` | `300` | TTL for nonce values used in replay protection | -| `security.redact` | `{}` | Outbound redaction policy, see [Request guards](#request-guards) | -| `security.inspect_tools` | `{}` | Tool-call inspection policy, see [Request guards](#request-guards) | +| `security.redact` | `{}` | Secrets & privacy (outbound redaction) policy, see [Request guards](#request-guards) | +| `security.inspect_tools` | `{}` | Dangerous commands (tool-call inspection) policy, see [Request guards](#request-guards) | | `security.content` | `{}` | Content filter policy, see [Request guards](#request-guards) | | `security.rate_limit_fail_closed` | `false` | Refuse requests whose limits cannot be checked, see [Limits that cannot be checked](#limits-that-cannot-be-checked) | #### Request guards -Outbound redaction, tool-call inspection and the content filter each keep their whole policy as one JSON object under `security.redact`, `security.inspect_tools` and `security.content`. The object has the shape of the `security` section of ThinkWatch Core's `config.yaml`, which the [Core configuration reference](/docs/core/configuration#cfg-security) describes field by field, built-in rules included; `{}` is the factory setting. +The three request guards, Secrets & privacy (outbound redaction), Dangerous commands (tool-call inspection) and the content filter, each keep their whole policy as one JSON object under `security.redact`, `security.inspect_tools` and `security.content`. The object has the shape of the `security` section of ThinkWatch Core's `config.yaml`, which the [Core configuration reference](/docs/core/configuration#cfg-security) describes field by field, built-in rules included; `{}` is the factory setting. -- `mode` is `off`, `observe` or `enforce`. `observe`, the factory mode, records matches in the audit log and changes nothing; the console calls `enforce` Replace for outbound redaction, Cut off for tool-call inspection and Enforce for the content filter. -- `enable` and `disable` switch built-in rules on and off by id, `actions` changes what a built-in rule does under `enforce`, and `custom` holds rules of the deployment's own. +- `mode` is `off`, `observe` or `enforce`, shown in the console as Off, Monitor and On. `observe`, the factory mode, records matches in the audit log and changes nothing; `enforce` handles each match by the action of the rule that found it. +- `enable` and `disable` switch built-in rules on and off by id, `actions` changes what a built-in rule does under `enforce`, and `custom` holds rules of the deployment's own, each with its own `action`. A redaction rule replaces what it finds with a placeholder (`placeholder`, the default) or only records it (`record`); a tool-call rule cuts the answer off (`cut`) or records; a content rule refuses the request (`block`), deletes the match (`strip`), replaces it (`replace`) or records. +- A record-only redaction rule sends the value upstream unchanged and writes `gateway.redaction_flagged` while the guard is On. Where its match overlaps a match that is replaced, the value is replaced. With `audit.body_redact_pii` on, the value is still masked in stored bodies. - A custom redaction rule's `match` is `contains`, the default, which looks for `pattern` as written, so `.`, `*` and `\d` have no special meaning, or `regex`, which takes `pattern` as a regular expression. It ignores case unless `case_sensitive` is `true`. The console calls these Match by and Case-sensitive. - Redaction does not search field names, and custom redaction rules leave alone the values of `id`, `call_id`, `item_id`, `tool_use_id`, `tool_call_id`, `toolUseId`, `previous_response_id`, `response_id`, `type`, `role`, `name`, `namespace`, `model`, `status`, `object` and `phase`. Built-in rules still search those values, and every other value is searched by every rule. The same holds when stored bodies are masked with `audit.body_redact_pii`. +- A custom content rule's `scope` says what it checks: `["request"]` (the default, the caller's messages and tool results), `["response"]` or both. On an answer the rule reads the text the client is shown and the input of freeform tools such as Codex's `apply_patch`, not tool calls and not reasoning, in whole and streamed answers, answers served from the cache and the Responses WebSocket. A rule that checks answers cannot use `block` or `"match": "codepoints"`; such a policy is refused when saved. Built-in content rules check requests only. +- `replace` writes the rule's `replacement` (`***` when left out, at most 200 characters) in place of a match, in requests and in answers. A replacement is not put back in the answer and is not checked again. `case_sensitive: true` makes a content rule tell capital letters from small ones; content rules ignore case by default. +- Under On, with a rule that checks answers and deletes or replaces, a streamed answer is never held back whole: only the last characters that could still grow into a match wait for the next piece, at most 256 for a regular expression. Logprobs are then removed from streamed answers, and from a whole answer whose text changed, and the log row stores the answer as the client received it. Under Monitor, or when every answer rule only records, answers pass unchanged. +- Guard hits are audit events, and with them reach the log forwarders. A content rule that replaces writes `gateway.content_replaced`; a content event carries `direction` (`request` or `response`), and an answer's event names the upstream in `resource`. Content, redaction and tool-call events carry the guard's `mode`, and redaction events the rule's `action`. The `gateway_content_matched_total` metric has a `direction` label. ```json { "mode": "enforce", "enable": ["email"], + "actions": { "email": "record" }, "custom": [{ "name": "Employee ID", "pattern": "EMP-\\d{6}", "match": "regex", "label": "EMPLOYEE" }] } ``` -The Content Security page of the console edits these objects. Through `PATCH /api/admin/settings` a key is written whole and checked first: a misspelt field, an unknown built-in rule, a pattern that does not compile or a malformed code point is refused with `400`. Writing `security.redact` takes the `pii_redactor:write` permission, and the other two keys take `content_filter:write`. `GET /api/admin/security` lists each guard's mode and every rule, and `POST /api/admin/security/{guard}/test` tries a sample against them. Custom redaction rules saved by ThinkWatch 3.0 to 3.6 carry neither `match` nor `case_sensitive`, so from 3.7.0 they look for their text as written and ignore case; one written as a regular expression needs `"match": "regex"`, and `"case_sensitive": true` where case matters. Change them only once every replica runs 3.7.0, since 3.6 cannot read a redaction policy that uses these keys. A deployment upgraded from a version that kept `security.content_filter_patterns`, `security.pii_redactor_patterns`, `security.hidden_text` and `security.tool_inspection` has them converted into these keys at its first start; the old redaction patterns become case-sensitive `regex` rules. +A `security.content` policy that replaces a codename in requests and answers: + +```json +{ + "mode": "enforce", + "custom": [{ "name": "Codename", "pattern": "polaris", "scope": ["request", "response"], "action": "replace", "replacement": "[codename]" }] +} +``` + +The Content Security page of the console edits these objects: a Log tab, for holders of `logs:read_all`, lists the guards' audit events, and each guard has a tab where every rule is switched on or off and given its action in place. Through `PATCH /api/admin/settings` a key is written whole and checked first: a misspelt field, an unknown built-in rule, a pattern that does not compile, a malformed code point or a rule on answers that refuses or matches code points is refused with `400`. Writing `security.redact` takes the `pii_redactor:write` permission, shown on the role pages as Secrets & privacy, and the other two keys take `content_filter:write`, shown as Content filter & dangerous commands. `GET /api/admin/security` lists each guard's mode and every rule, and `POST /api/admin/security/{guard}/test` tries a sample against them; for the content filter it takes `scope`, to try the sample as a request or as an answer, and `replacement`. + +Policies saved before 3.8.0 keep their behaviour: redaction rules replace with placeholders, content rules check requests only and ignore case, and answers are not changed. ThinkWatch 3.7 refuses a policy with keys it does not know and runs that guard on its factory policy, so use `actions` or a custom rule's `action` on redaction rules, or `scope`, `case_sensitive`, `replacement` or the action `replace` on content rules, only once every replica runs 3.8.0, and remove those keys before rolling back. Custom redaction rules saved by ThinkWatch 3.0 to 3.6 carry neither `match` nor `case_sensitive`, so from 3.7.0 they look for their text as written and ignore case; one written as a regular expression needs `"match": "regex"`, and `"case_sensitive": true` where case matters. A deployment upgraded from a version that kept `security.content_filter_patterns`, `security.pii_redactor_patterns`, `security.hidden_text` and `security.tool_inspection` has them converted into these keys at its first start; the old redaction patterns become case-sensitive `regex` rules. #### Limits that cannot be checked diff --git a/src/content/docs/en/deployment-guide.md b/src/content/docs/en/deployment-guide.md index 1d05a39..01119b9 100644 --- a/src/content/docs/en/deployment-guide.md +++ b/src/content/docs/en/deployment-guide.md @@ -231,7 +231,7 @@ docker compose -f deploy/docker-compose.yml --env-file .env.production up -d To pin a release instead of `latest`, set `IMAGE_TAG` to its version, or to the SHA of a commit on `main`: ```bash -IMAGE_TAG=3.7.0 docker compose -f deploy/docker-compose.yml --env-file .env.production up -d +IMAGE_TAG=3.8.0 docker compose -f deploy/docker-compose.yml --env-file .env.production up -d ``` This starts: @@ -752,8 +752,8 @@ The server is stateless, so rolling updates work out of the box: ```bash # Update the image tag helm upgrade think-watch deploy/helm/think-watch \ - --set image.server.tag=3.7.0 \ - --set image.web.tag=3.7.0 \ + --set image.server.tag=3.8.0 \ + --set image.web.tag=3.8.0 \ --reuse-values ``` diff --git a/src/content/docs/en/overview.md b/src/content/docs/en/overview.md index fdafc3d..aff553e 100644 --- a/src/content/docs/en/overview.md +++ b/src/content/docs/en/overview.md @@ -7,7 +7,7 @@ ThinkWatch Enterprise is a self-hosted AI API and MCP gateway for organizations. ## Highlights - **MCP tool calls run as the real user.** Each user connects their own GitHub, Notion, Linear, Slack or Atlassian account, so the upstream's own audit log shows who acted. Each tool can be granted per role and per API key. -- **Security guards on every request.** Credentials and personal information can be replaced with placeholders before a request goes upstream and restored in the answer, and a dangerous tool call in a model response can be cut off before the client runs it. A content filter can refuse prompt injection or delete hidden characters from what the caller sends; every guard ships in observe mode, which only records. +- **Security guards on every request.** Credentials and personal information can be replaced with placeholders before a request goes upstream and restored in the answer, and a dangerous tool call in a model response can be cut off before the client runs it. A content filter can refuse prompt injection or delete hidden characters from what the caller sends, and delete or replace chosen words in requests and answers. Every guard ships in Monitor, which only records, and every rule has its own action. - **Identity from the organization's directory.** Sign-in works through any OIDC provider, with optional TOTP. Five built-in roles and custom roles decide who may use which models, tools and admin pages. - **One key for AI and MCP.** `tw-` virtual keys can be scoped to the AI gateway, the MCP gateway or both. Keys are stored only as hashes and rotate with a grace period. - **Rate limits and budgets.** Sliding windows from one minute to one week limit requests or tokens, and daily, weekly or monthly budgets cap spending. Both attach to users, API keys or roles. diff --git a/src/content/docs/zh-CN/api-reference.md b/src/content/docs/zh-CN/api-reference.md index 1368980..a118b35 100644 --- a/src/content/docs/zh-CN/api-reference.md +++ b/src/content/docs/zh-CN/api-reference.md @@ -2054,6 +2054,7 @@ curl http://localhost:3001/api/analytics/costs/stats \ | 参数 | 类型 | 必填 | 默认值 | 描述 | | --------- | ------- | -------- | ------- | -------------------------------------- | | `q` | string | 否 | — | 全文搜索查询 | +| `action` | string | 否 | — | 一个操作,或以逗号分隔的多个操作(取前 32 个);条目与其中任一个相符即返回 | | `from` | string | 否 | — | 开始日期时间(ISO 8601) | | `to` | string | 否 | — | 结束日期时间(ISO 8601) | | `limit` | integer | 否 | 50 | 结果数量(最大 1000) | diff --git a/src/content/docs/zh-CN/architecture.md b/src/content/docs/zh-CN/architecture.md index fbb51a0..afc987d 100644 --- a/src/content/docs/zh-CN/architecture.md +++ b/src/content/docs/zh-CN/architecture.md @@ -324,7 +324,7 @@ MCP 代理引擎。包含: 所有其他 crate 使用的共享基础设施。包含: - **`config.rs`** —— 从环境变量加载的 `AppConfig` 结构体。 -- **`dynamic_config.rs`** —— `DynamicConfig` 系统,从 `system_settings` 数据库表加载配置。支持通过 Redis Pub/Sub 的多实例同步和内存缓存。涵盖 JWT TTL、缓存 TTL、请求防护(出站脱敏、工具调用审查、内容过滤)的策略、预算阈值、API Key 策略和数据保留设置。 +- **`dynamic_config.rs`** —— `DynamicConfig` 系统,从 `system_settings` 数据库表加载配置。支持通过 Redis Pub/Sub 的多实例同步和内存缓存。涵盖 JWT TTL、缓存 TTL、请求防护(`security.redact`、`security.inspect_tools`、`security.content`,控制台中为「密钥与隐私」「危险命令」「内容过滤」)的策略、预算阈值、API Key 策略和数据保留设置。 - **`db.rs`** —— 使用 `sqlx` 设置 PostgreSQL 连接池。 - **`models/`** —— 数据库模型结构体(每个领域实体一个):`user.rs`、`team.rs`、`api_key.rs`、`provider.rs`、`mcp_server.rs`、`usage.rs`、`audit_log.rs`。 - **`dto/`** —— 用于 API 请求/响应序列化的数据传输对象。 diff --git a/src/content/docs/zh-CN/configuration.md b/src/content/docs/zh-CN/configuration.md index 6303e78..bbe7a31 100644 --- a/src/content/docs/zh-CN/configuration.md +++ b/src/content/docs/zh-CN/configuration.md @@ -495,29 +495,46 @@ openssl rand -base64 32 | ---------------------------- | ------- | -------------------------------------------- | | `signature_drift_seconds` | `300` | 签名请求允许的最大时钟偏差 | | `nonce_ttl_seconds` | `300` | 用于重放保护的 nonce 值 TTL | -| `security.redact` | `{}` | 出站脱敏的策略,见[请求防护](#请求防护) | -| `security.inspect_tools` | `{}` | 工具调用审查的策略,见[请求防护](#请求防护) | +| `security.redact` | `{}` | 「密钥与隐私」(出站脱敏)的策略,见[请求防护](#请求防护) | +| `security.inspect_tools` | `{}` | 「危险命令」(工具调用审查)的策略,见[请求防护](#请求防护) | | `security.content` | `{}` | 内容过滤的策略,见[请求防护](#请求防护) | | `security.rate_limit_fail_closed` | `false` | 限额无法检查时拒绝请求,见[无法检查限额时](#无法检查限额时) | #### 请求防护 -出站脱敏、工具调用审查和内容过滤各以一个 JSON 对象保存完整的策略,分别位于 `security.redact`、`security.inspect_tools` 和 `security.content`。对象的结构与 ThinkWatch Core 的 `config.yaml` 中 `security` 一节相同,各字段与全部内置规则见 [Core 配置手册](/zh-CN/docs/core/configuration#cfg-security);`{}` 即出厂设置。 +三项请求防护,即「密钥与隐私」(出站脱敏)、「危险命令」(工具调用审查)和「内容过滤」,各以一个 JSON 对象保存完整的策略,分别位于 `security.redact`、`security.inspect_tools` 和 `security.content`。对象的结构与 ThinkWatch Core 的 `config.yaml` 中 `security` 一节相同,各字段与全部内置规则见 [Core 配置手册](/zh-CN/docs/core/configuration#cfg-security);`{}` 即出厂设置。 -- `mode` 为 `off`、`observe` 或 `enforce`。出厂为 `observe`:命中的内容记入审计日志,不做任何改动;`enforce` 在控制台中按作用命名,出站脱敏为「替换」,工具调用审查为「切断」,内容过滤为「处置」。 -- `enable` 和 `disable` 按 id 启用或停用内置规则,`actions` 改变内置规则在 `enforce` 下的处置,`custom` 保存部署自己的规则。 -- 出站脱敏的自定义规则以 `match` 指定匹配方式:`contains`(默认)按原样查找 `pattern`,`.`、`*`、`\d` 等没有特殊含义;`regex` 把 `pattern` 作为正则表达式。`case_sensitive` 为 `true` 时区分大小写,否则不区分。控制台中两项分别为「匹配方式」和「区分大小写」。 -- 出站脱敏不查找字段名;自定义脱敏规则还会跳过 `id`、`call_id`、`item_id`、`tool_use_id`、`tool_call_id`、`toolUseId`、`previous_response_id`、`response_id`、`type`、`role`、`name`、`namespace`、`model`、`status`、`object` 和 `phase` 的值。内置规则照常查找这些值,其余的值由所有规则照常查找。按 `audit.body_redact_pii` 对存储的请求体脱敏时同样如此。 +- `mode` 为 `off`、`observe` 或 `enforce`,控制台中分别显示为「关闭」「监控」「开启」。出厂为 `observe`:命中的内容记入审计日志,不做任何改动;`enforce` 按命中规则的动作处理。 +- `enable` 和 `disable` 按 id 启用或停用内置规则,`actions` 改变内置规则在 `enforce` 下的动作,`custom` 保存部署自己的规则,每条规则各带 `action`。脱敏规则替换为占位符(`placeholder`,默认)或只记录(`record`);工具调用规则切断回答(`cut`)或只记录;内容规则拒绝请求(`block`)、删除命中内容(`strip`)、替换命中内容(`replace`)或只记录。 +- 只记录的脱敏规则把值原样发往上游,防护处于「开启」时写入 `gateway.redaction_flagged`。与要替换的命中重叠时,该值照常替换。开启 `audit.body_redact_pii` 时,存储的请求体中该值仍以掩码保存。 +- 自定义脱敏规则以 `match` 指定匹配方式:`contains`(默认)按原样查找 `pattern`,`.`、`*`、`\d` 等没有特殊含义;`regex` 把 `pattern` 作为正则表达式。`case_sensitive` 为 `true` 时区分大小写,否则不区分。控制台中两项分别为「匹配方式」和「区分大小写」。 +- 脱敏不查找字段名;自定义脱敏规则还会跳过 `id`、`call_id`、`item_id`、`tool_use_id`、`tool_call_id`、`toolUseId`、`previous_response_id`、`response_id`、`type`、`role`、`name`、`namespace`、`model`、`status`、`object` 和 `phase` 的值。内置规则照常查找这些值,其余的值由所有规则照常查找。按 `audit.body_redact_pii` 对存储的请求体脱敏时同样如此。 +- 自定义内容规则以 `scope` 指定检查对象:`["request"]`(默认,即调用方的消息与工具结果)、`["response"]` 或两者。检查回答时,规则读取客户端看到的正文,以及 Codex `apply_patch` 等自由格式工具的输入,不含工具调用与思考过程;整份回答、流式回答、缓存命中的回答与 Responses WebSocket 都在其内。检查回答的规则不能使用 `block`,也不能使用 `"match": "codepoints"`,这样的策略在保存时被拒绝。内置内容规则只检查请求。 +- `replace` 把命中内容替换为规则的 `replacement`(省略时为 `***`,最多 200 个字符),请求与回答中均适用。替换后的文字在回答中不还原,也不再检查。`case_sensitive: true` 使内容规则区分大小写;内容规则默认不区分。 +- 防护处于「开启」且有检查回答的规则会删除或替换时,流式回答不整体缓冲,只暂缓末尾可能构成命中的字符,正则规则至多 256 个字符。此时流式回答以及正文有改动的整份回答不再附带 logprobs,日志行保存客户端实际收到的回答。处于「监控」或检查回答的规则全部只记录时,回答原样通过。 +- 各项防护的命中都是审计事件,也随之进入日志转发。替换内容的内容规则写入 `gateway.content_replaced`;内容事件带 `direction`(`request` 或 `response`),回答中的事件在 `resource` 中注明上游。内容、脱敏与工具调用事件都带防护的 `mode`,脱敏事件另带规则的 `action`。指标 `gateway_content_matched_total` 带 `direction` 标签。 ```json { "mode": "enforce", "enable": ["email"], + "actions": { "email": "record" }, "custom": [{ "name": "员工编号", "pattern": "EMP-\\d{6}", "match": "regex", "label": "EMPLOYEE" }] } ``` -控制台的「内容安全」页编辑这些对象。经 `PATCH /api/admin/settings` 写入时,一个键整体写入,写入前先校验:字段名拼错、内置规则 id 不存在、正则无法编译或码位写法有误时返回 `400`。写入 `security.redact` 需要 `pii_redactor:write` 权限,另外两个键需要 `content_filter:write`。`GET /api/admin/security` 列出每项防护的档位与全部规则,`POST /api/admin/security/{guard}/test` 用一段样本测试这些规则。ThinkWatch 3.0 至 3.6 保存的自定义脱敏规则不带 `match` 和 `case_sensitive`,自 3.7.0 起按原样查找文字、不区分大小写;按正则表达式编写的规则需要加上 `"match": "regex"`,需要区分大小写的再加上 `"case_sensitive": true`。3.6 读不了使用这两个键的脱敏策略,因此应在所有副本都升级到 3.7.0 之后再修改。从仍使用 `security.content_filter_patterns`、`security.pii_redactor_patterns`、`security.hidden_text` 和 `security.tool_inspection` 的版本升级时,这些设置在首次启动时转换为上述三个键,原有的脱敏写法转换为区分大小写的 `regex` 规则。 +在请求与回答中替换项目代号的 `security.content` 策略: + +```json +{ + "mode": "enforce", + "custom": [{ "name": "项目代号", "pattern": "polaris", "scope": ["request", "response"], "action": "replace", "replacement": "[代号]" }] +} +``` + +控制台的「内容安全」页编辑这些对象:「日志」标签页向拥有 `logs:read_all` 权限的用户列出各项防护的审计事件,每项防护各有一个标签页,可在列表中直接启用或停用每条规则并设定动作。经 `PATCH /api/admin/settings` 写入时,一个键整体写入,写入前先校验:字段名拼错、内置规则 id 不存在、正则无法编译、码位写法有误,或检查回答的规则使用拒绝或码位时,返回 `400`。写入 `security.redact` 需要 `pii_redactor:write` 权限(角色页中显示为「密钥与隐私」),另外两个键需要 `content_filter:write`(显示为「内容过滤与危险命令」)。`GET /api/admin/security` 列出每项防护的状态与全部规则,`POST /api/admin/security/{guard}/test` 用一段样本测试这些规则;测试内容过滤时可传入 `scope`,按请求或按回答测试,并可传入 `replacement`。 + +3.8.0 之前保存的策略行为不变:脱敏规则替换为占位符,内容规则只检查请求、不区分大小写,回答不作改动。ThinkWatch 3.7 拒绝含有不认识的键的策略,并让该项防护按出厂策略运行;因此脱敏规则的 `actions` 或自定义规则的 `action`,以及内容规则的 `scope`、`case_sensitive`、`replacement` 和动作 `replace`,应在所有副本都升级到 3.8.0 之后再使用,回滚前须先删除这些键。ThinkWatch 3.0 至 3.6 保存的自定义脱敏规则不带 `match` 和 `case_sensitive`,自 3.7.0 起按原样查找文字、不区分大小写;按正则表达式编写的规则需要加上 `"match": "regex"`,需要区分大小写的再加上 `"case_sensitive": true`。从仍使用 `security.content_filter_patterns`、`security.pii_redactor_patterns`、`security.hidden_text` 和 `security.tool_inspection` 的版本升级时,这些设置在首次启动时转换为上述三个键,原有的脱敏写法转换为区分大小写的 `regex` 规则。 #### 无法检查限额时 diff --git a/src/content/docs/zh-CN/deployment-guide.md b/src/content/docs/zh-CN/deployment-guide.md index 88639a4..ff22425 100644 --- a/src/content/docs/zh-CN/deployment-guide.md +++ b/src/content/docs/zh-CN/deployment-guide.md @@ -231,7 +231,7 @@ docker compose -f deploy/docker-compose.yml --env-file .env.production up -d 如需固定某个版本而非 `latest`,将 `IMAGE_TAG` 设为该版本号,或 `main` 分支上某次提交的 SHA: ```bash -IMAGE_TAG=3.7.0 docker compose -f deploy/docker-compose.yml --env-file .env.production up -d +IMAGE_TAG=3.8.0 docker compose -f deploy/docker-compose.yml --env-file .env.production up -d ``` 这将启动: @@ -752,8 +752,8 @@ ThinkWatch 在 Web 控制台中内置了**配置指南**页面,位于 `/guide` ```bash # Update the image tag helm upgrade think-watch deploy/helm/think-watch \ - --set image.server.tag=3.7.0 \ - --set image.web.tag=3.7.0 \ + --set image.server.tag=3.8.0 \ + --set image.web.tag=3.8.0 \ --reuse-values ``` diff --git a/src/content/docs/zh-CN/overview.md b/src/content/docs/zh-CN/overview.md index d795528..9fff26d 100644 --- a/src/content/docs/zh-CN/overview.md +++ b/src/content/docs/zh-CN/overview.md @@ -7,7 +7,7 @@ ThinkWatch 企业版是面向组织自托管的 AI API 与 MCP 网关。组织 ## 要点 - **MCP 工具调用以真实用户身份执行。** 每位用户连接自己的 GitHub、Notion、Linear、Slack、Atlassian 等账号,上游自身的审计日志因此能记录到具体操作人。每个工具可以按角色和按 API Key 授权。 -- **每个请求都经过安全防护。** 凭据和个人信息可在请求发往上游前替换为占位符,并在回答中还原;模型返回的危险工具调用可在客户端执行前切断。内容过滤可拒绝提示词注入,或删除调用方发送内容中的隐藏字符;各项防护出厂为观察档,只记录。 +- **每个请求都经过安全防护。** 凭据和个人信息可在请求发往上游前替换为占位符,并在回答中还原;模型返回的危险工具调用可在客户端执行前切断。内容过滤可拒绝提示词注入,或删除调用方发送内容中的隐藏字符,也可删除或替换请求与回答中的指定词语。各项防护出厂为「监控」,只作记录;每条规则可单独设定动作。 - **身份来自组织目录。** 登录可对接任意 OIDC 提供商,并可启用 TOTP 两步验证。五个内置角色与自定义角色决定每个人可用的模型、工具和管理页面。 - **AI 与 MCP 共用一把密钥。** `tw-` 虚拟密钥可限定用于 AI 网关、MCP 网关或两者。密钥只以哈希形式保存,轮换时保留宽限期。 - **限流与预算。** 一分钟到一周的滑动窗口限制请求数或 token 数,按日、周、月的预算控制总用量。两者均可设置在用户、API Key 或角色上。 diff --git a/src/data/core-docs/config.md b/src/data/core-docs/config.md index ff22925..65200a7 100644 --- a/src/data/core-docs/config.md +++ b/src/data/core-docs/config.md @@ -738,27 +738,29 @@ The defaults intercept only what nobody would miss. ### `security` Three guards, applied to every upstream alike. Each has a `mode`: `off`, -`observe` (detect and record, change nothing) or `enforce` (act). All three -start in `observe`. What `enforce` does differs per guard: redaction replaces, -tool-call inspection cuts the response off, and the content filter does what -each rule says (refuse, delete or record). +`observe` (detect and record, change nothing) or `enforce` (handle each match +by its rule's action). All three start in `observe`. Every rule has an +action: redaction replaces with a placeholder or only records, tool-call +inspection cuts the response off or only records, and the content filter +refuses, deletes, replaces or only records. | Field | Type | Default | Description | |---|---|---|---| -| `redact` | object, [`security.redact`](#cfg-security-redact) | — | Outbound redaction: credentials and personal information anywhere in a request are replaced before it leaves. | -| `inspect_tools` | object, [`security.inspect_tools`](#cfg-security-inspect_tools) | — | Tool-call inspection: dangerous commands in the tool calls a model returns cut the response off. | -| `content` | object, [`security.content`](#cfg-security-content) | — | Content filter: words, patterns or characters (hidden ones among them) in what the caller sends; each rule refuses the request, deletes what it matched, or only records it. | +| `redact` | object, [`security.redact`](#cfg-security-redact) | — | Outbound redaction (Secrets & privacy in the app): credentials and personal information anywhere in a request are replaced with placeholders before it leaves, or only recorded, rule by rule. | +| `inspect_tools` | object, [`security.inspect_tools`](#cfg-security-inspect_tools) | — | Tool-call inspection (Dangerous commands in the app): dangerous commands in the tool calls a model returns cut the response off. | +| `content` | object, [`security.content`](#cfg-security-content) | — | Content filter: words, patterns or characters (hidden ones among them) in what the caller sends, and words or patterns in the text of the answer; each rule refuses the request, deletes or replaces what it matched, or only records it. | #### `security.redact` Before a request leaves, the whole request (system prompt, earlier answers and tool calls included) is searched for credentials and personal -information. Under `enforce` what is found is replaced with placeholders, and -put back where the answer repeats them. Images, files and other base64 +information. Under `enforce` what a rule finds is replaced with placeholders, +and put back where the answer repeats them; what a rule with `action: record` +finds is sent as it is and only recorded. Images, files and other base64 payloads are not searched, nor are field names; custom rules also leave alone the identifiers a protocol needs as they are, such as item and call ids, types, roles, tool names and model names. @@ -768,10 +770,11 @@ types, roles, tool names and model names. | Field | Type | Default | Description | |---|---|---|---| -| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` does nothing; `observe` detects and records only, and changes nothing; `enforce` detects and acts. | +| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` does nothing (Off in the app); `observe` detects and records only, and changes nothing (Monitor); `enforce` detects and handles each match by its rule's action (On). | | `enable` | list of strings | `[]` | Built-in rules to switch on that are off out of the box, by id. | | `disable` | list of strings | `[]` | Built-in rules to switch off, by id. | -| `custom` | list of [`security.redact.custom[]`](#cfg-security-redact-custom) | `[]` | Rules of your own: whatever a rule matches is replaced like a credential. | +| `actions` | map of built-in rule id → `placeholder` \| `record` | `{}` | What a built-in rule does under `enforce`, written only where it differs from the factory setting (`email: record`). `placeholder` sends a placeholder in place of the value and puts the value back where the answer repeats the placeholder; `record` sends the value as it is and records the match. | +| `custom` | list of [`security.redact.custom[]`](#cfg-security-redact-custom) | `[]` | Rules of your own: whatever a rule matches is replaced like a credential, or only recorded. | @@ -784,6 +787,7 @@ types, roles, tool names and model names. | `match` | `contains` \| `regex` | `contains` | `contains`: `pattern` is looked for as written; characters such as `.` and `*` have no special meaning. `regex`: `pattern` is a regular expression. | | `case_sensitive` | bool | `false` | Tell capital letters from small ones. Off by default: `ABC` and `abc` both match. | | `label` | string | `SECRET` | Placeholder name: what the rule matches is replaced with `<>`, numbered per name. Capital letters, digits and underscores, starting with a letter, at most 24 characters. | +| `action` | `placeholder` \| `record` | `placeholder` | Under `enforce`: replace what the rule matches with a `placeholder`, or only `record` the match and send it as it is. | | `disabled` | bool | `false` | Switches the rule off and keeps it in the file. | @@ -871,7 +875,7 @@ receives a complete call to run. | Field | Type | Default | Description | |---|---|---|---| -| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` does nothing; `observe` detects and records only, and changes nothing; `enforce` detects and acts. | +| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` does nothing (Off in the app); `observe` detects and records only, and changes nothing (Monitor); `enforce` detects and handles each match by its rule's action (On). | | `enable` | list of strings | `[]` | Built-in rules to switch on that are off out of the box, by id. | | `disable` | list of strings | `[]` | Built-in rules to switch off, by id. | | `actions` | map of built-in rule id → `cut` \| `record` | `{}` | What a built-in rule does under `enforce`, written only where it differs from the factory setting (`rm-rf-root: record`). | @@ -911,24 +915,30 @@ Built-in rules: #### `security.content` -Words, patterns or characters in what the caller sends: user messages and -the tool results in them, not the system prompt or the model's own turns. -Each rule matches a keyword (`contains`), a regular expression (`regex`) or -code points (`codepoints`), and says what happens under `enforce`: `block` -refuses the request, `strip` deletes every match from the caller's text and -sends the rest, `record` only records it. After deleting, the text is checked -again, so a keyword split by hidden characters is caught once they are gone. +Words, patterns or characters in what the caller sends (user messages and +the tool results in them, not the system prompt or the model's own turns), +and, for custom rules with `response` in their `scope`, words or patterns in +the text of the answer. Each rule matches a keyword (`contains`), a regular +expression (`regex`) or code points (`codepoints`, requests only), and says +what happens under `enforce`: `block` refuses the request (requests only), +`strip` deletes every match and sends the rest, `replace` puts the rule's +`replacement` in place of every match and sends the rest, `record` only +records it. In a request, the text is checked again after deleting or +replacing, so a keyword split by hidden characters is caught once they are +gone; a replacement is not checked again. In an answer, what a rule deletes +or replaces never reaches the client, and the request record keeps the answer +the client received. | Field | Type | Default | Description | |---|---|---|---| -| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` does nothing; `observe` detects and records only, and changes nothing; `enforce` detects and acts. | +| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` does nothing (Off in the app); `observe` detects and records only, and changes nothing (Monitor); `enforce` detects and handles each match by its rule's action (On). | | `enable` | list of strings | `[]` | Built-in rules to switch on that are off out of the box, by id. | | `disable` | list of strings | `[]` | Built-in rules to switch off, by id. | -| `actions` | map of built-in rule id → `block` \| `strip` \| `record` | `{}` | What a built-in rule does under `enforce`, written only where it differs from the factory setting. | -| `custom` | list of [`security.content.custom[]`](#cfg-security-content-custom) | `[]` | Rules of your own. | +| `actions` | map of built-in rule id → `block` \| `strip` \| `replace` \| `record` | `{}` | What a built-in rule does under `enforce`, written only where it differs from the factory setting. Built-in rules check requests only; `replace` puts `***` in place of a match. | +| `custom` | list of [`security.content.custom[]`](#cfg-security-content-custom) | `[]` | Rules of your own, each checking requests, answers or both. | @@ -937,9 +947,12 @@ again, so a keyword split by hidden characters is caught once they are gone. | Field | Type | Default | Description | |---|---|---|---| | `name` | string | **required** | Name shown in logs and in the app; it identifies the rule and has to be unique within this guard. | -| `pattern` | string | **required** | A keyword; a regular expression with `match: regex`; code points with `match: codepoints` (`U+200B, U+E0000–U+E007F`). Keywords and regular expressions are case-insensitive. | -| `match` | `contains` \| `regex` \| `codepoints` | `contains` | `contains`: the text contains `pattern`. `regex`: `pattern` is a regular expression. `codepoints`: the text has a character among the code points or ranges listed in `pattern`, separated by commas. | -| `action` | `block` \| `strip` \| `record` | `record` | Under `enforce`: `block` the request, `strip` what matched and send the rest, or only `record` the match. | +| `pattern` | string | **required** | A keyword; a regular expression with `match: regex`; code points with `match: codepoints` (`U+200B, U+E0000–U+E007F`). | +| `scope` | list of `request` \| `response` | `[request]` | What the rule checks: `request` is what the caller sends (its messages and the tool results in them); `response` is the text of the answer the client sees, the input of free-form tools such as Codex's `apply_patch` included, and neither tool calls nor reasoning. Both may be listed. A streamed answer is never held back whole: only the last few characters that could still grow into a match wait for the next piece, at most one fewer than the longest keyword, and at most 256 for a regular expression; a match longer than that may have its beginning sent already. Under `enforce`, rules that delete hold back as many characters again: text that comes together where something was deleted is checked again, until no match is left. A match nested deeper than that may have its beginning sent already, and the rest of it is deleted. Under `enforce`, when any rule that checks answers deletes or replaces, logprobs are removed from streamed answers, and from a whole answer whose text changed, since they repeat the text token by token. A rule that checks answers cannot `block`, and cannot match by `codepoints`. | +| `match` | `contains` \| `regex` \| `codepoints` | `contains` | `contains`: the text contains `pattern` as written; characters such as `.` and `*` have no special meaning. `regex`: `pattern` is a regular expression. `codepoints`: the text has a character among the code points or ranges listed in `pattern`, separated by commas; requests only. | +| `case_sensitive` | bool | `false` | Tell capital letters from small ones. Off by default: `ABC` and `abc` both match. Code points are what they are either way. | +| `action` | `block` \| `strip` \| `replace` \| `record` | `record` | Under `enforce`: `block` the request (requests only), `strip` what matched and send the rest, `replace` what matched with `replacement` and send the rest, or only `record` the match. Text that comes together where something was stripped is checked again, until no match is left; a replacement is never checked again, and in an answer a regular expression anchored to the start or end of the text or of a line (`^`, `$`, `\A`, `\z`) is checked once. Replacing cannot be undone: the answer does not get the original back. | +| `replacement` | string | `"***"` | What `replace` puts in place of a match. | | `disabled` | bool | `false` | Switches the rule off and keeps it in the file. | @@ -1001,6 +1014,11 @@ security: - name: project-x pattern: project-x action: strip + - name: codename + pattern: polaris + scope: [request, response] + action: replace + replacement: "[codename]" ``` ### `retention` diff --git a/src/data/core-docs/config.zh-CN.md b/src/data/core-docs/config.zh-CN.md index 4021405..f038a2b 100644 --- a/src/data/core-docs/config.zh-CN.md +++ b/src/data/core-docs/config.zh-CN.md @@ -547,31 +547,32 @@ pricing: ### `security` -三项防护,对所有上游一视同仁。每一项都有 `mode`:`off`、`observe`(检测并记录,不改变任何行为)、`enforce`(处置)。出厂时三项都是 `observe`。各项在 `enforce` 下的处置不同:出站脱敏替换,工具调用审查切断响应,内容过滤按每条规则的处置拒绝、删除或只记录。 +三项防护,对所有上游一视同仁。每一项都有 `mode`:`off`、`observe`(检测并记录,不改变任何行为)、`enforce`(按每条规则的动作处理)。出厂时三项都是 `observe`。每条规则各有动作:出站脱敏替换为占位符或只记录,工具调用审查切断响应或只记录,内容过滤拒绝、删除、替换或只记录。 | 字段 | 类型 | 默认值 | 说明 | |---|---|---|---| -| `redact` | 对象,见 [`security.redact`](#cfg-security-redact) | — | 出站脱敏:请求发出前,把其中任何位置的凭据和个人信息替换掉。 | -| `inspect_tools` | 对象,见 [`security.inspect_tools`](#cfg-security-inspect_tools) | — | 工具调用审查:模型返回的工具调用中出现危险命令时切断响应。 | -| `content` | 对象,见 [`security.content`](#cfg-security-content) | — | 内容过滤:调用方发送的内容中出现指定的词、写法或字符(包括隐藏字符)时,按规则拒绝请求、删除命中的内容或只记录。 | +| `redact` | 对象,见 [`security.redact`](#cfg-security-redact) | — | 出站脱敏(应用里叫「密钥与隐私」):请求发出前,按每条规则把其中任何位置的凭据和个人信息替换为占位符,或只记录。 | +| `inspect_tools` | 对象,见 [`security.inspect_tools`](#cfg-security-inspect_tools) | — | 工具调用审查(应用里叫「危险命令」):模型返回的工具调用中出现危险命令时切断响应。 | +| `content` | 对象,见 [`security.content`](#cfg-security-content) | — | 内容过滤:调用方发送的内容中、或模型回答的正文中出现指定的词、写法或字符(包括隐藏字符)时,按规则拒绝请求、删除或替换命中的内容,或只记录。 | #### `security.redact` -请求发出前,在整个请求中(包括系统提示、之前的回答和工具调用)查找凭据和个人信息。`enforce` 下将其替换为占位符,回答中重复出现时再换回原值。图片、文件等 base64 内容不查,字段名也不查;自定义规则还不查协议要求原样保留的标识,如条目和调用的 id、类型、角色、工具名、模型名。 +请求发出前,在整个请求中(包括系统提示、之前的回答和工具调用)查找凭据和个人信息。`enforce` 下将规则找到的内容替换为占位符,回答中重复出现时再换回原值;`action: record` 的规则找到的内容原样发送,只作记录。图片、文件等 base64 内容不查,字段名也不查;自定义规则还不查协议要求原样保留的标识,如条目和调用的 id、类型、角色、工具名、模型名。 | 字段 | 类型 | 默认值 | 说明 | |---|---|---|---| -| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` 不检测;`observe` 检测并记录,不改变任何行为;`enforce` 检测并处置。 | +| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` 不检测(应用里叫「关闭」);`observe` 检测并记录,不改变任何行为(「监控」);`enforce` 检测并按每条规则的动作处理(「开启」)。 | | `enable` | 字符串列表 | `[]` | 打开出厂时关着的内置规则,按 id。 | | `disable` | 字符串列表 | `[]` | 关掉内置规则,按 id。 | -| `custom` | 对象列表,见 [`security.redact.custom[]`](#cfg-security-redact-custom) | `[]` | 自定义规则:匹配到的内容和凭据一样替换。 | +| `actions` | 映射: 内置规则 id → `placeholder` \| `record` | `{}` | 内置规则在 `enforce` 下的动作,只写与出厂不同的(`email: record`)。`placeholder` 将值替换为占位符后发送,回答中出现该占位符时还原为原值;`record` 原样发送,记录命中。 | +| `custom` | 对象列表,见 [`security.redact.custom[]`](#cfg-security-redact-custom) | `[]` | 自定义规则:匹配到的内容和凭据一样替换,或只记录。 | @@ -584,6 +585,7 @@ pricing: | `match` | `contains` \| `regex` | `contains` | `contains`:按原样查找 `pattern`,`.`、`*` 等字符没有特殊含义。`regex`:`pattern` 是正则表达式。 | | `case_sensitive` | 布尔 | `false` | 区分大小写。默认不区分:`ABC` 和 `abc` 都会匹配。 | | `label` | 字符串 | `SECRET` | 占位符名称:匹配到的内容替换为 `<>`,每个名称各自编号。只能使用大写字母、数字和下划线,以字母开头,最多 24 个字符。 | +| `action` | `placeholder` \| `record` | `placeholder` | `enforce` 下将匹配到的内容替换为占位符(`placeholder`),或只记录、原样发送(`record`)。 | | `disabled` | 布尔 | `false` | 停用这条规则,规则本身留在文件里。 | @@ -645,7 +647,7 @@ pricing: | 字段 | 类型 | 默认值 | 说明 | |---|---|---|---| -| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` 不检测;`observe` 检测并记录,不改变任何行为;`enforce` 检测并处置。 | +| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` 不检测(应用里叫「关闭」);`observe` 检测并记录,不改变任何行为(「监控」);`enforce` 检测并按每条规则的动作处理(「开启」)。 | | `enable` | 字符串列表 | `[]` | 打开出厂时关着的内置规则,按 id。 | | `disable` | 字符串列表 | `[]` | 关掉内置规则,按 id。 | | `actions` | 映射: 内置规则 id → `cut` \| `record` | `{}` | 内置规则在 `enforce` 下的处置,只写与出厂不同的(`rm-rf-root: record`)。 | @@ -685,18 +687,18 @@ pricing: #### `security.content` -调用方发送的内容中(用户消息及其中的工具结果,不含系统提示和模型自己的回答)出现的词、写法或字符。每条规则按关键词(`contains`)、正则(`regex`)或码位(`codepoints`)匹配,并写明 `enforce` 下的处置:`block` 拒绝请求,`strip` 把命中的内容从调用方的正文中全部删除后发出,`record` 只记录。删除之后会再检查一遍:被隐藏字符拆开的关键词,删掉隐藏字符后照样命中。 +调用方发送的内容中(用户消息及其中的工具结果,不含系统提示和模型自己的回答)出现的词、写法或字符;`scope` 含 `response` 的自定义规则还检查模型回答的正文。每条规则按关键词(`contains`)、正则(`regex`)或码位(`codepoints`,仅用于请求)匹配,并写明 `enforce` 下的动作:`block` 拒绝请求(仅用于请求),`strip` 删除全部命中的内容后发出,`replace` 将全部命中的内容替换为规则的 `replacement` 后发出,`record` 只记录。请求中删除或替换之后会再检查一遍:被隐藏字符拆开的关键词,删掉隐藏字符后照样命中;替换上去的文字不再检查。回答中删除或替换的内容不会送达客户端,请求记录中保存客户端实际收到的回答。 | 字段 | 类型 | 默认值 | 说明 | |---|---|---|---| -| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` 不检测;`observe` 检测并记录,不改变任何行为;`enforce` 检测并处置。 | +| `mode` | `off` \| `observe` \| `enforce` | `observe` | `off` 不检测(应用里叫「关闭」);`observe` 检测并记录,不改变任何行为(「监控」);`enforce` 检测并按每条规则的动作处理(「开启」)。 | | `enable` | 字符串列表 | `[]` | 打开出厂时关着的内置规则,按 id。 | | `disable` | 字符串列表 | `[]` | 关掉内置规则,按 id。 | -| `actions` | 映射: 内置规则 id → `block` \| `strip` \| `record` | `{}` | 内置规则在 `enforce` 下的处置,只写与出厂不同的。 | -| `custom` | 对象列表,见 [`security.content.custom[]`](#cfg-security-content-custom) | `[]` | 自定义规则。 | +| `actions` | 映射: 内置规则 id → `block` \| `strip` \| `replace` \| `record` | `{}` | 内置规则在 `enforce` 下的动作,只写与出厂不同的。内置规则只检查请求;`replace` 将命中的内容替换为 `***`。 | +| `custom` | 对象列表,见 [`security.content.custom[]`](#cfg-security-content-custom) | `[]` | 自定义规则,每条可检查请求、回答或两者。 | @@ -705,9 +707,12 @@ pricing: | 字段 | 类型 | 默认值 | 说明 | |---|---|---|---| | `name` | 字符串 | **必填** | 日志和应用里显示的名字,也是规则的标识;同一项防护里不能重名。 | -| `pattern` | 字符串 | **必填** | 关键词;`match: regex` 时为正则表达式;`match: codepoints` 时为码位(`U+200B, U+E0000–U+E007F`)。关键词和正则不区分大小写。 | -| `match` | `contains` \| `regex` \| `codepoints` | `contains` | `contains`:正文包含 `pattern`。`regex`:`pattern` 是正则表达式。`codepoints`:正文中出现 `pattern` 所列码位或码位范围内的字符,多个之间用逗号分隔。 | -| `action` | `block` \| `strip` \| `record` | `record` | `enforce` 下拒绝请求(`block`)、删除命中的内容后发出(`strip`),或只记录(`record`)。 | +| `pattern` | 字符串 | **必填** | 关键词;`match: regex` 时为正则表达式;`match: codepoints` 时为码位(`U+200B, U+E0000–U+E007F`)。 | +| `scope` | 列表,每项是 `request` \| `response` | `[request]` | 检查对象:`request` 为调用方发送的内容(用户消息及其中的工具结果);`response` 为客户端看到的回答正文,包含 Codex `apply_patch` 等自由格式工具的输入,不含工具调用与思考过程。两项可同时列出。流式回答不整体缓冲,只暂缓发送可能构成命中的末尾片段:「包含」规则不超过最长匹配内容的字符数减一,正则规则最多 256 个字符;超过此长度的正则命中,其起始部分可能已送达客户端。`enforce` 下有删除内容的规则时,再多暂缓同样多的字符:删除处前后拼接成的文字重新检查,直到不再有命中。嵌套层数超出暂缓范围的命中,其起始部分可能已送达客户端,其余部分删除。`enforce` 下有检查回答的规则删除或替换内容时,流式回答中的 logprobs 一律去掉,非流式回答在正文有改动时去掉:logprobs 按 token 重复了正文。检查回答的规则不能用 `block`,也不能按 `codepoints` 匹配。 | +| `match` | `contains` \| `regex` \| `codepoints` | `contains` | `contains`:正文按原样包含 `pattern`,`.`、`*` 等字符没有特殊含义。`regex`:`pattern` 是正则表达式。`codepoints`:正文中出现 `pattern` 所列码位或码位范围内的字符,多个之间用逗号分隔;仅用于请求。 | +| `case_sensitive` | 布尔 | `false` | 区分大小写。默认不区分:`ABC` 和 `abc` 都会匹配。码位不受此项影响。 | +| `action` | `block` \| `strip` \| `replace` \| `record` | `record` | `enforce` 下拒绝请求(`block`,仅用于请求)、删除命中的内容后发出(`strip`)、将命中的内容替换为 `replacement` 后发出(`replace`),或只记录(`record`)。删除处前后拼接成的文字重新检查,直到不再有命中;替换上的文字不再检查;回答中锚定正文或行首尾的正则(`^`、`$`、`\A`、`\z`)只检查一次。替换不可还原,回答中不换回原文。 | +| `replacement` | 字符串 | `"***"` | 动作为 `replace` 时替换成的文字。 | | `disabled` | 布尔 | `false` | 停用这条规则,规则本身留在文件里。 | @@ -764,6 +769,11 @@ security: - name: project-x pattern: project-x action: strip + - name: codename + pattern: polaris + scope: [request, response] + action: replace + replacement: "[codename]" ``` ### `retention` diff --git a/src/data/core-docs/manifest.json b/src/data/core-docs/manifest.json index 52b9db5..2fd8726 100644 --- a/src/data/core-docs/manifest.json +++ b/src/data/core-docs/manifest.json @@ -1,9 +1,9 @@ { "repository": "ThinkWatchProject/ThinkWatch-Core", - "ref": "v0.71.0", + "ref": "v0.73.0", "files": { - "docs/config.md": "78a0133f0351e44c164261cc9ed7b2239360243c5b6bcbd807996dd7ae50c436", - "docs/config.zh-CN.md": "a9f2ad1f11adf2e3582692933d915f3e8ce6f955bebf9d675453b376e5910ee8", + "docs/config.md": "986aa44925c1d0e4143c35d19a9b233ae831352df0cb0ebb1f5e1948a3db2a3b", + "docs/config.zh-CN.md": "8337946ff902c365f02ff3c11fbd97c62f3458b42ba428f5d49cc7a797ffb9dc", "docs/server.md": "5e1e9b901bef2b46d417aea057a1db24c78457d3c1938b8540ecb4766515b68f", "docs/server.zh-CN.md": "1f508e7c39b8ded28653773ca4d8701e6bdc2247bcd359c3a8fd00fd1401a6ff" } diff --git a/src/i18n/index.ts b/src/i18n/index.ts index bbf0cbc..d532308 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -117,7 +117,7 @@ const dict = { { title: "Custom roles and SSO/OIDC", body: "Five built-in roles, from Super Admin to Viewer, and any number of custom roles. A new role can start from an existing one, its policy can be edited as JSON in the console, and every change is kept in the role's history. A role can also be granted for a single team. Sign-in works with Zitadel, Okta, Azure AD, or any OIDC provider, with optional TOTP." }, { title: "AES-256-GCM at rest", body: "Provider keys, MCP tokens, and other upstream secrets are encrypted at rest with AES-256-GCM. Virtual API keys are stored as HMAC-SHA256 hashes, and the plaintext is shown only once." }, { title: "HttpOnly cookie sessions", body: "Access and refresh tokens are stored in HttpOnly cookies, which JavaScript cannot read. Each console session also signs its requests with a key bound to the IP address it signed in from, so a stolen cookie cannot be replayed from a different network." }, - { title: "Request guards", body: "Credentials and personal information can be replaced with placeholders before a request goes upstream and restored in the answer, and a tool call that downloads and runs code or sends out credentials can be cut off before the client runs it. A content filter can refuse prompt injection or delete hidden characters by rule; every guard starts in observe mode, and its rules can be tried out in the console." }, + { title: "Request guards", body: "Credentials and personal information can be replaced with placeholders before a request goes upstream and restored in the answer, and a tool call that downloads and runs code or sends out credentials can be cut off before the client runs it. A content filter can refuse prompt injection, delete hidden characters, and delete or replace chosen words in requests and answers. Every guard starts in Monitor, which only records; each rule has its own action and can be tried out in the console." }, { title: "Distroless containers", body: "The server image holds one statically linked binary on a distroless base, with no shell. The server refuses to start with a JWT secret shorter than 32 characters, and deleted users, keys, and providers are purged after 30 days." }, { title: "Model allowlists on every API", body: "A request may use only the models allowed by both the API key's allowlist and the user's roles. The same check applies to OpenAI Chat Completions, OpenAI Responses, Anthropic Messages, and Gemini requests, so no API bypasses it." }, ], @@ -133,7 +133,7 @@ const dict = { { title: "Health & readiness", body: "/health/live, /health/ready (which checks PostgreSQL, Redis, ClickHouse, and at least one active provider), and /api/health with per-dependency latency and connection-pool statistics." }, { title: "Unified log explorer", body: "Search audit, gateway, MCP, access, and application logs from a single page. Each cell offers buttons to filter on or exclude its value, -key:value excludes a value in the query, and the query is kept in the URL." }, { title: "Live dashboard", body: "The console overview receives live data over a WebSocket: requests per minute, each provider's latency, success rate, and circuit-breaker state, the most active users, and the latest requests, without a page refresh." }, - { title: "Full-body audit capture", body: "By default, request and response bodies of gateway calls, and the arguments and results of MCP tool calls, are stored in ClickHouse with each log row, compressed and kept for their own retention period. Bodies can be redacted with the outbound redaction rules before they are stored. Bodies above the inline size limit are moved to S3-compatible storage such as MinIO or the bundled RustFS. Auditors read bodies in the log detail panel or search across them; access requires the separate logs:read_bodies permission." }, + { title: "Full-body audit capture", body: "By default, request and response bodies of gateway calls, and the arguments and results of MCP tool calls, are stored in ClickHouse with each log row, compressed and kept for their own retention period. Bodies can be redacted with the Secrets & privacy rules before they are stored. Bodies above the inline size limit are moved to S3-compatible storage such as MinIO or the bundled RustFS. Auditors read bodies in the log detail panel or search across them; access requires the separate logs:read_bodies permission." }, ], }, { @@ -349,7 +349,7 @@ const dict = { { title: "自定义角色 + SSO/OIDC", body: "内置从超级管理员到只读用户共五个角色,并可创建任意数量的自定义角色。新角色可从现有角色复制起步,权限策略可在控制台中以 JSON 编辑,每次修改都保留在角色的变更历史中。角色也可仅针对某一团队授予。登录支持 Zitadel、Okta、Azure AD 或任意 OIDC Provider,可选 TOTP 二次验证。" }, { title: "AES-256-GCM 静态加密", body: "Provider 密钥、MCP 令牌及其他上游凭据以 AES-256-GCM 加密存储。虚拟 API 密钥以 HMAC-SHA256 哈希存储,明文只展示一次。" }, { title: "HttpOnly Cookie 会话", body: "访问令牌和刷新令牌均存储在 HttpOnly Cookie 中,JavaScript 无法读取。每个控制台会话还会用一把绑定登录时 IP 地址的密钥为请求签名,被盗的 Cookie 无法在其他网络中重放。" }, - { title: "请求防护", body: "凭据和个人信息可在请求发往上游前替换为占位符,并在回答中还原;下载即执行、外发凭据之类的工具调用可在客户端执行前切断。内容过滤可按规则拒绝提示注入或删除隐藏字符;各项防护出厂为观察档,规则可在控制台中试用。" }, + { title: "请求防护", body: "凭据和个人信息可在请求发往上游前替换为占位符,并在回答中还原;下载即执行、外发凭据之类的工具调用可在客户端执行前切断。内容过滤可按规则拒绝提示注入、删除隐藏字符,或删除、替换请求与回答中的指定词语。各项防护出厂为「监控」,只作记录;每条规则可单独设定动作,并可在控制台中试用。" }, { title: "Distroless 容器", body: "服务端镜像只包含一个静态链接的二进制程序,基于 distroless 基础镜像,不含 shell。JWT 密钥短于 32 个字符时服务端拒绝启动;已删除的用户、密钥与 Provider 在 30 天后彻底清除。" }, { title: "模型白名单覆盖全部 API", body: "请求只能使用同时被 API 密钥白名单与用户角色允许的模型。该检查对 OpenAI Chat Completions、OpenAI Responses、Anthropic Messages 与 Gemini 请求一致生效,任何 API 均无法绕过。" }, ], @@ -365,7 +365,7 @@ const dict = { { title: "健康与就绪", body: "/health/live、/health/ready(检查 PostgreSQL、Redis、ClickHouse 以及至少一个启用的 Provider),以及提供各依赖延迟与连接池统计的 /api/health。" }, { title: "统一日志检索", body: "在同一页面搜索审计、网关、MCP、访问与应用日志。每个单元格提供按其值筛选或排除的按钮,查询中可用 -key:value 排除指定值,查询条件保存在 URL 中。" }, { title: "实时看板", body: "控制台总览通过 WebSocket 接收实时数据:每分钟请求数,各 Provider 的延迟、成功率与熔断状态,最活跃的用户以及最新请求,无需刷新页面。" }, - { title: "全量请求 / 响应体审计", body: "默认情况下,网关调用的请求体与响应体、MCP 工具调用的参数与结果,随每条日志一并存入 ClickHouse,压缩存储并单独设置保留期限。可在写入前按出站脱敏的规则脱敏。超过内联大小上限的内容转存到 S3 兼容存储,如 MinIO 或内置的 RustFS。审计员可在日志详情面板中查看,也可跨日志搜索;查看需要单独的 logs:read_bodies 权限。" }, + { title: "全量请求 / 响应体审计", body: "默认情况下,网关调用的请求体与响应体、MCP 工具调用的参数与结果,随每条日志一并存入 ClickHouse,压缩存储并单独设置保留期限。可在写入前按「密钥与隐私」的规则脱敏。超过内联大小上限的内容转存到 S3 兼容存储,如 MinIO 或内置的 RustFS。审计员可在日志详情面板中查看,也可跨日志搜索;查看需要单独的 logs:read_bodies 权限。" }, ], }, { diff --git a/src/i18n/pages/core.ts b/src/i18n/pages/core.ts index f62ee83..921cdee 100644 --- a/src/i18n/pages/core.ts +++ b/src/i18n/pages/core.ts @@ -58,7 +58,7 @@ export const coreCopy = { }, { title: "Malicious tool calls cut off", - body: "A relay can rewrite an answer and slip in a tool call for the client to run; a call that downloads and runs code, sends out credentials or does something similar can be cut off mid-stream. A content filter can also delete hidden characters that smuggle in instructions, and all three guards start by only recording.", + body: "A relay can rewrite an answer and slip in a tool call for the client to run; a call that downloads and runs code, sends out credentials or does something similar can be cut off mid-stream. A content filter can also delete hidden characters that smuggle in instructions, and delete or replace chosen words in answers. All three guards start by only recording, and every rule has its own action.", }, { title: "Encrypted control plane", @@ -182,7 +182,7 @@ export const coreCopy = { }, { title: "切断恶意工具调用", - body: "中转站可以改写回答,塞入让客户端执行的工具调用;下载即执行、外发凭据之类的危险调用可在流式传输中途切断。内容过滤还可删除夹带指令的隐藏字符,三项防护出厂均只记录。", + body: "中转站可以改写回答,塞入让客户端执行的工具调用;下载即执行、外发凭据之类的危险调用可在流式传输中途切断。内容过滤还可删除夹带指令的隐藏字符,删除或替换回答中的指定词语。三项防护出厂均只记录,每条规则可单独设定动作。", }, { title: "加密的控制面", diff --git a/src/i18n/pages/lite.ts b/src/i18n/pages/lite.ts index 4ac2c42..ade3ed6 100644 --- a/src/i18n/pages/lite.ts +++ b/src/i18n/pages/lite.ts @@ -42,7 +42,7 @@ export const liteCopy = { aria: "Illustration: requests passing through the gateway, in turn a request whose key is replaced, one whose upstream fails and is replaced by the next, and one whose dangerous tool call is cut off", scenes: [ { - checks: [["Routing", "main → anthropic"], ["Outbound redaction", "1 credential"], ["Tool-call inspection", "passed"], ["Cost", "$0.0124"]], + checks: [["Routing", "main → anthropic"], ["Secrets & privacy", "1 credential"], ["Dangerous commands", "passed"], ["Cost", "$0.0124"]], log: [ "claude-code POST /v1/messages · claude-sonnet-5", "rule main matched, sent to anthropic", @@ -62,7 +62,7 @@ export const liteCopy = { ], }, { - checks: [["Routing", "budget → relay"], ["Outbound redaction", "2 credentials"], ["Tool-call inspection", "cut off"], ["Cost", "$0.0032"]], + checks: [["Routing", "budget → relay"], ["Secrets & privacy", "2 credentials"], ["Dangerous commands", "cut off"], ["Cost", "$0.0032"]], log: [ "cursor POST /v1/chat/completions · claude-sonnet-5", "rule budget matched, sent to relay", @@ -124,7 +124,7 @@ export const liteCopy = { { id: "security", title: "Protection against relays: keys replaced, malicious tool calls cut off", - body: "API keys, private keys, connection-string passwords, ID numbers and bank card numbers can be replaced with placeholders before a request leaves, so a relay never holds the real values, and an answer whose tool call downloads and runs code or sends out credentials can be cut off before the client runs it. Hidden characters that smuggle in instructions can be deleted and prompt injection refused; the three protections start in Observe, recording without changing anything, and each switches to Replace, Cut off or Enforce on its own.", + body: "API keys, private keys, connection-string passwords, ID numbers and bank card numbers can be replaced with placeholders before a request leaves, so a relay never holds the real values, and an answer whose tool call downloads and runs code or sends out credentials can be cut off before the client runs it. Hidden characters that smuggle in instructions can be deleted, prompt injection refused, and chosen words deleted or replaced in requests and answers. The three protections start in Monitor, which records and notifies without changing anything; each is switched on separately, and every rule has its own action.", alt: "The Security page log: credentials replaced before a request left, one of them matched by a custom rule; a download-and-run tool call cut off; and hidden characters, a delete command and an injected instruction recorded, each with the key, client, model and upstream of its request", }, { @@ -295,7 +295,7 @@ export const liteCopy = { aria: "示意:请求经过网关,依次展示密钥被替换的请求、上游出错时换用下一个上游的请求,以及危险工具调用被切断的请求", scenes: [ { - checks: [["路由", "main → anthropic"], ["出站脱敏", "1 处凭据"], ["工具调用审查", "通过"], ["记账", "$0.0124"]], + checks: [["路由", "main → anthropic"], ["密钥与隐私", "1 处凭据"], ["危险命令", "通过"], ["记账", "$0.0124"]], log: [ "claude-code POST /v1/messages · claude-sonnet-5", "命中规则 main,交给 anthropic", @@ -315,7 +315,7 @@ export const liteCopy = { ], }, { - checks: [["路由", "budget → relay"], ["出站脱敏", "2 处凭据"], ["工具调用审查", "已切断"], ["记账", "$0.0032"]], + checks: [["路由", "budget → relay"], ["密钥与隐私", "2 处凭据"], ["危险命令", "已切断"], ["记账", "$0.0032"]], log: [ "cursor POST /v1/chat/completions · claude-sonnet-5", "命中规则 budget,交给 relay", @@ -367,7 +367,7 @@ export const liteCopy = { { id: "security", title: "防范中转站:替换密钥,切断恶意工具调用", - body: "API 密钥、私钥、连接串口令、身份证号与银行卡号可在请求发出前换成占位符,中转站拿不到原值;回答中的工具调用若是下载即执行或外发凭据,可在客户端执行之前切断。夹带指令的隐藏字符可以删除,提示注入可以拒绝;三项防护出厂只记录、不改动请求,可逐项切换到「替换」「切断」或「处置」。", + body: "API 密钥、私钥、连接串口令、身份证号与银行卡号可在请求发出前换成占位符,中转站拿不到原值;回答中的工具调用若是下载即执行或外发凭据,可在客户端执行之前切断。夹带指令的隐藏字符可以删除,提示注入可以拒绝,请求和回答中的指定词语可以删除或替换。三项防护出厂为「监控」,只记录并发出通知、不改动内容;各项单独开启,每条规则可单独设定动作。", alt: "安全页日志:请求发出前替换的凭据(其中一条由自定义规则命中)、被切断的下载即执行工具调用,以及记录在案的隐藏字符、删除命令与注入指令,每条都注明所属请求的密钥、客户端、模型与上游", }, {