Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ Documentation: [configuration reference](docs/config.md) ·
- **Malicious tool calls are cut off.** A relay can rewrite an answer and slip
in a tool call for the client to run. Tool-call inspection can cut off an
answer whose tool call downloads and runs code, sends out environment
variables or credential files, reads private keys, or installs a startup item
or scheduled job, before the client receives it whole.
variables or credential files, reads private keys, reads or changes
ThinkWatch's own configuration, or installs a startup item or scheduled job,
before the client receives it whole.
- **Hidden instructions are removed.** Characters invisible on screen can carry
instructions that a model reads; the content filter can delete them from user
messages and tool results before a request leaves, or refuse a request that
Expand Down Expand Up @@ -110,7 +111,11 @@ each with a `.sha256` checksum; the Linux `.tar.gz` includes the systemd unit.

`twcore` keeps its configuration and data in `~/.thinkwatch`
(`%APPDATA%\ThinkWatch` on Windows), or in `THINKWATCH_HOME`. Every field is in
the [configuration reference](docs/config.md).
the [configuration reference](docs/config.md). The configuration 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. [Where the file is](docs/config.md#where-the-file-is)
describes what protects it.

## Control plane

Expand Down
4 changes: 2 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ ThinkWatch Core 是 ThinkWatch 的网关引擎,由一组 Rust crate 及其构

- **一次接入,随时切换**。客户端只保留一个地址和一把密钥,更换上游或模型都在网关中完成,客户端无需改配置或重启。Anthropic Messages、OpenAI Chat Completions、OpenAI Responses 与 Gemini 四种格式双向转换,流式输出同样适用。
- **出站脱敏**。出站脱敏可在请求发出前把 API 密钥、私钥和连接串中的口令替换为占位符,并在回答回显时还原,中转站因此看不到真实的值。
- **切断恶意工具调用**。中转站可以改写回答,塞入让客户端执行的工具调用。回答中的工具调用若是下载即执行、外发环境变量或凭据文件、读取私钥、写入开机启动项或定时任务,工具调用审查可以在客户端收到完整调用之前切断回答。
- **切断恶意工具调用**。中转站可以改写回答,塞入让客户端执行的工具调用。回答中的工具调用若是下载即执行、外发环境变量或凭据文件、读取私钥、读写 ThinkWatch 自己的配置、写入开机启动项或定时任务,工具调用审查可以在客户端收到完整调用之前切断回答。
- **清除隐藏指令**。屏幕上看不见的字符可以夹带模型会读取的指令,内容过滤可以在请求发出前把它们从用户消息和工具结果中删除,也可以拒绝要求模型忽略自身指令的请求。出站脱敏、工具调用审查和内容过滤出厂均为观察档,只记录检出的内容,不改变任何请求。
- **每个请求都可追溯**。每个请求连同决定其去向的规则、每次尝试、格式转换、用量、费用及价格来源、首 token 时间和生成速度一并保存。试算可以在不发出请求的情况下说明请求会被送往何处;已保存的请求可以对另一个上游重放,以便对比。
- **路由与故障转移**。规则可按模型、密钥、格式、请求大小、工具、图片、思考等条件匹配,把请求交给一个上游或策略组(按顺序、手动指定、轮流、最低延迟、最低价格)。响应的首字节到达客户端之前,失败的上游由下一个候选替换,并按其给出的失败原因暂停相应的时间。
Expand Down Expand Up @@ -58,7 +58,7 @@ twc control-key # 标准输出是 ThinkWatch Lite 所

**预编译二进制**:每个 [Release](https://github.com/ThinkWatchProject/ThinkWatch-Core/releases/latest) 都提供 macOS(Apple silicon)、Windows(x64、ARM64)和 Linux(x86_64、aarch64)版本,均附 `.sha256` 校验文件;Linux 的 `.tar.gz` 包含 systemd 服务单元。

`twcore` 的配置和数据存放在 `~/.thinkwatch`(Windows 上为 `%APPDATA%\ThinkWatch`),设置了 `THINKWATCH_HOME` 时存放在它指定的目录。每个字段的说明见[配置手册](docs/config.zh-CN.md)。
`twcore` 的配置和数据存放在 `~/.thinkwatch`(Windows 上为 `%APPDATA%\ThinkWatch`),设置了 `THINKWATCH_HOME` 时存放在它指定的目录。每个字段的说明见[配置手册](docs/config.zh-CN.md)。配置以明文保存密钥,只有所有者可读:挡得住其他用户,挡不住以同一用户身份运行的程序;出站脱敏保护的是带出本机的内容,不是这份文件。它受什么保护,见配置手册的[文件位置](docs/config.zh-CN.md#文件位置)一节。

## 控制面

Expand Down
9 changes: 9 additions & 0 deletions crates/tw-guard/data/rules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ dangerous:
why: Sends a credential to a host that is neither local nor the credential's own provider
level: high
check: credential-to-network
# ThinkWatch 自己的数据目录:里面是明文的全部上游密钥和这几项防护的设置。读它一步就
# 拿走全部凭据,改它就能关掉管着自己的防护 —— 高危。**提到这个路径不算**(改文档、
# 回答「配置在哪」),只看路径和命令参数,所以由代码实现,见 src/tools/own_data.rs。
- id: thinkwatch-data
name: Read or change ThinkWatch's own data
pattern: ''
why: Reads or changes ThinkWatch's data directory, which holds every upstream key in plain text and the settings of these protections
level: high
check: thinkwatch-data
# **写入启动项**:只要写进去了,下次开终端就执行 —— 而且是在你完全
# 不知情的时候。它和「下载即执行」并列为高危,理由是一样的:
# 一步就能拿到执行权。
Expand Down
1 change: 1 addition & 0 deletions crates/tw-guard/src/tools/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! 工具调用审查:上游返回的工具调用过一遍规则,高危的可以在那一帧上切断。

pub mod net;
mod own_data;
pub mod rules;
pub mod wall;
7 changes: 6 additions & 1 deletion crates/tw-guard/src/tools/net.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! 工具调用审查里两条**代码实现**的危险命令规则。
//! 工具调用审查里**代码实现**的危险命令规则:这里的两条,和 [`super::own_data`] 那一条。
//!
//! 正则认不出这两件事,因为判断要跨工具调用的参数、把几样东西凑到一起看:
//!
Expand All @@ -25,6 +25,8 @@ pub enum Check {
CredentialToNetwork,
/// 把本地文件的内容上传到外部主机
FileToNetwork,
/// 读写 ThinkWatch 自己的数据目录([`super::own_data`])
OwnData,
}

impl Check {
Expand All @@ -33,12 +35,14 @@ impl Check {
match self {
Check::CredentialToNetwork => "credential-to-network",
Check::FileToNetwork => "file-to-network",
Check::OwnData => "thinkwatch-data",
}
}
pub fn from_slug(s: &str) -> Option<Self> {
match s {
"credential-to-network" => Some(Check::CredentialToNetwork),
"file-to-network" => Some(Check::FileToNetwork),
"thinkwatch-data" => Some(Check::OwnData),
_ => None,
}
}
Expand All @@ -51,6 +55,7 @@ impl Check {
match self {
Check::CredentialToNetwork => credential_to_network(args),
Check::FileToNetwork => file_to_network(args),
Check::OwnData => super::own_data::find(args),
}
}
}
Expand Down
Loading
Loading