Compare commits

...

6 Commits

18 changed files with 857 additions and 227 deletions

View File

@@ -4,7 +4,7 @@ description: OpenWebUI Plugin Development & Release Workflow
# OpenWebUI Plugin Development Workflow
This workflow outlines the standard process for developing, documenting, and releasing plugins for OpenWebUI, ensuring compliance with project standards and CI/CD requirements.
This workflow outlines the standard process for developing, documenting, and releasing plugins for OpenWebUI. **Crucially, the default goal of this workflow is "Preparation" (updating all relevant files) rather than automatic "Submission" (git commit/push), unless a release is explicitly requested.**
## 1. Development Standards
@@ -77,7 +77,9 @@ Reference: `.github/workflows/release.yml`
- **When to Bump**: Only update the version when:
- User says "发布" / "release" / "bump version"
- User explicitly asks to prepare for release
- **Agent Initiative**: After completing significant changes (new features, bug fixes, or multiple code modifications), the agent **SHOULD proactively ask** the user if they want to release a new version. If confirmed, update all version-related files.
- **Agent Initiative**: After completing significant changes (new features, bug fixes, or multiple code modifications), the agent **SHOULD proactively ask** the user if they want to **prepare a new version** for release.
- **Release Information Compliance**: When a release is requested, the agent must generate a standard release summary (English commit title + bilingual bullet points) as defined in Section 3 & 5.
- **Default Action (Prepare Only)**: When performing a version bump or update, the agent should update all files locally but **STOP** before committing. Present the changes and the **proposed Release/Commit Message** to the user and wait for explicit confirmation to commit/push.
- **Consistency**: When bumping, update version in **ALL** locations:
1. English Code (`.py`)
2. Chinese Code (`.py`)
@@ -106,6 +108,21 @@ Reference: `.github/workflows/release.yml`
- Format: `https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/{type}/{name}/README.md`
- Example: `https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/filters/folder-memory/README.md`
### Release Content Standard
When the user confirms a release, the agent **MUST** follow these content standards:
1. **Commit Message**:
- **Language**: English ONLY.
- **Format**: `type(scope): description` (e.g., `feat(pipes): add streaming support for Copilot SDK`).
- **Body**: List 1-3 key changes in bullet points.
2. **Release Summary (for user review)**:
- Before committing, present a "Release Draft" containing:
- **Title**: e.g., `Release v0.1.1: [Plugin Name] - [Brief Summary]`
- **Changes**: Bilingual bullet points (English/Chinese) describing the impact.
- **Verification Status**: Confirm all 8+ files have been updated and synced.
3. **Internal Documentation**: Ensure "What's New" sections in READMEs and `docs/` match exactly the changes being released.
### Pull Request Check
- Workflow: `.github/workflows/plugin-version-check.yml`
@@ -126,4 +143,7 @@ Before committing:
## 5. Git Operations (Agent Rules)
Strictly follow the rules defined in `.github/copilot-instructions.md`**Git Operations (Agent Rules)** section.
1. **Prepare-on-Demand**: Focus on file modifications and local verification first.
2. **No Auto-Commit**: Never `git commit`, `git push`, or `create_pull_request` automatically after file updates unless the user explicitly says "commit this" or "release now".
3. **Draft Mode**: If available, use PRs as drafts first.
4. **Reference**: Strictly follow the rules defined in `.github/copilot-instructions.md`**Git Operations (Agent Rules)** section.

View File

@@ -481,6 +481,60 @@ async def get_user_language(self):
**注意**: 即使插件有 `Valves` 配置,也应优先尝试自动探测,提升用户体验。
### 8. 智能代理文件交付规范 (Agent File Delivery Standards)
在开发具备文件生成能力的智能代理插件(如 GitHub Copilot SDK 集成)时,必须遵循以下标准流程,以确保文件在不同存储后端(本地/S3下的可用性并绕过不必要的 RAG 处理。
#### 核心协议:三步交付法 (The 3-Step Delivery Protocol)
1. **本地写入 (Write Local)**:
- 代理必须在当前执行目录 (`.`) 下创建文件。
- **严禁**使用系统临时目录(如 `/tmp`)存放待发布的文件,因为这些路径在隔离的工作空间外不可见。
2. **显式发布 (Publish)**:
- 必须调用内建工具 `publish_file_from_workspace(filename='name.ext')`
- 该工具负责将文件迁移至 Open WebUI 正式存储(自动适配 S3并注入 `skip_rag` 元数据以防止触发向量化流程RAG Bypass
3. **呈现链接 (Display Link)**:
- 获取工具返回的 `download_url`(正确格式为 `/api/v1/files/{id}/content`)。
- **必须**以 Markdown 链接形式(如 `[点击下载报告](url)`)展示给用户。
#### 路径语义 (Path Semantics)
- 代理应始终将“当前目录”视为其受保护所在的私有工作空间。
- `publish_file_from_workspace` 的参数 `filename` 仅需传入相对于当前目录的文件名。
### 9. Copilot SDK 插件工具定义规范 (Copilot SDK Tool Definition Standards)
在为 GitHub Copilot SDK 开发自定义工具时,为了确保大模型能正确识别参数(避免生成空的 `properties` Schema必须遵循以下定义模式
#### 显式参数模型 (Explicit Parameter Schema)
**禁止**仅依赖函数签名和类型提示。**必须**定义一个继承自 `pydantic.BaseModel` 的类来描述参数,并在 `define_tool` 中通过 `params_type` 显式引用。
```python
from pydantic import BaseModel, Field
from copilot import define_tool
# 1. 定义参数模型
class MyToolParams(BaseModel):
query: str = Field(..., description="搜索关键词")
limit: int = Field(default=10, description="返回结果数量限制")
# 2. 实现工具逻辑
async def my_custom_search(query: str, limit: int) -> dict:
# ... 逻辑实现 ...
return {"results": []}
# 3. 注册工具(关键:使用 params_type
my_tool = define_tool(
name="my_custom_search",
description="在特定数据源中执行搜索",
params_type=MyToolParams, # 显式传递参数模型以生成正确的 JSON Schema
)(my_custom_search)
```
#### 关键要点 (Key Requirements)
1. **params_type**: 必须在 `define_tool` 中使用此参数。这是防止大模型幻觉认为工具“无参数”的唯一可靠方法。
2. **Field 描述**: 在 `BaseModel` 中使用 `Field(..., description="...")` 为每个参数提供详细的描述信息。
3. **Required vs Optional**: 明确标注必填项(无默认值)和可选项(带 `default`)。
---
## ⚡ Action 插件规范 (Action Plugin Standards)
@@ -928,10 +982,19 @@ Filter 实例是**单例 (Singleton)**。
- Update README/README_CN to include What's New section
- Migration: default TITLE_SOURCE changed to chat_title
### 4. 🤖 Git Operations (Agent Rules)
#### 发布信息生成准则 (Release Summary Generation)
当准备提交时,必须向用户展示以下格式的“发布草案”:
1. **Commit Message**: 符合 Conventional Commits 的英文标题及摘要。
2. **变更列表 (Bilingual Changes)**:
- 英文: Clear descriptions of technical/functional changes.
- 中文: 清晰描述用户可见的功能改进或修复。
3. **核查状态 (Verification)**: 确认版本号已在相关 8+ 处位置同步更新。
- **允许**: 直接推送到 `main` 分支并发布。
- **允许**: 创建功能分支 (`feature/xxx`),推送到功能分支。
### 4. 🤖 Git 提交与推送规范 (Git Operations & Push Rules)
- **核心原则**: 默认仅进行**本地文件准备**更新代码、READMEs、Docs、版本号**严禁**在未获用户明确许可的情况下自动执行 `git commit``git push`
- **允许 (需确认)**: 只有在用户明确表示“发布”、“Commit it”、“Release”或“提交”后才允许直接推送到 `main` 分支或创建 PR。
- **功能分支**: 推荐在进行大规模重构或实验性功能开发时,创建功能分支 (`feature/xxx`) 进行隔离。
### 5. 🤝 贡献者认可规范 (Contributor Recognition)

View File

@@ -8,28 +8,28 @@ A collection of enhancements, plugins, and prompts for [OpenWebUI](https://githu
<!-- STATS_START -->
## 📊 Community Stats
> 🕐 Auto-updated: 2026-02-09 23:25
> 🕐 Auto-updated: 2026-02-10 12:51
| 👤 Author | 👥 Followers | ⭐ Points | 🏆 Contributions |
| :---: | :---: | :---: | :---: |
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **212** | **261** | **44** |
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **216** | **262** | **44** |
| 📝 Posts | ⬇️ Downloads | 👁️ Views | 👍 Upvotes | 💾 Saves |
| :---: | :---: | :---: | :---: | :---: |
| **21** | **3962** | **46159** | **223** | **267** |
| **21** | **4031** | **47177** | **224** | **267** |
### 🔥 Top 6 Popular Plugins
> 🕐 Auto-updated: 2026-02-09 23:25
> 🕐 Auto-updated: 2026-02-10 12:51
| Rank | Plugin | Version | Downloads | Views | Updated |
| :---: | :--- | :---: | :---: | :---: | :---: |
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.2 | 922 | 8131 | 2026-01-28 |
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 670 | 6311 | 2026-01-30 |
| 🥉 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.4 | 370 | 2881 | 2026-02-07 |
| 4⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 355 | 3627 | 2026-01-28 |
| 5⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 339 | 1611 | 2026-01-29 |
| 6⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | 1.2.4 | 313 | 4483 | 2026-01-29 |
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.2 | 935 | 8224 | 2026-01-28 |
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 678 | 6439 | 2026-01-30 |
| 🥉 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.4 | 374 | 2931 | 2026-02-07 |
| 4⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 360 | 3689 | 2026-01-28 |
| 5⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 340 | 1631 | 2026-02-09 |
| 6⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | 1.2.4 | 323 | 4559 | 2026-01-29 |
*See full stats in [Community Stats Report](./docs/community-stats.md)*
<!-- STATS_END -->

View File

@@ -7,28 +7,28 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
<!-- STATS_START -->
## 📊 社区统计
> 🕐 自动更新于 2026-02-09 23:25
> 🕐 自动更新于 2026-02-10 12:51
| 👤 作者 | 👥 粉丝 | ⭐ 积分 | 🏆 贡献 |
| :---: | :---: | :---: | :---: |
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **212** | **261** | **44** |
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) | **216** | **262** | **44** |
| 📝 发布 | ⬇️ 下载 | 👁️ 浏览 | 👍 点赞 | 💾 收藏 |
| :---: | :---: | :---: | :---: | :---: |
| **21** | **3962** | **46159** | **223** | **267** |
| **21** | **4031** | **47177** | **224** | **267** |
### 🔥 热门插件 Top 6
> 🕐 自动更新于 2026-02-09 23:25
> 🕐 自动更新于 2026-02-10 12:51
| 排名 | 插件 | 版本 | 下载 | 浏览 | 更新日期 |
| :---: | :--- | :---: | :---: | :---: | :---: |
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.2 | 922 | 8131 | 2026-01-28 |
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 670 | 6311 | 2026-01-30 |
| 🥉 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.4 | 370 | 2881 | 2026-02-07 |
| 4⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 355 | 3627 | 2026-01-28 |
| 5⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 339 | 1611 | 2026-01-29 |
| 6⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | 1.2.4 | 313 | 4483 | 2026-01-29 |
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | 0.9.2 | 935 | 8224 | 2026-01-28 |
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | 1.5.0 | 678 | 6439 | 2026-01-30 |
| 🥉 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | 0.4.4 | 374 | 2931 | 2026-02-07 |
| 4⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | 1.2.2 | 360 | 3689 | 2026-01-28 |
| 5⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | 0.3.7 | 340 | 1631 | 2026-02-09 |
| 6⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | 1.2.4 | 323 | 4559 | 2026-01-29 |
*完整统计请查看 [社区统计报告](./docs/community-stats.zh.md)*
<!-- STATS_END -->

View File

@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"label": "followers",
"message": "212",
"message": "216",
"color": "blue"
}

View File

@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"label": "points",
"message": "261",
"message": "262",
"color": "orange"
}

View File

@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"label": "upvotes",
"message": "223",
"message": "224",
"color": "brightgreen"
}

