Skip to content

Commit db33f44

Browse files
authored
feat(plugins): release Copilot SDK Pipe v0.8.0 and Files Filter v0.1.3 (#50)
* feat(plugins): release copilot sdk pipe v0.8.0 and files filter v0.1.3 - Add P1~P4 conditional tool filtering and admin/server gating behavior - Fix artifact publishing reliability, strict /api file URLs, and HTML preview/download delivery - Update bilingual README/docs, release notes, and filter matching/debug improvements * fix(docs): remove duplicate code block in tool-filtering zh doc - Remove incorrectly placed duplicate 'if not is_enabled: continue' block outside code fence on line 161-163 of copilot-sdk-tool-filtering.zh.md - Addresses review comment from gemini-code-assist (#50)
1 parent 5b6dddd commit db33f44

20 files changed

+1175
-247
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ A collection of enhancements, plugins, and prompts for [OpenWebUI](https://githu
3535

3636
| Status | Plugin | Version | Downloads | Views | 📅 Updated |
3737
| :---: | :--- | :---: | :---: | :---: | :---: |
38-
| 🆕 | [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | ![v](https://img.shields.io/badge/v-0.7.0-blue?style=flat) | ![copilot_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_dl.json&style=flat) | ![copilot_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--02--23-blue?style=flat) |
38+
| 🆕 | [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | ![v](https://img.shields.io/badge/v-0.8.0-blue?style=flat) | ![copilot_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_dl.json&style=flat) | ![copilot_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--02--25-blue?style=flat) |
3939

4040
### 📈 Total Downloads Trend
4141

README_CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
3232

3333
| 状态 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 |
3434
| :---: | :--- | :---: | :---: | :---: | :---: |
35-
| 🆕 | [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | ![v](https://img.shields.io/badge/v-0.7.0-blue?style=flat) | ![copilot_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_dl.json&style=flat) | ![copilot_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--02--23-blue?style=flat) |
35+
| 🆕 | [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | ![v](https://img.shields.io/badge/v-0.8.0-blue?style=flat) | ![copilot_dl](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_dl.json&style=flat) | ![copilot_vw](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_post_aef940e01073e811a311c3a443d9c149_vw.json&style=flat) | ![updated](https://img.shields.io/badge/2026--02--25-blue?style=flat) |
3636

3737
### 📈 总下载量累计趋势
3838

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# GitHub Copilot SDK Tool Filtering Logic Documentation
2+
3+
## Overview
4+
5+
The tool filtering logic ensures that changes made in the **OpenWebUI admin panel take effect on the very next chat message** — no restart or cache flush required. The design balances three goals: administrator control, user autonomy, and built-in feature availability.
6+
7+
## Priority Hierarchy
8+
9+
Filtering is applied top-to-bottom. A higher layer can fully block a lower one:
10+
11+
| Priority | Layer | Controls |
12+
|---|---|---|
13+
| 1 (Highest) | **Plugin Valve toggles** | `ENABLE_OPENWEBUI_TOOLS`, `ENABLE_MCP_SERVER`, `ENABLE_OPENAPI_SERVER` — category master switches |
14+
| 2 | **Admin backend server toggle** | Per-server `config.enable` in OpenWebUI Connections panel — blocks specific servers |
15+
| 3 (Lowest) | **User Chat menu selection** | `tool_ids` from the chat UI — selects which enabled items to use |
16+
17+
---
18+
19+
## Core Decision Logic (Flowchart)
20+
21+
```mermaid
22+
graph TD
23+
A[New message arrives] --> V{Plugin Valve enabled\nfor this category?}
24+
V -- No --> VX[Drop all tools in this category]
25+
V -- Yes --> B{Admin backend:\nconfig.enable = True?}
26+
B -- No --> C[Skip this server]
27+
B -- Yes --> F{Built-in or Custom/Server tool?}
28+
29+
F -- Built-in --> G{Any builtin: IDs\nselected in Chat?}
30+
G -- Yes --> H[Enable ONLY the mapped categories\nunselected categories set to False]
31+
G -- No --> I[Enable default 4 categories:\nweb_search, image_generation,\ncode_interpreter, memory]
32+
33+
F -- Custom / Server --> J{Any custom IDs\nselected in Chat?}
34+
J -- Yes --> K[Load ONLY the selected IDs]
35+
J -- No --> L[Load ALL admin-enabled custom tools]
36+
37+
H & I & K & L --> M[Always inject: publish_file_from_workspace]
38+
M --> N[Start / Resume Copilot SDK Session]
39+
```
40+
41+
---
42+
43+
## Scenario Reference Table
44+
45+
| User selects in Chat | Custom tools loaded | Built-in tools loaded |
46+
|---|---|---|
47+
| Nothing | All admin-enabled | Default 4 (search, image, code, memory) |
48+
| Only `builtin:xxx` | All admin-enabled (unaffected) | Only selected categories |
49+
| Only custom/server IDs | Only selected IDs | Default 4 |
50+
| Both builtin and custom | Only selected custom IDs | Only selected builtin categories |
51+
52+
---
53+
54+
## Technical Implementation Details
55+
56+
### 1. Real-time Admin Sync (No Caching)
57+
58+
Every request re-reads `TOOL_SERVER_CONNECTIONS.value` live. There is **no in-memory cache** for server state. As a result:
59+
60+
- Enable a server in the admin panel → it appears on the **next message**.
61+
- Disable a server → it is dropped on the **next message**.
62+
63+
```python
64+
# Read live on every request — no cache
65+
if hasattr(TOOL_SERVER_CONNECTIONS, "value"):
66+
raw_connections = TOOL_SERVER_CONNECTIONS.value
67+
68+
for server in connections:
69+
is_enabled = config.get("enable", False) # checked per-server, per-request
70+
if not is_enabled:
71+
continue # skipped immediately — hard block
72+
```
73+
74+
### 2. Built-in Tool Category Mapping
75+
76+
The plugin maps individual `builtin:func_name` IDs to one of 9 categories understood by `get_builtin_tools`. When the user selects specific builtins, **only those categories are enabled; unselected categories are explicitly set to `False`** (not omitted) to prevent OpenWebUI's default-`True` fallback:
77+
78+
```python
79+
if builtin_selected:
80+
# Strict mode: set every category explicitly
81+
for cat in all_builtin_categories: # all 9
82+
is_enabled = cat in enabled_categories # only selected ones are True
83+
builtin_tools_meta[cat] = is_enabled # unselected are explicitly False
84+
else:
85+
# Default mode: only the 4 core categories
86+
default_builtin_categories = [
87+
"web_search", "image_generation", "code_interpreter", "memory"
88+
]
89+
for cat in all_builtin_categories:
90+
builtin_tools_meta[cat] = cat in default_builtin_categories
91+
features.update(req_features) # merge backend feature flags
92+
```
93+
94+
### 3. Custom Tool "Select-All" Fallback
95+
96+
The whitelist is activated **only when the user explicitly selects custom/server IDs**. Selecting only `builtin:` IDs does not trigger the custom whitelist, so all admin-enabled servers remain accessible:
97+
98+
```python
99+
# custom_selected contains only non-builtin: IDs
100+
if custom_selected:
101+
# Whitelist active: keep only what the user picked
102+
tool_ids = [tid for tid in available_ids if tid in custom_selected]
103+
else:
104+
# No custom selection: load everything enabled in backend
105+
tool_ids = available_ids
106+
```
107+
108+
The same rule applies to MCP servers in `_parse_mcp_servers`.
109+
110+
### 4. Admin Backend Strict Validation
111+
112+
Applied uniformly to both OpenAPI and MCP servers, handling both dict and Pydantic object shapes:
113+
114+
```python
115+
is_enabled = False
116+
config = server.get("config", {}) if isinstance(server, dict) else getattr(server, "config", {})
117+
is_enabled = config.get("enable", False) if isinstance(config, dict) else getattr(config, "enable", False)
118+
119+
if not is_enabled:
120+
continue # hard skip — no user or valve setting can override this
121+
```
122+
123+
## Important Notes
124+
125+
- **SDK Internal Tools**: `available_tools = None` is passed to the session so SDK-native capabilities (`read_file`, `shell`, etc.) are never accidentally blocked by the custom tool list.
126+
- **Persistent Tool**: `publish_file_from_workspace` is always injected after all filtering — it is required for the file delivery workflow regardless of any toggle.
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# GitHub Copilot SDK 工具过滤逻辑开发文档
2+
3+
## 核心需求
4+
5+
**管理员在后台修改工具服务的启用状态后,用户发送下一条消息时立即生效,无需重启服务或刷新缓存。**
6+
7+
过滤逻辑同时兼顾两个目标:管理员管控权、用户自主选择权。内置工具则完全独立,仅由模型配置决定。
8+
9+
---
10+
11+
## 工具分类说明
12+
13+
本文档涉及两类完全独立的工具,权限控制机制不同:
14+
15+
| 工具类型 | 说明 | 权限控制来源 |
16+
|---|---|---|
17+
| **内置工具(Builtin Tools)** | OpenWebUI 原生能力:时间、知识库、记忆、联网搜索、图像生成、代码解释器等 | 仅由模型配置 `meta.builtinTools` 决定,**与 Chat 前端选择无关** |
18+
| **OpenWebUI Tools** | 用户安装的 Python 工具插件 | 插件 Valve + Chat 工具选择(tool_ids) |
19+
| **工具服务器(OpenAPI / MCP)** | 外部 OpenAPI Server、MCP Server | 插件 Valve + 管理员 `config.enable` + `function_name_filter_list` + Chat 工具选择(tool_ids) |
20+
21+
---
22+
23+
## 内置工具权限控制(模型配置驱动,与前端无关)
24+
25+
内置工具**完全由模型配置决定**,Chat 界面的工具选择对其没有任何影响。
26+
27+
### 模型 `meta.builtinTools` 字段
28+
29+
在模型(自定义模型或基础模型)的 `meta` 字段中有一个可选的 `builtinTools` 对象:
30+
31+
```json
32+
{
33+
"meta": {
34+
"capabilities": { "builtin_tools": true },
35+
"builtinTools": {
36+
"time": false,
37+
"memory": true,
38+
"chats": true,
39+
"notes": true,
40+
"knowledge": true,
41+
"channels": true,
42+
"web_search": true,
43+
"image_generation": true,
44+
"code_interpreter": true
45+
}
46+
}
47+
}
48+
```
49+
50+
**判定规则(源码 `utils/tools.py`):**
51+
52+
```python
53+
def is_builtin_tool_enabled(category: str) -> bool:
54+
builtin_tools = model.get("info", {}).get("meta", {}).get("builtinTools", {})
55+
return builtin_tools.get(category, True) # 缺省时默认 True
56+
```
57+
58+
- `builtinTools` 字段**不存在** → 所有内置工具类别默认全部开启
59+
- `builtinTools` 字段**存在** → 仅值为 `true` 的类别开启,其余关闭
60+
61+
---
62+
63+
## OpenWebUI Tools 和工具服务器的优先级层级
64+
65+
这两类工具的过滤从上到下依次执行,**受 Chat 前端选择影响**
66+
67+
| 优先级 | 层级 | 控制范围 |
68+
|---|---|---|
69+
| 1(最高) | **插件 Valve 开关** | `ENABLE_OPENWEBUI_TOOLS` / `ENABLE_MCP_SERVER` / `ENABLE_OPENAPI_SERVER` — 类别总开关 |
70+
| 2 | **管理员后端服务器开关** | OpenWebUI 连接面板中每个服务器的 `config.enable` — 控制具体服务器是否启用 |
71+
| 3 | **管理员函数名过滤列表** | 工具服务器 `config.function_name_filter_list` — 限制该服务器对外暴露的函数列表(逗号分隔) |
72+
| 4(最低) | **用户 Chat 工具选择** | Chat 界面的 `tool_ids` — 在已启用范围内进一步筛选:未选则全选,有选则仅选中的 |
73+
74+
### 管理员函数名过滤列表说明
75+
76+
OpenWebUI 后台的工具服务器连接配置中支持设置 `function_name_filter_list` 字段(逗号分隔的函数名),用于限制该服务器对外暴露的函数。源码逻辑:
77+
78+
```python
79+
# utils/tools.py
80+
function_name_filter_list = tool_server_connection.get("config", {}).get("function_name_filter_list", "")
81+
if isinstance(function_name_filter_list, str):
82+
function_name_filter_list = function_name_filter_list.split(",")
83+
84+
for spec in specs:
85+
function_name = spec["name"]
86+
if function_name_filter_list:
87+
if not is_string_allowed(function_name, function_name_filter_list):
88+
continue # 不在列表中的函数被跳过
89+
```
90+
91+
- 列表**为空** → 该服务器所有函数均可用
92+
- 列表**有值** → 只有名称匹配的函数会被暴露给用户
93+
94+
---
95+
96+
## 核心判定流程
97+
98+
```mermaid
99+
graph TD
100+
A[新消息到来] --> BT[内置工具:读模型 meta.builtinTools]
101+
BT --> BT2{builtinTools 字段存在?}
102+
BT2 -- 否 --> BT3[开启全部内置工具]
103+
BT2 -- 是 --> BT4[仅开启值为 true 的类别]
104+
105+
A --> CT[OpenWebUI Tools / 工具服务器]
106+
CT --> V{插件 Valve 开启了该类别?}
107+
V -- 否 --> VX[丢弃该类别]
108+
V -- 是 --> B{后端 config.enable = True?}
109+
B -- 否 --> C[跳过该服务器]
110+
B -- 是 --> FL{function_name_filter_list 有值?}
111+
FL -- 是 --> FL2[过滤掉不在列表中的函数]
112+
FL -- 否 --> J
113+
FL2 --> J{Chat tool_ids 有勾选?}
114+
J -- 有 --> K[仅加载勾选的 ID]
115+
J -- 无 --> L[加载所有后台已启用工具]
116+
117+
BT3 & BT4 & K & L --> M[始终注入: publish_file_from_workspace]
118+
M --> N[启动/恢复 Copilot SDK 会话]
119+
```
120+
121+
---
122+
123+
## 场景速查表
124+
125+
### 内置工具(与前端选择无关)
126+
127+
| 模型配置 | 结果 |
128+
|---|---|
129+
| `meta.builtinTools` 字段不存在 | 全部内置工具类别开启 |
130+
| `meta.builtinTools` 字段存在 |`true` 的类别开启 |
131+
132+
### OpenWebUI Tools / 工具服务器(受 Chat 前端选择影响)
133+
134+
| Chat 工具选择情况 | 加载逻辑 |
135+
|---|---|
136+
| 什么都没选 | 加载所有 Valve 开启且后台已启用的工具(Python Tools + OpenAPI + MCP) |
137+
| 选了部分 tool_ids | 仅加载勾选的 ID(必须同时通过 Valve 和 config.enable 校验) |
138+
139+
---
140+
141+
## 代码实现详述
142+
143+
### 1. 管理员后台变更即时同步
144+
145+
OpenWebUI 通过 `PersistentConfig` + Redis 保证多 worker 之间的配置同步,插件直接读取 `request.app.state.config.TOOL_SERVER_CONNECTIONS` 即可获取最新值:
146+
147+
- 后台**启用**一个服务器 → **下一条消息**就出现。
148+
- 后台**禁用**一个服务器 → **下一条消息**就消失。
149+
150+
```python
151+
# 直接读取 OpenWebUI 的配置对象,有 Redis 时每次读取都会同步最新值
152+
connections = request.app.state.config.TOOL_SERVER_CONNECTIONS # list
153+
154+
for server in connections:
155+
config = server.get("config", {})
156+
is_enabled = config.get("enable", False) # 每条服务器、每次请求都检查
157+
if not is_enabled:
158+
continue # 立即跳过,硬性拦截
159+
```
160+
161+
### 2. 内置工具直接透传给 OpenWebUI 处理
162+
163+
插件调用 OpenWebUI 的 `get_builtin_tools(request, extra_params, model)` 时,将 `model` 原样传入即可。OpenWebUI 内部会自动读取 `model.info.meta.builtinTools` 来决定哪些内置工具生效:
164+
165+
```python
166+
# OpenWebUI 源码 utils/tools.py 中的判定逻辑(开发参考,非插件代码)
167+
def is_builtin_tool_enabled(category: str) -> bool:
168+
builtin_tools = model.get("info", {}).get("meta", {}).get("builtinTools", {})
169+
return builtin_tools.get(category, True) # 缺省值 True:未配置时全部开启
170+
```
171+
172+
插件无需自行维护内置工具分类映射,也不需要向 `builtinTools` 注入任何值。
173+
174+
### 3. 自定义工具"默认全选"(白名单仅在显式勾选时激活)
175+
176+
白名单**只有在用户明确勾选了 tool_ids 时才启用**。未勾选任何工具时,加载所有后台已启用工具:
177+
178+
```python
179+
# tool_ids 来自 Chat 请求体
180+
if tool_ids:
181+
# 白名单模式:严格只保留勾选项
182+
available_ids = [tid for tid in available_ids if tid in tool_ids]
183+
else:
184+
# 无勾选:加载所有后台已启用工具(免配置可用)
185+
pass # available_ids 保持不变
186+
```
187+
188+
MCP 服务器的 `_parse_mcp_servers` 遵循同样规则。
189+
190+
### 4. 后端状态硬校验(OpenAPI 和 MCP 统一处理)
191+
192+
```python
193+
is_enabled = False
194+
config = server.get("config", {}) if isinstance(server, dict) else getattr(server, "config", {})
195+
is_enabled = config.get("enable", False) if isinstance(config, dict) else getattr(config, "enable", False)
196+
197+
if not is_enabled:
198+
continue # 硬性跳过,任何用户或 Valve 设置都无法绕过
199+
```
200+
201+
---
202+
203+
## 注意事项
204+
205+
- **SDK 内部工具**:向会话传 `available_tools = None`,保证 `read_file``shell` 等 SDK 原生能力不被自定义工具列表意外屏蔽。
206+
- **始终注入的工具**`publish_file_from_workspace` 在所有过滤完成后硬性追加,是文件交付工作流的必要依赖,不受任何开关影响。

docs/plugins/filters/github-copilot-sdk-files-filter.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
# GitHub Copilot SDK Files Filter (v0.1.2)
1+
# GitHub Copilot SDK Files Filter (v0.1.3)
22

33
This is a dedicated **companion filter plugin** designed specifically for the [GitHub Copilot SDK Pipe](../pipes/github-copilot-sdk.md).
44

55
Its core mission is to **protect user-uploaded files from being "pre-processed" by the OpenWebUI core system, ensuring that the Copilot Agent receives the raw files for autonomous analysis.**
66

7+
## ✨ v0.1.3 Updates (What's New)
8+
9+
- **🔍 BYOK Model ID Matching Fixed**: Now correctly identifies models in `github_copilot_official_sdk_pipe.xxx` format via prefix matching, in addition to keyword fallback for backward compatibility. (v0.1.3)
10+
- **🐛 Dual-channel Debug Log**: Added `show_debug_log` valve. When enabled, logs are written to both server-side logger and browser console (`console.group`). (v0.1.3)
11+
712
## 🎯 Why is this needed?
813

914
In OpenWebUI's default workflow, when you upload a file (e.g., PDF, Excel, Python script), OpenWebUI automatically initiates a **RAG (Retrieval-Augmented Generation)** process: parsing the file, vectorizing it, extracting text, and injecting it into the prompt.
@@ -48,6 +53,6 @@ Default settings work for most users unless you have specific needs:
4853

4954
## ⚠️ Important Notes
5055

51-
* **Must be used with Copilot SDK Pipe**: If you install this plugin without the main Pipe plugin, uploaded files will simply "disappear" (as no subsequent plugin will look for them in `copilot_files`).
52-
* **Gemini Filter Compatibility**: This plugin is fully compatible with the Gemini Multimodal Filter. As long as the priority is set correctly (This Plugin < Gemini Plugin), they can coexist without interference.
53-
* **Physical File Path**: Ensure the `OPENWEBUI_UPLOAD_PATH` is correctly set in the Pipe plugin Valves for the actual file transport to work.
56+
- **Must be used with Copilot SDK Pipe**: If you install this plugin without the main Pipe plugin, uploaded files will simply "disappear" (as no subsequent plugin will look for them in `copilot_files`).
57+
- **Gemini Filter Compatibility**: This plugin is fully compatible with the Gemini Multimodal Filter. As long as the priority is set correctly (This Plugin < Gemini Plugin), they can coexist without interference.
58+
- **Physical File Path**: Ensure the `OPENWEBUI_UPLOAD_PATH` is correctly set in the Pipe plugin Valves for the actual file transport to work.

0 commit comments

Comments
 (0)