View File

@@ -1,8 +1,8 @@
{
"total_posts": 21,
"total_downloads": 3962,
"total_views": 46159,
"total_upvotes": 223,
"total_downloads": 4031,
"total_views": 47177,
"total_upvotes": 224,
"total_downvotes": 2,
"total_saves": 267,
"total_comments": 51,
@@ -19,8 +19,8 @@
"version": "0.9.2",
"author": "Fu-Jie",
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
"downloads": 922,
"views": 8131,
"downloads": 935,
"views": 8224,
"upvotes": 22,
"saves": 50,
"comments": 13,
@@ -35,8 +35,8 @@
"version": "1.5.0",
"author": "Fu-Jie",
"description": "AI-powered infographic generator based on AntV Infographic. Supports professional templates, auto-icon matching, and SVG/PNG downloads.",
"downloads": 670,
"views": 6311,
"downloads": 678,
"views": 6439,
"upvotes": 24,
"saves": 34,
"comments": 10,
@@ -51,8 +51,8 @@
"version": "0.4.4",
"author": "Fu-Jie",
"description": "Export current conversation from Markdown to Word (.docx) with Mermaid diagrams rendered client-side (Mermaid.js, SVG+PNG), LaTeX math, real hyperlinks, improved tables, syntax highlighting, and blockquote support.",
"downloads": 370,
"views": 2881,
"downloads": 374,
"views": 2931,
"upvotes": 14,
"saves": 26,
"comments": 3,
@@ -67,8 +67,8 @@
"version": "1.2.2",
"author": "Fu-Jie",
"description": "Reduces token consumption in long conversations while maintaining coherence through intelligent summarization and message compression.",
"downloads": 355,
"views": 3627,
"downloads": 360,
"views": 3689,
"upvotes": 14,
"saves": 33,
"comments": 0,
@@ -83,13 +83,13 @@
"version": "0.3.7",
"author": "Fu-Jie",
"description": "Extracts tables from chat messages and exports them to Excel (.xlsx) files with smart formatting.",
"downloads": 339,
"views": 1611,
"downloads": 340,
"views": 1631,
"upvotes": 7,
"saves": 6,
"comments": 0,
"created_at": "2025-05-30",
"updated_at": "2026-01-29",
"updated_at": "2026-02-09",
"url": "https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d"
},
{
@@ -99,8 +99,8 @@
"version": "1.2.4",
"author": "Fu-Jie",
"description": "A content normalizer filter that fixes common Markdown formatting issues in LLM outputs, such as broken code blocks, LaTeX formulas, and list formatting.",
"downloads": 313,
"views": 4483,
"downloads": 323,
"views": 4559,
"upvotes": 17,
"saves": 28,
"comments": 5,
@@ -115,8 +115,8 @@
"version": "0.2.4",
"author": "Fu-Jie",
"description": "Quickly generates beautiful flashcards from text, extracting key points and categories.",
"downloads": 219,
"views": 3321,
"downloads": 220,
"views": 3342,
"upvotes": 13,
"saves": 14,
"comments": 2,
@@ -131,8 +131,8 @@
"version": "",
"author": "",
"description": "",
"downloads": 180,
"views": 2530,
"downloads": 184,
"views": 2608,
"upvotes": 9,
"saves": 5,
"comments": 0,
@@ -148,7 +148,7 @@
"author": "Fu-Jie",
"description": "A comprehensive thinking lens that dives deep into any content - from context to logic, insights, and action paths.",
"downloads": 146,
"views": 1232,
"views": 1237,
"upvotes": 6,
"saves": 11,
"comments": 0,
@@ -163,8 +163,8 @@
"version": "0.4.4",
"author": "Fu-Jie",
"description": "将对话导出为 Word (.docx),支持 Mermaid 图表 (客户端渲染 SVG+PNG)、LaTeX 数学公式、真实超链接、增强表格格式、代码高亮和引用块。",
"downloads": 124,
"views": 2171,
"downloads": 125,
"views": 2187,
"upvotes": 13,
"saves": 7,
"comments": 4,
@@ -176,11 +176,11 @@
"title": "GitHub Copilot Official SDK Pipe",
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
"type": "action",
"version": "0.6.0",
"version": "0.6.1",
"author": "Fu-Jie",
"description": "Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.",
"downloads": 83,
"views": 2162,
"downloads": 95,
"views": 2254,
"upvotes": 13,
"saves": 7,
"comments": 4,
@@ -196,7 +196,7 @@
"author": "Fu-Jie",
"description": "Automatically extracts project rules from conversations and injects them into the folder's system prompt.",
"downloads": 59,
"views": 1264,
"views": 1278,
"upvotes": 6,
"saves": 8,
"comments": 0,
@@ -212,7 +212,7 @@
"author": "Fu-Jie",
"description": "基于 AntV Infographic 的智能信息图生成插件。支持多种专业模板,自动图标匹配,并提供 SVG/PNG 下载功能。",
"downloads": 58,
"views": 1040,
"views": 1048,
"upvotes": 10,
"saves": 1,
"comments": 0,
@@ -228,7 +228,7 @@
"author": "Fu-Jie",
"description": "智能分析文本内容,生成交互式思维导图,帮助用户结构化和可视化知识。",
"downloads": 37,
"views": 577,
"views": 579,
"upvotes": 6,
"saves": 2,
"comments": 0,
@@ -244,7 +244,7 @@
"author": "Fu-Jie",
"description": "通过智能摘要和消息压缩,降低长对话的 token 消耗,同时保持对话连贯性。",
"downloads": 33,
"views": 650,
"views": 656,
"upvotes": 7,
"saves": 5,
"comments": 0,
@@ -260,7 +260,7 @@
"author": "Fu-Jie",
"description": "快速将文本提炼为精美的学习记忆卡片,支持核心要点提取与分类。",
"downloads": 27,
"views": 675,
"views": 680,
"upvotes": 8,
"saves": 1,
"comments": 0,
@@ -276,7 +276,7 @@
"author": "Fu-Jie",
"description": "全方位的思维透镜 —— 从背景全景到逻辑脉络,从深度洞察到行动路径。",
"downloads": 24,
"views": 423,
"views": 425,
"upvotes": 5,
"saves": 1,
"comments": 0,
@@ -291,9 +291,9 @@
"version": "0.1.2",
"author": "Fu-Jie",
"description": "A specialized filter to bypass OpenWebUI's default RAG for GitHub Copilot SDK models. It moves uploaded files to a safe location ('copilot_files') so the Copilot Pipe can process them natively without interference.",
"downloads": 3,
"views": 47,
"upvotes": 1,
"downloads": 13,
"views": 370,
"upvotes": 2,
"saves": 0,
"comments": 0,
"created_at": "2026-02-09",
@@ -308,7 +308,7 @@
"author": "",
"description": "",
"downloads": 0,
"views": 1468,
"views": 1481,
"upvotes": 12,
"saves": 18,
"comments": 8,
@@ -324,7 +324,7 @@
"author": "",
"description": "",
"downloads": 0,
"views": 140,
"views": 142,
"upvotes": 2,
"saves": 0,
"comments": 0,
@@ -340,7 +340,7 @@
"author": "",
"description": "",
"downloads": 0,
"views": 1415,
"views": 1417,
"upvotes": 14,
"saves": 10,
"comments": 2,
@@ -354,10 +354,10 @@
"name": "Fu-Jie",
"profile_url": "https://openwebui.com/u/Fu-Jie",
"profile_image": "https://community.s3.openwebui.com/uploads/users/b15d1348-4347-42b4-b815-e053342d6cb0/profile_d9510745-4bd4-4f8f-a997-4a21847d9300.webp",
"followers": 212,
"followers": 216,
"following": 4,
"total_points": 261,
"post_points": 221,
"total_points": 262,
"post_points": 222,
"comment_points": 40,
"contributions": 44
}

View File

@@ -1,15 +1,15 @@
# 📊 OpenWebUI Community Stats Report
> 📅 Updated: 2026-02-09 23:25
> 📅 Updated: 2026-02-10 12:51
## 📈 Overview
| Metric | Value |
|------|------|
| 📝 Total Posts | 21 |
| ⬇️ Total Downloads | 3962 |
| 👁️ Total Views | 46159 |
| 👍 Total Upvotes | 223 |
| ⬇️ Total Downloads | 4031 |
| 👁️ Total Views | 47177 |
| 👍 Total Upvotes | 224 |
| 💾 Total Saves | 267 |
| 💬 Total Comments | 51 |
@@ -23,24 +23,24 @@
| Rank | Title | Type | Version | Downloads | Views | Upvotes | Saves | Updated |
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 922 | 8131 | 22 | 50 | 2026-01-28 |
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 670 | 6311 | 24 | 34 | 2026-01-30 |
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.4 | 370 | 2881 | 14 | 26 | 2026-02-07 |
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 355 | 3627 | 14 | 33 | 2026-01-28 |
| 5 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 339 | 1611 | 7 | 6 | 2026-01-29 |
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 313 | 4483 | 17 | 28 | 2026-01-29 |
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 219 | 3321 | 13 | 14 | 2026-01-28 |
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | unknown | | 180 | 2530 | 9 | 5 | 2026-01-28 |
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 146 | 1232 | 6 | 11 | 2026-01-08 |
| 10 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.4 | 124 | 2171 | 13 | 7 | 2026-02-07 |
| 11 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | action | 0.6.0 | 83 | 2162 | 13 | 7 | 2026-02-09 |
| 12 | [📂 Folder Memory Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 59 | 1264 | 6 | 8 | 2026-01-20 |
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 58 | 1040 | 10 | 1 | 2026-01-29 |
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.2 | 37 | 577 | 6 | 2 | 2026-01-28 |
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 33 | 650 | 7 | 5 | 2026-01-28 |
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 675 | 8 | 1 | 2026-01-28 |
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 24 | 423 | 5 | 1 | 2026-01-08 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 3 | 47 | 1 | 0 | 2026-02-09 |
| 19 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 1468 | 12 | 18 | 2026-01-28 |
| 20 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 140 | 2 | 0 | 2026-01-14 |
| 21 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1415 | 14 | 10 | 2026-01-10 |
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 935 | 8224 | 22 | 50 | 2026-01-28 |
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 678 | 6439 | 24 | 34 | 2026-01-30 |
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.4 | 374 | 2931 | 14 | 26 | 2026-02-07 |
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 360 | 3689 | 14 | 33 | 2026-01-28 |
| 5 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 340 | 1631 | 7 | 6 | 2026-02-09 |
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 323 | 4559 | 17 | 28 | 2026-01-29 |
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 220 | 3342 | 13 | 14 | 2026-01-28 |
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | unknown | | 184 | 2608 | 9 | 5 | 2026-01-28 |
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 146 | 1237 | 6 | 11 | 2026-01-08 |
| 10 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.4 | 125 | 2187 | 13 | 7 | 2026-02-07 |
| 11 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | action | 0.6.1 | 95 | 2254 | 13 | 7 | 2026-02-09 |
| 12 | [📂 Folder Memory Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 59 | 1278 | 6 | 8 | 2026-01-20 |
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 58 | 1048 | 10 | 1 | 2026-01-29 |
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.2 | 37 | 579 | 6 | 2 | 2026-01-28 |
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 33 | 656 | 7 | 5 | 2026-01-28 |
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 680 | 8 | 1 | 2026-01-28 |
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 24 | 425 | 5 | 1 | 2026-01-08 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 13 | 370 | 2 | 0 | 2026-02-09 |
| 19 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 1481 | 12 | 18 | 2026-01-28 |
| 20 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 142 | 2 | 0 | 2026-01-14 |
| 21 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1417 | 14 | 10 | 2026-01-10 |

View File

@@ -1,15 +1,15 @@
# 📊 OpenWebUI 社区统计报告
> 📅 更新时间: 2026-02-09 23:25
> 📅 更新时间: 2026-02-10 12:51
## 📈 总览
| 指标 | 数值 |
|------|------|
| 📝 发布数量 | 21 |
| ⬇️ 总下载量 | 3962 |
| 👁️ 总浏览量 | 46159 |
| 👍 总点赞数 | 223 |
| ⬇️ 总下载量 | 4031 |
| 👁️ 总浏览量 | 47177 |
| 👍 总点赞数 | 224 |
| 💾 总收藏数 | 267 |
| 💬 总评论数 | 51 |
@@ -23,24 +23,24 @@
| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 922 | 8131 | 22 | 50 | 2026-01-28 |
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 670 | 6311 | 24 | 34 | 2026-01-30 |
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.4 | 370 | 2881 | 14 | 26 | 2026-02-07 |
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 355 | 3627 | 14 | 33 | 2026-01-28 |
| 5 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 339 | 1611 | 7 | 6 | 2026-01-29 |
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 313 | 4483 | 17 | 28 | 2026-01-29 |
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 219 | 3321 | 13 | 14 | 2026-01-28 |
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | unknown | | 180 | 2530 | 9 | 5 | 2026-01-28 |
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 146 | 1232 | 6 | 11 | 2026-01-08 |
| 10 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.4 | 124 | 2171 | 13 | 7 | 2026-02-07 |
| 11 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | action | 0.6.0 | 83 | 2162 | 13 | 7 | 2026-02-09 |
| 12 | [📂 Folder Memory Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 59 | 1264 | 6 | 8 | 2026-01-20 |
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 58 | 1040 | 10 | 1 | 2026-01-29 |
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.2 | 37 | 577 | 6 | 2 | 2026-01-28 |
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 33 | 650 | 7 | 5 | 2026-01-28 |
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 675 | 8 | 1 | 2026-01-28 |
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 24 | 423 | 5 | 1 | 2026-01-08 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 3 | 47 | 1 | 0 | 2026-02-09 |
| 19 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 1468 | 12 | 18 | 2026-01-28 |
| 20 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 140 | 2 | 0 | 2026-01-14 |
| 21 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1415 | 14 | 10 | 2026-01-10 |
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action | 0.9.2 | 935 | 8224 | 22 | 50 | 2026-01-28 |
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action | 1.5.0 | 678 | 6439 | 24 | 34 | 2026-01-30 |
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action | 0.4.4 | 374 | 2931 | 14 | 26 | 2026-02-07 |
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | action | 1.2.2 | 360 | 3689 | 14 | 33 | 2026-01-28 |
| 5 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action | 0.3.7 | 340 | 1631 | 7 | 6 | 2026-02-09 |
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | action | 1.2.4 | 323 | 4559 | 17 | 28 | 2026-01-29 |
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action | 0.2.4 | 220 | 3342 | 13 | 14 | 2026-01-28 |
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | unknown | | 184 | 2608 | 9 | 5 | 2026-01-28 |
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action | 1.0.0 | 146 | 1237 | 6 | 11 | 2026-01-08 |
| 10 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action | 0.4.4 | 125 | 2187 | 13 | 7 | 2026-02-07 |
| 11 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | action | 0.6.1 | 95 | 2254 | 13 | 7 | 2026-02-09 |
| 12 | [📂 Folder Memory Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter | 0.1.0 | 59 | 1278 | 6 | 8 | 2026-01-20 |
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action | 1.5.0 | 58 | 1048 | 10 | 1 | 2026-01-29 |
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action | 0.9.2 | 37 | 579 | 6 | 2 | 2026-01-28 |
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action | 1.2.2 | 33 | 656 | 7 | 5 | 2026-01-28 |
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action | 0.2.4 | 27 | 680 | 8 | 1 | 2026-01-28 |
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action | 1.0.0 | 24 | 425 | 5 | 1 | 2026-01-08 |
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter | 0.1.2 | 13 | 370 | 2 | 0 | 2026-02-09 |
| 19 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | unknown | | 0 | 1481 | 12 | 18 | 2026-01-28 |
| 20 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | unknown | | 0 | 142 | 2 | 0 | 2026-01-14 |
| 21 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | unknown | | 0 | 1417 | 14 | 10 | 2026-01-10 |

View File

@@ -1,6 +1,6 @@
# GitHub Copilot SDK Pipe for OpenWebUI
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.6.0 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 0.6.2 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/open-webui) that integrates the official [GitHub Copilot SDK](https://github.com/github/copilot-sdk). It enables you to use **GitHub Copilot models** (e.g., `gpt-5.2-codex`, `claude-sonnet-4.5`,`gemini-3-pro`, `gpt-5-mini`) **AND** your own models via **BYOK** (OpenAI, Anthropic) directly within OpenWebUI, providing a unified agentic experience with **strict User & Chat-level Workspace Isolation**.
@@ -14,13 +14,12 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
---
## ✨ v0.6.0 Updates (What's New)
## ✨ v0.6.2 Updates (What's New)
- **👥 User & Chat Management**: Physical management architecture (`user_id/chat_id`) for absolute resource independence.
- **🤖 Empowering Agent Autonomy**: Automatic synchronization of raw files to the workspace, enabling direct Python-based analysis of Excel/CSV.
- **🔧 OpenAPI & External Tool Fixes**: Full support for tools mounted via OpenAPI servers.
- **📊 Cost Control**: Enhanced **Billing Multiplier Limits** (`MAX_MULTIPLIER`, e.g., set to 0 for free models only) and **Model Keyword Filtering** (`EXCLUDE_KEYWORDS`) for precise cost management.
- **🧠 Persistent TODO Lists**: Database-backed task tracking that persists across sessions.
- **🛠️ New Workspace Artifacts Tool**: Introduced `publish_file_from_workspace`. Agents can now generate files (e.g., Python-generated Excel/CSV) and provide direct download links for the user to click and save.
- **⚙️ Workflow Optimization**: Improved reliability of the internal agentic workspace management.
- **🛡️ Enhanced Security**: Refined access control for system resources within the isolated environment.
- **🔧 Performance Tuning**: Optimized stream processing for larger context windows.
---
@@ -33,7 +32,7 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
- **🧠 Deep Database Integration**: Real-time persistence of TOD·O lists for long-running workflows.
- **🌊 Advanced Streaming**: Full support for thinking process/Chain of Thought visualization.
- **🖼️ Intelligent Multimodal**: Vision capabilities and raw file analysis support.
- **⚡ Interactive Artifacts**: Automatically renders HTML/JS apps generated by the agent directly in the chat interface.
- **⚡ Full-Lifecycle File Agent**: Supports receiving uploaded files for raw bypass analysis and publishing generated results (e.g., analyzed Excel/reports) as downloadable links—a complete closed-loop agentic workflow.
---

View File

@@ -1,6 +1,6 @@
# GitHub Copilot SDK 官方管道
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.6.0 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 0.6.2 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
这是一个用于 [OpenWebUI](https://github.com/open-webui/open-webui) 的高级 Pipe 函数,深度集成了 **GitHub Copilot SDK**。它不仅支持 **GitHub Copilot 官方模型**(如 `gpt-5.2-codex`, `claude-sonnet-4.5`, `gemini-3-pro`, `gpt-5-mini`),还支持 **BYOK (自带 Key)** 模式对接自定义服务商OpenAI, Anthropic并具备**严格的用户与会话级工作区隔离**能力,提供统一且安全的 Agent 交互体验。
@@ -14,13 +14,12 @@
---
## ✨ 0.6.0 更新内容 (What's New)
## ✨ 0.6.2 更新内容 (What's New)
- **👥 多用户与会话管理**: 采用 `user_id/chat_id` 的物理隔离架构,确保资源独立与稳健管理
- **🤖 赋予 Agent 文件自主权**: 自动将上传的文件同步至物理工作区,支持 Python 直接分析 Excel/CSV
- **🔧 OpenAPI & 外部工具修复**: 完美支持通过 OpenAPI 服务器挂载的工具调用
- **📊 计费与成本控制**: 增强的**计费倍率限制** (`MAX_MULTIPLIER`,例如设为 0 即仅限免费模型) 和**模型关键词过滤** (`EXCLUDE_KEYWORDS`),实现更精准的成本管控
- **🧠 数据库持久化 TODO**: 任务进度跨会话保存Agent 拥有更持久的任务 memory。
- **🛠️ 新增工作区产物工具**: 引入 `publish_file_from_workspace`。Agent 现在可以生成物理文件(如使用 Python 生成的 Excel/CSV 报表),并直接在聊天界面提供点击下载链接
- **⚙️ 工作流优化**: 提升了内部 Agent 物理工作区管理的可靠性与原子性
- **🛡️ 安全增强**: 精细化了隔离环境下系统资源的访问控制策略
- **🔧 性能微调**: 针对大上下文窗口优化了流式数据处理性能
---
@@ -33,7 +32,7 @@
- **🧠 深度数据库集成**: 实时持久化 TOD·O 列表到 UI 进度条。
- **🌊 深度推理展示**: 完整支持模型思考过程 (Thinking Process) 的流式渲染。
- **🖼️ 智能多模态**: 完整支持图像识别与附件上传分析。
- **⚡ 交互式伪影 (Artifacts)**: 自动渲染 Agent 生成的 HTML/JS 应用程序,直接在聊天界面交互
- **⚡ 全生命周期文件 Agent**: 支持接收上传文件进行绕过 RAG 的深度分析,并将处理结果(如分析后的 Excel/报告)发布为可下载链接,实现完整的闭环 Agent 工作流
---

View File

@@ -15,7 +15,7 @@ Pipes allow you to:
## Available Pipe Plugins
- [GitHub Copilot SDK](github-copilot-sdk.md) (v0.6.0) - Official GitHub Copilot SDK integration. Features **Workspace Isolation**, **Database Persistence**, **Zero-config OpenWebUI Tool Bridge**, **BYOK** support, and **dynamic MCP discovery**. Supports streaming, multimodal, and infinite sessions.
- [GitHub Copilot SDK](github-copilot-sdk.md) (v0.6.2) - Official GitHub Copilot SDK integration. Features **Workspace Isolation**, **Database Persistence**, **Zero-config OpenWebUI Tool Bridge**, **BYOK** support, and **dynamic MCP discovery**. Supports streaming, multimodal, and infinite sessions.
---

View File

@@ -15,7 +15,7 @@ Pipes 可以用于:
## 可用的 Pipe 插件
- [GitHub Copilot SDK](github-copilot-sdk.zh.md) (v0.6.0) - GitHub Copilot SDK 官方集成。具备**工作区安全隔离**、**数据库持久化**、**零配置工具桥接**与**BYOK (自带 Key) 支持**。支持流式输出、打字机思考过程及无限会话。[查看深度架构解析](github-copilot-sdk-deep-dive.zh.md)。
- [GitHub Copilot SDK](github-copilot-sdk.zh.md) (v0.6.2) - GitHub Copilot SDK 官方集成。具备**工作区安全隔离**、**数据库持久化**、**零配置工具桥接**与**BYOK (自带 Key) 支持**。支持流式输出、打字机思考过程及无限会话。[查看深度架构解析](github-copilot-sdk-deep-dive.zh.md)。
---

View File

@@ -1,6 +1,6 @@
# GitHub Copilot SDK Pipe for OpenWebUI
**Author:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **Version:** 0.6.1 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 0.6.2 | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT
This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/open-webui) that integrates the official [GitHub Copilot SDK](https://github.com/github/copilot-sdk). It enables you to use **GitHub Copilot models** (e.g., `gpt-5.2-codex`, `claude-sonnet-4.5`,`gemini-3-pro`, `gpt-5-mini`) **AND** your own models via **BYOK** (OpenAI, Anthropic) directly within OpenWebUI, providing a unified agentic experience with **strict User & Chat-level Workspace Isolation**.
@@ -14,13 +14,12 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
---
## ✨ v0.6.1 Updates (What's New)
## ✨ v0.6.2 Updates (What's New)
- **👥 User & Chat Management**: Physical management architecture (`user_id/chat_id`) for absolute resource independence.
- **🤖 Empowering Agent Autonomy**: Automatic synchronization of raw files to the workspace, enabling direct Python-based analysis of Excel/CSV.
- **🔧 OpenAPI & External Tool Fixes**: Full support for tools mounted via OpenAPI servers.
- **📊 Cost Control**: Enhanced **Billing Multiplier Limits** (`MAX_MULTIPLIER`, e.g., set to 0 for free models only) and **Model Keyword Filtering** (`EXCLUDE_KEYWORDS`) for precise cost management.
- **🧠 Persistent TODO Lists**: Database-backed task tracking that persists across sessions.
- **🛠️ New Workspace Artifacts Tool**: Introduced `publish_file_from_workspace`. Agents can now generate files (e.g., Python-generated Excel/CSV) and provide direct download links for the user to click and save.
- **⚙️ Workflow Optimization**: Improved reliability of the internal agentic workspace management.
- **🛡️ Enhanced Security**: Refined access control for system resources within the isolated environment.
- **🔧 Performance Tuning**: Optimized stream processing for larger context windows.
---
@@ -33,7 +32,7 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
- **🧠 Deep Database Integration**: Real-time persistence of TOD·O lists for long-running workflows.
- **🌊 Advanced Streaming**: Full support for thinking process/Chain of Thought visualization.
- **🖼️ Intelligent Multimodal**: Vision capabilities and raw file analysis support.
- **⚡ Interactive Artifacts**: Automatically renders HTML/JS apps generated by the agent directly in the chat interface.
- **⚡ Full-Lifecycle File Agent**: Supports receiving uploaded files for raw bypass analysis and publishing generated results (e.g., analyzed Excel/reports) as downloadable links—a complete closed-loop agentic workflow.
---

View File

@@ -1,6 +1,6 @@
# GitHub Copilot SDK 官方管道
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.6.1 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
**作者:** [Fu-Jie](https://github.com/Fu-Jie/awesome-openwebui) | **版本:** 0.6.2 | **项目:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **许可证:** MIT
这是一个用于 [OpenWebUI](https://github.com/open-webui/open-webui) 的高级 Pipe 函数,深度集成了 **GitHub Copilot SDK**。它不仅支持 **GitHub Copilot 官方模型**(如 `gpt-5.2-codex`, `claude-sonnet-4.5`, `gemini-3-pro`, `gpt-5-mini`),还支持 **BYOK (自带 Key)** 模式对接自定义服务商OpenAI, Anthropic并具备**严格的用户与会话级工作区隔离**能力,提供统一且安全的 Agent 交互体验。
@@ -14,13 +14,12 @@
---
## ✨ 0.6.1 更新内容 (What's New)
## ✨ 0.6.2 更新内容 (What's New)
- **👥 多用户与会话管理**: 采用 `user_id/chat_id` 的物理隔离架构,确保资源独立与稳健管理
- **🤖 赋予 Agent 文件自主权**: 自动将上传的文件同步至物理工作区,支持 Python 直接分析 Excel/CSV
- **🔧 OpenAPI & 外部工具修复**: 完美支持通过 OpenAPI 服务器挂载的工具调用
- **📊 计费与成本控制**: 增强的**计费倍率限制** (`MAX_MULTIPLIER`,例如设为 0 即仅限免费模型) 和**模型关键词过滤** (`EXCLUDE_KEYWORDS`),实现更精准的成本管控
- **🧠 数据库持久化 TODO**: 任务进度跨会话保存Agent 拥有更持久的任务记忆。
- **🛠️ 新增工作区产物工具**: 引入 `publish_file_from_workspace`。Agent 现在可以生成物理文件(如使用 Python 生成的 Excel/CSV 报表),并直接在聊天界面提供点击下载链接
- **⚙️ 工作流优化**: 提升了内部 Agent 物理工作区管理的可靠性与原子性
- **🛡️ 安全增强**: 精细化了隔离环境下系统资源的访问控制策略
- **🔧 性能微调**: 针对大上下文窗口优化了流式数据处理性能
---
@@ -33,7 +32,7 @@
- **🧠 深度数据库集成**: 实时持久化 TOD·O 列表到 UI 进度条。
- **🌊 深度推理展示**: 完整支持模型思考过程 (Thinking Process) 的流式渲染。
- **🖼️ 智能多模态**: 完整支持图像识别与附件上传分析。
- **⚡ 交互式伪影 (Artifacts)**: 自动渲染 Agent 生成的 HTML/JS 应用程序,直接在聊天界面交互
- **⚡ 全生命周期文件 Agent**: 支持接收上传文件进行绕过 RAG 的深度分析,并将处理结果(如分析后的 Excel/报告)发布为可下载链接,实现完整的闭环 Agent 工作流
---

View File

@@ -5,7 +5,7 @@ author_url: https://github.com/Fu-Jie/awesome-openwebui
funding_url: https://github.com/open-webui
openwebui_id: ce96f7b4-12fc-4ac3-9a01-875713e69359
description: Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.
version: 0.6.1
version: 0.6.2
requirements: github-copilot-sdk==0.1.23
"""
@@ -44,6 +44,11 @@ from open_webui.config import (
from open_webui.utils.tools import get_tools as get_openwebui_tools, get_builtin_tools
from open_webui.models.tools import Tools
from open_webui.models.users import Users
from open_webui.models.files import Files, FileForm
from open_webui.config import UPLOAD_DIR, DATA_DIR
import mimetypes
import uuid
import shutil
# Open WebUI internal database (re-use shared connection)
try:
@@ -129,18 +134,22 @@ BASE_GUIDELINES = (
" - 2. **Render**: Immediately output the SAME code in a ` ```html ` block so the user can interact with it.\n"
" - **Result**: The user gets both a saved file AND a live app. Never force the user to choose one over the other.\n"
"4. **Images & Files**: ALWAYS embed generated images/files directly using `![caption](url)`. Never provide plain text links.\n"
"5. **TODO Visibility**: Every time you call the `update_todo` tool, you **MUST** immediately follow up with a beautifully formatted **Markdown summary** of the current TODO list. Use task checkboxes (`- [ ]`), progress indicators, and clear headings so the user can see the status directly in the chat.\n"
"6. **Python Execution Standard**: For ANY task requiring Python logic (not just data analysis), you **MUST NOT** embed multi-line code directly in a shell command (e.g., using `python -c` or `<< 'EOF'`).\n"
"5. **File Delivery & Publishing (CRITICAL)**:\n"
" - **Implicit Requests**: If the user says 'publish this', 'export your response', or 'give me a link to this content', you MUST: 1. Write the relevant content to a `.md` (or other appropriate) file in the current directory (`.`). 2. Call `publish_file_from_workspace(filename='name.md')` to get a link.\n"
" - **Manual Sequence**: 1. **Write Local**: Create the file in `.` (your only workspace). 2. **Publish**: Call `publish_file_from_workspace(filename='your_file.ext')`. **WARNING**: You MUST provide the filename argument; never call this tool with empty parentheses.\n"
" - *Rule*: Only files in the current directory (`.`) can be published. The tool bypasses RAG and handles S3/Local storage automatically.\n"
"6. **TODO Visibility**: Every time you call the `update_todo` tool, you **MUST** immediately follow up with a beautifully formatted **Markdown summary** of the current TODO list. Use task checkboxes (`- [ ]`), progress indicators, and clear headings so the user can see the status directly in the chat.\n"
"7. **Python Execution Standard**: For ANY task requiring Python logic (not just data analysis), you **MUST NOT** embed multi-line code directly in a shell command (e.g., using `python -c` or `<< 'EOF'`).\n"
' - **Exception**: Trivial one-liners (e.g., `python -c "print(1+1)"`) are permitted.\n'
" - **Protocol**: For everything else, you MUST:\n"
" 1. **Create** a `.py` file in the workspace (e.g., `script.py`).\n"
" 2. **Run** it using `python3 script.py`.\n"
" - **Reason**: This ensures code is debuggable, readable, and persistent.\n"
"7. **Active & Autonomous**: You are an expert engineer. **DO NOT** ask for permission to proceed with obvious steps. **DO NOT** stop to ask 'Shall I continue?'.\n"
"8. **Active & Autonomous**: You are an expert engineer. **DO NOT** ask for permission to proceed with obvious steps. **DO NOT** stop to ask 'Shall I continue?'.\n"
" - **Behavior**: Analyze the user's request -> Formulate a plan -> **EXECUTE** the plan immediately.\n"
" - **Clarification**: Only ask questions if the request is ambiguous or carries high risk (e.g., destructive actions).\n"
" - **Goal**: Minimize user friction. Deliver results, not questions.\n"
"8. **Large Output Management**: If a tool execution output is truncated or saved to a temporary file (e.g., `/tmp/...`), DO NOT worry. The system will automatically move it to your workspace and notify you of the new filename. You can then read it directly.\n"
"9. **Large Output Management**: If a tool execution output is truncated or saved to a temporary file (e.g., `/tmp/...`), DO NOT worry. The system will automatically move it to your workspace and notify you of the new filename. You can then read it directly.\n"
)
# Sensitive extensions only for Administrators
@@ -343,6 +352,7 @@ class Pipe:
# =============================================================
_model_cache: List[dict] = [] # Model list cache
_standard_model_ids: set = set() # Track standard model IDs
_last_byok_config_hash: str = "" # Track BYOK config for cache invalidation
_tool_cache = None # Cache for converted OpenWebUI tools
_mcp_server_cache = None # Cache for MCP server config
_env_setup_done = False # Track if env setup has been completed
@@ -488,6 +498,7 @@ class Pipe:
__user__: Optional[dict] = None,
__event_emitter__=None,
__event_call__=None,
__request__=None,
) -> Union[str, AsyncGenerator]:
return await self._pipe_impl(
body,
@@ -495,6 +506,7 @@ class Pipe:
__user__=__user__,
__event_emitter__=__event_emitter__,
__event_call__=__event_call__,
__request__=__request__,
)
# ==================== Functional Areas ====================
@@ -507,7 +519,12 @@ class Pipe:
# Tool registration: Add @define_tool decorated functions at module level,
# then register them in _initialize_custom_tools() -> all_tools dict.
async def _initialize_custom_tools(
self, body: dict = None, __user__=None, __event_call__=None
self,
body: dict = None,
__user__=None,
__event_call__=None,
__request__=None,
__metadata__=None,
):
"""Initialize custom tools based on configuration"""
# 1. Determine effective settings (User override > Global)
@@ -525,7 +542,17 @@ class Pipe:
await self._emit_debug_log(
" Using cached OpenWebUI tools.", __event_call__
)
return self._tool_cache
# Create a shallow copy to append user-specific tools without polluting cache
tools = list(self._tool_cache)
# Inject File Publish Tool
chat_ctx = self._get_chat_context(body, __metadata__)
chat_id = chat_ctx.get("chat_id")
file_tool = self._get_publish_file_tool(__user__, chat_id, __request__)
if file_tool:
tools.append(file_tool)
return tools
# Load OpenWebUI tools dynamically
openwebui_tools = await self._load_openwebui_tools(
@@ -557,7 +584,204 @@ class Pipe:
__event_call__,
)
return openwebui_tools
# Create a shallow copy to append user-specific tools without polluting cache
final_tools = list(openwebui_tools)
# Inject File Publish Tool
chat_ctx = self._get_chat_context(body, __metadata__)
chat_id = chat_ctx.get("chat_id")
file_tool = self._get_publish_file_tool(__user__, chat_id, __request__)
if file_tool:
final_tools.append(file_tool)
return final_tools
def _get_publish_file_tool(self, __user__, chat_id, __request__=None):
"""
Create a tool to publish files from the workspace to a downloadable URL.
"""
# Resolve user_id
if isinstance(__user__, (list, tuple)):
user_data = __user__[0] if __user__ else {}
elif isinstance(__user__, dict):
user_data = __user__
else:
user_data = {}
user_id = user_data.get("id") or user_data.get("user_id")
if not user_id:
return None
# Resolve workspace directory
workspace_dir = Path(self._get_workspace_dir(user_id=user_id, chat_id=chat_id))
# Define parameter schema explicitly for the SDK
class PublishFileParams(BaseModel):
filename: str = Field(
...,
description="The EXACT name of the file you just created in the current directory (e.g., 'report.csv'). REQUIRED.",
)
async def publish_file_from_workspace(filename: Any) -> dict:
"""
Publishes a file from the local chat workspace to a downloadable URL.
"""
try:
# 1. Robust Parameter Extraction
# Case A: filename is a Pydantic model (common when using params_type)
if hasattr(filename, "model_dump"): # Pydantic v2
filename = filename.model_dump().get("filename")
elif hasattr(filename, "dict"): # Pydantic v1
filename = filename.dict().get("filename")
# Case B: filename is a dict
if isinstance(filename, dict):
filename = (
filename.get("filename")
or filename.get("file")
or filename.get("file_path")
)
# Case C: filename is a JSON string or wrapped string
if isinstance(filename, str):
filename = filename.strip()
if filename.startswith("{"):
try:
import json
data = json.loads(filename)
if isinstance(data, dict):
filename = (
data.get("filename") or data.get("file") or filename
)
except:
pass
# 2. Final String Validation
if (
not filename
or not isinstance(filename, str)
or filename.strip() in ("", "{}", "None", "null")
):
return {
"error": "Missing or invalid required argument: 'filename'.",
"hint": f"Received value: {type(filename).__name__}. Please provide the filename as a simple string like 'report.md'.",
}
filename = filename.strip()
# 2. Path Resolution (Lock to current chat workspace)
target_path = workspace_dir / filename
try:
target_path = target_path.resolve()
if not str(target_path).startswith(str(workspace_dir.resolve())):
return {
"error": f"Access denied: File must be within the current chat workspace."
}
except Exception as e:
return {"error": f"Path validation failed: {e}"}
if not target_path.exists() or not target_path.is_file():
return {
"error": f"File '{filename}' not found in chat workspace. Ensure you saved it to the CURRENT DIRECTORY (.)."
}
# 3. Upload via API (S3 Compatible)
api_success = False
file_id = None
safe_filename = filename
token = None
if __request__:
auth_header = __request__.headers.get("Authorization")
if auth_header and auth_header.startswith("Bearer "):
token = auth_header.split(" ")[1]
if not token and "token" in __request__.cookies:
token = __request__.cookies.get("token")
if token:
try:
import aiohttp
base_url = str(__request__.base_url).rstrip("/")
upload_url = f"{base_url}/api/v1/files/"
async with aiohttp.ClientSession() as session:
with open(target_path, "rb") as f:
data = aiohttp.FormData()
data.add_field("file", f, filename=target_path.name)
import json
data.add_field(
"metadata",
json.dumps(
{
"source": "copilot_workspace_publish",
"skip_rag": True,
}
),
)
async with session.post(
upload_url,
data=data,
headers={"Authorization": f"Bearer {token}"},
) as resp:
if resp.status == 200:
api_result = await resp.json()
file_id = api_result.get("id")
safe_filename = api_result.get(
"filename", target_path.name
)
api_success = True
except Exception as e:
logger.error(f"API upload failed: {e}")
# 4. Fallback: Manual DB Insert (Local only)
if not api_success:
file_id = str(uuid.uuid4())
safe_filename = target_path.name
dest_path = Path(UPLOAD_DIR) / f"{file_id}_{safe_filename}"
await asyncio.to_thread(shutil.copy2, target_path, dest_path)
try:
db_path = str(os.path.relpath(dest_path, DATA_DIR))
except:
db_path = str(dest_path)
file_form = FileForm(
id=file_id,
filename=safe_filename,
path=db_path,
data={"status": "completed", "skip_rag": True},
meta={
"name": safe_filename,
"content_type": mimetypes.guess_type(safe_filename)[0]
or "text/plain",
"size": os.path.getsize(dest_path),
"source": "copilot_workspace_publish",
"skip_rag": True,
},
)
await asyncio.to_thread(Files.insert_new_file, user_id, file_form)
# 5. Result
download_url = f"/api/v1/files/{file_id}/content"
return {
"file_id": file_id,
"filename": safe_filename,
"download_url": download_url,
"message": "File published successfully.",
"hint": f"Link: [Download {safe_filename}]({download_url})",
}
except Exception as e:
return {"error": str(e)}
return define_tool(
name="publish_file_from_workspace",
description="Converts a file created in your local workspace into a downloadable URL. Use this tool AFTER writing a file to the current directory.",
params_type=PublishFileParams,
)(publish_file_from_workspace)
def _json_schema_to_python_type(self, schema: dict) -> Any:
"""Convert JSON Schema type to Python type for Pydantic models."""
@@ -1756,13 +1980,17 @@ class Pipe:
async def _fetch_byok_models(self, uv: "Pipe.UserValves" = None) -> List[dict]:
"""Fetch BYOK models from configured provider."""
model_list = []
# Resolve effective settings (User > Global)
# Note: We handle the case where uv might be None
effective_base_url = (uv.BYOK_BASE_URL if uv else "") or self.valves.BYOK_BASE_URL
effective_base_url = (
uv.BYOK_BASE_URL if uv else ""
) or self.valves.BYOK_BASE_URL
effective_type = (uv.BYOK_TYPE if uv else "") or self.valves.BYOK_TYPE
effective_api_key = (uv.BYOK_API_KEY if uv else "") or self.valves.BYOK_API_KEY
effective_bearer_token = (uv.BYOK_BEARER_TOKEN if uv else "") or self.valves.BYOK_BEARER_TOKEN
effective_bearer_token = (
uv.BYOK_BEARER_TOKEN if uv else ""
) or self.valves.BYOK_BEARER_TOKEN
effective_models = (uv.BYOK_MODELS if uv else "") or self.valves.BYOK_MODELS
if effective_base_url:
@@ -1778,9 +2006,7 @@ class Pipe:
headers["anthropic-version"] = "2023-06-01"
else:
if effective_bearer_token:
headers["Authorization"] = (
f"Bearer {effective_bearer_token}"
)
headers["Authorization"] = f"Bearer {effective_bearer_token}"
elif effective_api_key:
headers["Authorization"] = f"Bearer {effective_api_key}"
@@ -1813,7 +2039,9 @@ class Pipe:
f"BYOK: Failed to fetch models from {url} (Attempt {attempt+1}/3). Status: {resp.status}"
)
except Exception as e:
await self._emit_debug_log(f"BYOK: Model fetch error (Attempt {attempt+1}/3): {e}")
await self._emit_debug_log(
f"BYOK: Model fetch error (Attempt {attempt+1}/3): {e}"
)
if attempt < 2:
await asyncio.sleep(1)
@@ -1941,7 +2169,25 @@ class Pipe:
if k.strip()
]
# --- NEW: CONFIG-AWARE CACHE INVALIDATION ---
# Calculate current config fingerprint to detect changes
current_config_str = f"{token}|{uv.BYOK_BASE_URL or self.valves.BYOK_BASE_URL}|{uv.BYOK_API_KEY or self.valves.BYOK_API_KEY}|{self.valves.BYOK_BEARER_TOKEN}"
current_config_hash = hashlib.md5(current_config_str.encode()).hexdigest()
if (
self._model_cache
and self.__class__._last_byok_config_hash != current_config_hash
):
if self.valves.DEBUG:
logger.info(
f"[Pipes] Configuration change detected. Invalidating model cache."
)
self.__class__._model_cache = []
self.__class__._last_byok_config_hash = current_config_hash
if not self._model_cache:
# Update the hash when we refresh the cache
self.__class__._last_byok_config_hash = current_config_hash
if self.valves.DEBUG:
logger.info("[Pipes] Refreshing model cache...")
try:
@@ -2437,6 +2683,7 @@ class Pipe:
__user__: Optional[dict] = None,
__event_emitter__=None,
__event_call__=None,
__request__=None,
) -> Union[str, AsyncGenerator]:
# --- PROBE LOG ---
if __event_call__:
@@ -2716,7 +2963,11 @@ class Pipe:
# Initialize custom tools (Handles caching internally)
custom_tools = await self._initialize_custom_tools(
body=body, __user__=__user__, __event_call__=__event_call__
body=body,
__user__=__user__,
__event_call__=__event_call__,
__request__=__request__,
__metadata__=__metadata__,
)
if custom_tools:
tool_names = [t.name for t in custom_tools]
@@ -3468,4 +3719,6 @@ class Pipe:
await client.stop()
except Exception as e:
pass
# Triggering release after CI fix

View File

@@ -4,7 +4,7 @@ author: Fu-Jie
author_url: https://github.com/Fu-Jie/awesome-openwebui
funding_url: https://github.com/open-webui
description: 集成 GitHub Copilot SDK。支持动态模型、多选提供商、流式输出、多模态 input、无限会话及前端调试日志。
version: 0.6.1
version: 0.6.2
requirements: github-copilot-sdk==0.1.23
"""
@@ -35,6 +35,11 @@ from open_webui.config import (
from open_webui.utils.tools import get_tools as get_openwebui_tools, get_builtin_tools
from open_webui.models.tools import Tools
from open_webui.models.users import Users
from open_webui.models.files import Files, FileForm
from open_webui.config import UPLOAD_DIR, DATA_DIR
import mimetypes
import uuid
import shutil
# Setup logger
logger = logging.getLogger(__name__)
@@ -58,6 +63,10 @@ FORMATTING_GUIDELINES = (
"1. **Markdown & 多媒体**:自由使用粗体、斜体、表格和列表。\n"
"2. **Mermaid 图表**:请务必使用标准的 ```mermaid 代码块。\n"
"3. **交互式 HTML/JS**:你可以输出完整的 ```html 代码块(含 CSS/JS将在 iframe 中渲染。\n"
"4. **文件交付与发布 (关键规范)**\n"
" - **隐式请求**若用户要求“发布这个”、“导出刚才的内容”或“给我一个链接”你必须1. 将内容写入当前目录 (`.`) 下的 `.md` (或其他合适) 文件。2. 调用 `publish_file_from_workspace(filename='name.md')` 获取链接。\n"
" - **标准流程**1. **本地写入**:使用 Python 在**当前目录 (`.`)** 创建文件。这是你的唯一工作区。**严禁**使用 `/tmp` 等绝对路径。2. **显式发布**:调用 `publish_file_from_workspace(filename='your_file.ext')`。该工具会自动同步至 S3 并绕过 RAG。3. **呈现链接**:从工具返回的 JSON 中提取 `download_url`,并以 Markdown 链接 `[点击下载描述](url)` 展示。\n"
" - **规则**:只有当前目录 (`.`) 下的文件可以发布。调用时必须传入 `filename` 参数,严禁空调用。\n"
"7. **主动与自主**: 你是专家工程师。对于显而易见的步骤,**不要**请求许可。**不要**停下来问“我通过吗?”或“是否继续?”。\n"
" - **行为模式**: 分析用户请求 -> 制定计划 -> **立即执行**计划。\n"
" - **澄清**: 仅当请求模棱两可或具有高风险(例如破坏性操作)时才提出问题。\n"
@@ -230,6 +239,7 @@ class Pipe:
)
_model_cache: List[dict] = []
_last_byok_config_hash: str = "" # 跟踪配置状态以失效缓存
_standard_model_ids: set = set()
_tool_cache = None
_mcp_server_cache = None
@@ -256,13 +266,24 @@ class Pipe:
__user__=None,
__event_emitter__=None,
__event_call__=None,
__request__=None,
) -> Union[str, AsyncGenerator]:
return await self._pipe_impl(
body, __metadata__, __user__, __event_emitter__, __event_call__
body,
__metadata__=__metadata__,
__user__=__user__,
__event_emitter__=__event_emitter__,
__event_call__=__event_call__,
__request__=__request__,
)
async def _initialize_custom_tools(
self, __user__=None, __event_call__=None, body: dict = None
self,
body: dict = None,
__user__=None,
__event_call__=None,
__request__=None,
__metadata__=None,
):
"""基于配置初始化自定义工具"""
# 1. 确定有效设置 (用户覆盖 > 全局)
@@ -275,13 +296,22 @@ class Pipe:
if not enable_tools and not enable_openapi:
return []
# 提取 Chat ID 以对齐工作空间
chat_ctx = self._get_chat_context(body, __metadata__)
chat_id = chat_ctx.get("chat_id")
# 3. 检查缓存
if enable_cache and self._tool_cache is not None:
await self._emit_debug_log(" 使用缓存的 OpenWebUI 工具。", __event_call__)
return self._tool_cache
tools = list(self._tool_cache)
# 注入文件发布工具
file_tool = self._get_publish_file_tool(__user__, chat_id, __request__)
if file_tool:
tools.append(file_tool)
return tools
# 动态加载 OpenWebUI 工具
tools = await self._load_openwebui_tools(
openwebui_tools = await self._load_openwebui_tools(
__user__=__user__,
__event_call__=__event_call__,
body=body,
@@ -291,12 +321,194 @@ class Pipe:
# 更新缓存
if enable_cache:
self._tool_cache = tools
self._tool_cache = openwebui_tools
await self._emit_debug_log(
"✅ OpenWebUI 工具已缓存,供后续请求使用。", __event_call__
)
return tools
final_tools = list(openwebui_tools)
# 注入文件发布工具
file_tool = self._get_publish_file_tool(__user__, chat_id, __request__)
if file_tool:
final_tools.append(file_tool)
return final_tools
def _get_publish_file_tool(self, __user__, chat_id, __request__=None):
"""创建发布工作区文件为下载链接的工具"""
if isinstance(__user__, (list, tuple)):
user_data = __user__[0] if __user__ else {}
elif isinstance(__user__, dict):
user_data = __user__
else:
user_data = {}
user_id = user_data.get("id") or user_data.get("user_id")
if not user_id:
return None
# 锁定当前聊天的隔离工作空间
workspace_dir = Path(self._get_workspace_dir(user_id=user_id, chat_id=chat_id))
# 为 SDK 定义参数 Schema
class PublishFileParams(BaseModel):
filename: str = Field(
...,
description="你在当前目录创建的文件的确切名称(如 'report.csv')。必填。",
)
async def publish_file_from_workspace(filename: Any) -> dict:
"""将本地聊天工作区的文件发布为可下载的 URL。"""
try:
# 1. 参数鲁棒提取
if hasattr(filename, "model_dump"): # Pydantic v2
filename = filename.model_dump().get("filename")
elif hasattr(filename, "dict"): # Pydantic v1
filename = filename.dict().get("filename")
if isinstance(filename, dict):
filename = (
filename.get("filename")
or filename.get("file")
or filename.get("file_path")
)
if isinstance(filename, str):
filename = filename.strip()
if filename.startswith("{"):
try:
import json
data = json.loads(filename)
if isinstance(data, dict):
filename = (
data.get("filename") or data.get("file") or filename
)
except:
pass
if (
not filename
or not isinstance(filename, str)
or filename.strip() in ("", "{}", "None", "null")
):
return {
"error": "缺少必填参数: 'filename'",
"hint": "请以字符串形式提供文件名,例如 'report.md'",
}
filename = filename.strip()
# 2. 路径解析(锁定当前聊天工作区)
target_path = workspace_dir / filename
try:
target_path = target_path.resolve()
if not str(target_path).startswith(str(workspace_dir.resolve())):
return {"error": "拒绝访问:文件必须位于当前聊天工作区内。"}
except Exception as e:
return {"error": f"路径校验失败: {e}"}
if not target_path.exists() or not target_path.is_file():
return {
"error": f"在聊天工作区未找到文件 '{filename}'。请确保你已将其保存到当前目录 (.)。"
}
# 3. 通过 API 上传 (兼容 S3)
api_success = False
file_id = None
safe_filename = filename
token = None
if __request__:
auth_header = __request__.headers.get("Authorization")
if auth_header and auth_header.startswith("Bearer "):
token = auth_header.split(" ")[1]
if not token and "token" in __request__.cookies:
token = __request__.cookies.get("token")
if token:
try:
import aiohttp
base_url = str(__request__.base_url).rstrip("/")
upload_url = f"{base_url}/api/v1/files/"
async with aiohttp.ClientSession() as session:
with open(target_path, "rb") as f:
data = aiohttp.FormData()
data.add_field("file", f, filename=target_path.name)
import json
data.add_field(
"metadata",
json.dumps(
{
"source": "copilot_workspace_publish",
"skip_rag": True,
}
),
)
async with session.post(
upload_url,
data=data,
headers={"Authorization": f"Bearer {token}"},
) as resp:
if resp.status == 200:
api_res = await resp.json()
file_id = api_res.get("id")
safe_filename = api_res.get(
"filename", target_path.name
)
api_success = True
except Exception as e:
logger.error(f"API 上传失败: {e}")
# 4. 兜底:手动插入数据库 (仅限本地存储)
if not api_success:
file_id = str(uuid.uuid4())
safe_filename = target_path.name
dest_path = Path(UPLOAD_DIR) / f"{file_id}_{safe_filename}"
await asyncio.to_thread(shutil.copy2, target_path, dest_path)
try:
db_path = str(os.path.relpath(dest_path, DATA_DIR))
except:
db_path = str(dest_path)
file_form = FileForm(
id=file_id,
filename=safe_filename,
path=db_path,
data={"status": "completed", "skip_rag": True},
meta={
"name": safe_filename,
"content_type": mimetypes.guess_type(safe_filename)[0]
or "text/plain",
"size": os.path.getsize(dest_path),
"source": "copilot_workspace_publish",
"skip_rag": True,
},
)
await asyncio.to_thread(Files.insert_new_file, user_id, file_form)
# 5. 返回结果
download_url = f"/api/v1/files/{file_id}/content"
return {
"file_id": file_id,
"filename": safe_filename,
"download_url": download_url,
"message": "文件发布成功。",
"hint": f"链接: [下载 {safe_filename}]({download_url})",
}
except Exception as e:
return {"error": str(e)}
return define_tool(
name="publish_file_from_workspace",
description="将你在本地工作区创建的文件转换为可下载的 URL。请在完成文件写入当前目录后再使用此工具。",
params_type=PublishFileParams,
)(publish_file_from_workspace)
def _json_schema_to_python_type(self, schema: dict) -> Any:
if not isinstance(schema, dict):
@@ -782,12 +994,16 @@ class Pipe:
async def _fetch_byok_models(self, uv: "Pipe.UserValves" = None) -> List[dict]:
"""从配置的提供商获取 BYOK 模型。"""
model_list = []
# 确定有效配置 (用户 > 全局)
effective_base_url = (uv.BYOK_BASE_URL if uv else "") or self.valves.BYOK_BASE_URL
effective_base_url = (
uv.BYOK_BASE_URL if uv else ""
) or self.valves.BYOK_BASE_URL
effective_type = (uv.BYOK_TYPE if uv else "") or self.valves.BYOK_TYPE
effective_api_key = (uv.BYOK_API_KEY if uv else "") or self.valves.BYOK_API_KEY
effective_bearer_token = (uv.BYOK_BEARER_TOKEN if uv else "") or self.valves.BYOK_BEARER_TOKEN
effective_bearer_token = (
uv.BYOK_BEARER_TOKEN if uv else ""
) or self.valves.BYOK_BEARER_TOKEN
effective_models = (uv.BYOK_MODELS if uv else "") or self.valves.BYOK_MODELS
if effective_base_url:
@@ -803,9 +1019,7 @@ class Pipe:
headers["anthropic-version"] = "2023-06-01"
else:
if effective_bearer_token:
headers["Authorization"] = (
f"Bearer {effective_bearer_token}"
)
headers["Authorization"] = f"Bearer {effective_bearer_token}"
elif effective_api_key:
headers["Authorization"] = f"Bearer {effective_api_key}"
@@ -828,7 +1042,7 @@ class Pipe:
for item in data:
if isinstance(item, dict) and "id" in item:
model_list.append(item["id"])
await self._emit_debug_log(
f"BYOK: 从 {url} 获取了 {len(model_list)} 个模型"
)
@@ -838,8 +1052,10 @@ class Pipe:
f"BYOK: 获取模型失败 {url} (尝试 {attempt+1}/3). 状态码: {resp.status}"
)
except Exception as e:
await self._emit_debug_log(f"BYOK: 模型获取错误 (尝试 {attempt+1}/3): {e}")
await self._emit_debug_log(
f"BYOK: 模型获取错误 (尝试 {attempt+1}/3): {e}"
)
if attempt < 2:
await asyncio.sleep(1)
@@ -1001,6 +1217,7 @@ class Pipe:
__user__=None,
__event_emitter__=None,
__event_call__=None,
__request__=None,
) -> Union[str, AsyncGenerator]:
ud = __user__[0] if isinstance(__user__, (list, tuple)) else (__user__ or {})
uid = ud.get("id") or ud.get("user_id") or "default_user"
@@ -1057,7 +1274,14 @@ class Pipe:
client = CopilotClient(self._build_client_config(body, uid, cid))
try:
await client.start()
tools = await self._initialize_custom_tools(__user__, __event_call__, body)
# 同步更新工具初始化参数
tools = await self._initialize_custom_tools(
body=body,
__user__=__user__,
__event_call__=__event_call__,
__request__=__request__,
__metadata__=__metadata__,
)
prov = (
{
"type": (uv.BYOK_TYPE or self.valves.BYOK_TYPE).lower() or "openai",
@@ -1162,8 +1386,11 @@ class Pipe:
# 环境初始化 (带有 24 小时冷却时间)
from datetime import datetime
now = datetime.now().timestamp()
if not self.__class__._env_setup_done or (now - self.__class__._last_update_check > 86400):
if not self.__class__._env_setup_done or (
now - self.__class__._last_update_check > 86400
):
self._setup_env(debug_enabled=uv.DEBUG or self.valves.DEBUG, token=token)
elif token:
os.environ["GH_TOKEN"] = os.environ["GITHUB_TOKEN"] = token
@@ -1174,17 +1401,48 @@ class Pipe:
eff_max = uv.MAX_MULTIPLIER
# 确定关键词和提供商过滤
ex_kw = [k.strip().lower() for k in (self.valves.EXCLUDE_KEYWORDS + "," + uv.EXCLUDE_KEYWORDS).split(",") if k.strip()]
allowed_p = [p.strip().lower() for p in (uv.PROVIDERS if uv.PROVIDERS else self.valves.PROVIDERS).split(",") if p.strip()]
ex_kw = [
k.strip().lower()
for k in (self.valves.EXCLUDE_KEYWORDS + "," + uv.EXCLUDE_KEYWORDS).split(
","
)
if k.strip()
]
allowed_p = [
p.strip().lower()
for p in (uv.PROVIDERS if uv.PROVIDERS else self.valves.PROVIDERS).split(
","
)
if p.strip()
]
# --- 新增:配置感知缓存刷新 ---
# 计算当前配置指纹以检测变化
current_config_str = f"{token}|{(uv.BYOK_BASE_URL if uv else '') or self.valves.BYOK_BASE_URL}|{(uv.BYOK_API_KEY if uv else '') or self.valves.BYOK_API_KEY}|{(uv.BYOK_BEARER_TOKEN if uv else '') or self.valves.BYOK_BEARER_TOKEN}"
import hashlib
current_config_hash = hashlib.md5(current_config_str.encode()).hexdigest()
if (
self._model_cache
and self.__class__._last_byok_config_hash != current_config_hash
):
self.__class__._model_cache = []
self.__class__._last_byok_config_hash = current_config_hash
# 如果缓存为空,刷新模型列表
if not self._model_cache:
self.__class__._last_byok_config_hash = current_config_hash
byok_models = []
standard_models = []
# 1. 获取 BYOK 模型 (优先使用个人设置)
if ((uv.BYOK_BASE_URL if uv else "") or self.valves.BYOK_BASE_URL) and \
((uv.BYOK_API_KEY if uv else "") or self.valves.BYOK_API_KEY or (uv.BYOK_BEARER_TOKEN if uv else "") or self.valves.BYOK_BEARER_TOKEN):
if ((uv.BYOK_BASE_URL if uv else "") or self.valves.BYOK_BASE_URL) and (
(uv.BYOK_API_KEY if uv else "")
or self.valves.BYOK_API_KEY
or (uv.BYOK_BEARER_TOKEN if uv else "")
or self.valves.BYOK_BEARER_TOKEN
):
byok_models = await self._fetch_byok_models(uv=uv)
# 2. 获取标准 Copilot 模型
@@ -1194,55 +1452,91 @@ class Pipe:
raw_models = await c.list_models()
raw = raw_models if isinstance(raw_models, list) else []
processed = []
for m in raw:
try:
m_is_dict = isinstance(m, dict)
mid = m.get("id") if m_is_dict else getattr(m, "id", str(m))
bill = m.get("billing") if m_is_dict else getattr(m, "billing", None)
bill = (
m.get("billing")
if m_is_dict
else getattr(m, "billing", None)
)
if bill and not isinstance(bill, dict):
bill = bill.to_dict() if hasattr(bill, "to_dict") else vars(bill)
pol = m.get("policy") if m_is_dict else getattr(m, "policy", None)
bill = (
bill.to_dict()
if hasattr(bill, "to_dict")
else vars(bill)
)
pol = (
m.get("policy")
if m_is_dict
else getattr(m, "policy", None)
)
if pol and not isinstance(pol, dict):
pol = pol.to_dict() if hasattr(pol, "to_dict") else vars(pol)
pol = (
pol.to_dict()
if hasattr(pol, "to_dict")
else vars(pol)
)
if (pol or {}).get("state") == "disabled":
continue
cap = m.get("capabilities") if m_is_dict else getattr(m, "capabilities", None)
cap = (
m.get("capabilities")
if m_is_dict
else getattr(m, "capabilities", None)
)
vis, reas, ctx, supp = False, False, None, []
if cap:
if not isinstance(cap, dict):
cap = cap.to_dict() if hasattr(cap, "to_dict") else vars(cap)
cap = (
cap.to_dict()
if hasattr(cap, "to_dict")
else vars(cap)
)
s = cap.get("supports", {})
vis, reas = s.get("vision", False), s.get("reasoning_effort", False)
vis, reas = s.get("vision", False), s.get(
"reasoning_effort", False
)
l = cap.get("limits", {})
ctx = l.get("max_context_window_tokens")
raw_eff = (m.get("supported_reasoning_efforts") if m_is_dict else getattr(m, "supported_reasoning_efforts", [])) or []
raw_eff = (
m.get("supported_reasoning_efforts")
if m_is_dict
else getattr(m, "supported_reasoning_efforts", [])
) or []
supp = [str(e).lower() for e in raw_eff if e]
mult = (bill or {}).get("multiplier", 1)
cid = self._clean_model_id(mid)
processed.append({
"id": f"{self.id}-{mid}",
"name": f"-{cid} ({mult}x)" if mult > 0 else f"-🔥 {cid} (0x)",
"multiplier": mult,
"raw_id": mid,
"source": "copilot",
"provider": self._get_provider_name(m),
"meta": {
"capabilities": {
"vision": vis,
"reasoning": reas,
"supported_reasoning_efforts": supp,
processed.append(
{
"id": f"{self.id}-{mid}",
"name": (
f"-{cid} ({mult}x)"
if mult > 0
else f"-🔥 {cid} (0x)"
),
"multiplier": mult,
"raw_id": mid,
"source": "copilot",
"provider": self._get_provider_name(m),
"meta": {
"capabilities": {
"vision": vis,
"reasoning": reas,
"supported_reasoning_efforts": supp,
},
"context_length": ctx,
},
"context_length": ctx,
},
})
}
)
except:
continue
processed.sort(key=lambda x: (x["multiplier"], x["raw_id"]))
standard_models = processed
self._standard_model_ids = {m["raw_id"] for m in processed}
@@ -1254,7 +1548,9 @@ class Pipe:
self._model_cache = standard_models + byok_models
if not self._model_cache:
return [{"id": "error", "name": "未找到任何模型。请检查 Token 或 BYOK 配置。"}]
return [
{"id": "error", "name": "未找到任何模型。请检查 Token 或 BYOK 配置。"}
]
# 3. 实时过滤结果
res = []
@@ -1262,19 +1558,21 @@ class Pipe:
# 提供商过滤
if allowed_p and m.get("provider", "Unknown").lower() not in allowed_p:
continue
mid, mname = (m.get("raw_id") or m.get("id", "")).lower(), m.get("name", "").lower()
mid, mname = (m.get("raw_id") or m.get("id", "")).lower(), m.get(
"name", ""
).lower()
# 关键词过滤
if any(kw in mid or kw in mname for kw in ex_kw):
continue
# 倍率限制 (仅限 Copilot 官方模型)
if m.get("source") == "copilot":
if float(m.get("multiplier", 1)) > (float(eff_max) + 0.0001):
continue
res.append(m)
return res if res else [{"id": "none", "name": "没有匹配当前过滤条件的模型"}]
async def stream_response(