Compare commits
1 Commits
v2026.02.2
...
copilot/op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00e2593801 |
@@ -1,147 +0,0 @@
|
||||
---
|
||||
description: >
|
||||
Antigravity development mode rules. Apply when the user requests high-speed iteration,
|
||||
a quick prototype, or says "反重力开发" / "antigravity mode".
|
||||
globs: "plugins/**/*.py"
|
||||
always_on: false
|
||||
---
|
||||
# Antigravity Development Mode
|
||||
|
||||
> High-speed delivery + strict reversibility. Every decision must keep both roll-forward and rollback feasible.
|
||||
|
||||
---
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. **Small, isolated edits** — one logical change per operation; no mixing refactor + feature.
|
||||
2. **Deterministic interfaces** — function signatures and return shapes must not change without an explicit contract update.
|
||||
3. **Multi-level fallback** — every I/O path has a degraded alternative (e.g., S3 → local → DB).
|
||||
4. **Reversible by default** — every file write, API call, or schema change must have an undo path recorded or be idempotent.
|
||||
|
||||
---
|
||||
|
||||
## Mandatory Safety Patterns
|
||||
|
||||
### 1. Timeout Guards on All Frontend Calls
|
||||
|
||||
Any `__event_call__` or `__event_emitter__` JS execution MUST be wrapped:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
try:
|
||||
result = await asyncio.wait_for(
|
||||
__event_call__({"type": "execute", "data": {"code": js_code}}),
|
||||
timeout=2.0
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning("Frontend JS execution timed out; falling back.")
|
||||
result = fallback_value
|
||||
except Exception as e:
|
||||
logger.error(f"Frontend call failed: {e}", exc_info=True)
|
||||
result = fallback_value
|
||||
```
|
||||
|
||||
JS side must also guard internally:
|
||||
|
||||
```javascript
|
||||
try {
|
||||
return (localStorage.getItem('locale') || navigator.language || 'en-US');
|
||||
} catch (e) {
|
||||
return 'en-US';
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Path Sandbox Validation
|
||||
|
||||
Resolve every workspace path and verify it stays inside the repo root:
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
def _validate_workspace_path(path: str, workspace_root: str) -> str:
|
||||
resolved = os.path.realpath(os.path.abspath(path))
|
||||
root = os.path.realpath(workspace_root)
|
||||
if not resolved.startswith(root + os.sep) and resolved != root:
|
||||
raise PermissionError(f"Path escape detected: {resolved} is outside {root}")
|
||||
return resolved
|
||||
```
|
||||
|
||||
### 3. Dual-Channel Upload Fallback
|
||||
|
||||
Always try API first; fall back to DB/local on failure:
|
||||
|
||||
```python
|
||||
async def _upload_file(self, filename: str, content: bytes) -> str:
|
||||
# Channel 1: API upload (S3-compatible)
|
||||
try:
|
||||
url = await self._api_upload(filename, content)
|
||||
if url:
|
||||
return url
|
||||
except Exception as e:
|
||||
logger.warning(f"API upload failed: {e}; falling back to local.")
|
||||
|
||||
# Channel 2: Local file + DB registration
|
||||
return await self._local_db_upload(filename, content)
|
||||
```
|
||||
|
||||
### 4. Progressive Status Reporting
|
||||
|
||||
For tasks > 3 seconds, emit staged updates:
|
||||
|
||||
```python
|
||||
await self._emit_status(emitter, "正在分析内容...", done=False)
|
||||
# ... phase 1 ...
|
||||
await self._emit_status(emitter, "正在生成输出...", done=False)
|
||||
# ... phase 2 ...
|
||||
await self._emit_status(emitter, "完成", done=True)
|
||||
```
|
||||
|
||||
Always emit `done=True` on completion and `notification(error)` on failure.
|
||||
|
||||
### 5. Emitter Guard
|
||||
|
||||
Check before every emit to prevent crashes on missing emitter:
|
||||
|
||||
```python
|
||||
if emitter and self.valves.SHOW_STATUS:
|
||||
await emitter({"type": "status", "data": {"description": msg, "done": done}})
|
||||
```
|
||||
|
||||
### 6. Exception Surface Rule
|
||||
|
||||
Never swallow exceptions silently. Every `except` block must:
|
||||
|
||||
- Log to backend: `logger.error(f"...: {e}", exc_info=True)`
|
||||
- Notify user: `await self._emit_notification(emitter, f"处理失败: {str(e)}", "error")`
|
||||
|
||||
---
|
||||
|
||||
## Edit Discipline
|
||||
|
||||
| ✅ DO | ❌ DO NOT |
|
||||
|-------|-----------|
|
||||
| One function / one Valve / one method per edit | Mix multiple unrelated changes in one operation |
|
||||
| Validate input at the function boundary | Assume upstream data is well-formed |
|
||||
| Return early on invalid state | Nest complex logic beyond 3 levels |
|
||||
| Check fallback availability before primary path | Assume primary path always succeeds |
|
||||
| Log before and after expensive I/O | Skip logging for "obvious" operations |
|
||||
|
||||
---
|
||||
|
||||
## Rollback Checklist
|
||||
|
||||
Before completing an antigravity operation, confirm:
|
||||
|
||||
- [ ] No global state mutated on `self` (filter singleton rule)
|
||||
- [ ] File writes are atomic or can be recreated
|
||||
- [ ] Database changes are idempotent (safe to re-run)
|
||||
- [ ] Timeout guards are in place for all async calls to external systems
|
||||
- [ ] The user can observe progress through status/notification events
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Full engineering spec: `.github/copilot-instructions.md` → Section: **Antigravity Development Mode**
|
||||
- Design document: `docs/development/copilot-engineering-plan.md` → Section 5
|
||||
@@ -12,11 +12,11 @@ Reference: `.github/copilot-instructions.md`
|
||||
|
||||
### Bilingual Requirement
|
||||
|
||||
Every plugin **MUST** have a single internationalized code file and bilingual documentation:
|
||||
Every plugin **MUST** have bilingual versions for both code and documentation:
|
||||
|
||||
- **Code (i18n)**:
|
||||
- `plugins/{type}/{name}/{name}.py`
|
||||
- The single `.py` file must implement internal i18n (e.g., using `navigator.language` or backend headers) to support multiple languages natively, rather than splitting into separate files.
|
||||
- **Code**:
|
||||
- English: `plugins/{type}/{name}/{name}.py`
|
||||
- Chinese: `plugins/{type}/{name}/{name_cn}.py` (or `中文名.py`)
|
||||
- **README**:
|
||||
- English: `plugins/{type}/{name}/README.md`
|
||||
- Chinese: `plugins/{type}/{name}/README_CN.md`
|
||||
@@ -81,13 +81,14 @@ Reference: `.github/workflows/release.yml`
|
||||
- **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. Code (`.py`)
|
||||
2. English README (`README.md`)
|
||||
3. Chinese README (`README_CN.md`)
|
||||
4. Docs Index (`docs/.../index.md`)
|
||||
5. Docs Index CN (`docs/.../index.zh.md`)
|
||||
6. Docs Detail (`docs/.../{name}.md`)
|
||||
7. Docs Detail CN (`docs/.../{name}.zh.md`)
|
||||
1. English Code (`.py`)
|
||||
2. Chinese Code (`.py`)
|
||||
3. English README (`README.md`)
|
||||
4. Chinese README (`README_CN.md`)
|
||||
5. Docs Index (`docs/.../index.md`)
|
||||
6. Docs Index CN (`docs/.../index.zh.md`)
|
||||
7. Docs Detail (`docs/.../{name}.md`)
|
||||
8. Docs Detail CN (`docs/.../{name}.zh.md`)
|
||||
|
||||
### Automated Release Process
|
||||
|
||||
@@ -119,7 +120,7 @@ When the user confirms a release, the agent **MUST** follow these content standa
|
||||
- Before committing, present a "Release Draft" containing:
|
||||
- **Title**: e.g., `Release v0.1.1: [Plugin Name] - [Brief Summary]`
|
||||
- **Changelog**: English-only list of commits since the last release, including hashes (e.g., `896de02 docs(config): reorder antigravity model alias example`).
|
||||
- **Verification Status**: Confirm all 7+ files have been updated and synced.
|
||||
- **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
|
||||
@@ -133,7 +134,7 @@ When the user confirms a release, the agent **MUST** follow these content standa
|
||||
|
||||
Before committing:
|
||||
|
||||
- [ ] Code is internal i18n supported (`.py`) and fully functional?
|
||||
- [ ] Code is bilingual and functional?
|
||||
- [ ] Docstrings have updated version?
|
||||
- [ ] READMEs are updated and bilingual?
|
||||
- [ ] **Key Capabilities** in READMEs still cover all legacy core features + new features?
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Agent Skills Index
|
||||
|
||||
This folder contains reusable Agent Skills for GitHub Copilot / VS Code custom agent workflows.
|
||||
|
||||
## Available Skills
|
||||
|
||||
- **community-announcer**
|
||||
- Purpose: Generate community announcement content and related assets.
|
||||
- Entry: `community-announcer/SKILL.md`
|
||||
|
||||
- **doc-mirror-sync**
|
||||
- Purpose: Sync mirrored documentation content and helper scripts.
|
||||
- Entry: `doc-mirror-sync/SKILL.md`
|
||||
|
||||
- **gh-issue-replier**
|
||||
- Purpose: Draft standardized issue replies with templates.
|
||||
- Entry: `gh-issue-replier/SKILL.md`
|
||||
|
||||
- **gh-issue-scheduler**
|
||||
- Purpose: Schedule and discover unanswered issues for follow-up.
|
||||
- Entry: `gh-issue-scheduler/SKILL.md`
|
||||
|
||||
- **i18n-validator**
|
||||
- Purpose: Validate translation key consistency across i18n dictionaries.
|
||||
- Entry: `i18n-validator/SKILL.md`
|
||||
|
||||
- **plugin-scaffolder**
|
||||
- Purpose: Scaffold OpenWebUI plugin boilerplate with repository standards.
|
||||
- Entry: `plugin-scaffolder/SKILL.md`
|
||||
|
||||
- **version-bumper**
|
||||
- Purpose: Assist with semantic version bumping workflows.
|
||||
- Entry: `version-bumper/SKILL.md`
|
||||
|
||||
- **xlsx-single-file**
|
||||
- Purpose: Single-file spreadsheet operations workflow without LibreOffice.
|
||||
- Entry: `xlsx-single-file/SKILL.md`
|
||||
|
||||
## Notes
|
||||
|
||||
- Skill definitions follow the expected location pattern:
|
||||
- `.github/skills/<skill-name>/SKILL.md`
|
||||
- Each skill may include optional `assets/`, `references/`, and `scripts/` folders.
|
||||
- This directory mirrors `.gemini/skills` for compatibility.
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
name: community-announcer
|
||||
description: Drafts engaging English and Chinese update announcements for the OpenWebUI Community and other social platforms. Use when a new version is released.
|
||||
---
|
||||
|
||||
# Community Announcer
|
||||
|
||||
## Overview
|
||||
Automates the drafting of high-impact update announcements.
|
||||
|
||||
## Workflow
|
||||
1. **Source Intel**: Read the latest version's `What's New` section from `README.md`.
|
||||
2. **Drafting**: Create two versions:
|
||||
- **Community Post**: Professional, structured, technical.
|
||||
- **Catchy Short**: For Discord/Twitter, use emojis and bullet points.
|
||||
3. **Multi-language**: Generate BOTH English and Chinese versions automatically.
|
||||
|
||||
## Announcement Structure (Recommended)
|
||||
- **Headline**: "Update vX.X.X - [Main Feature]"
|
||||
- **Introduction**: Brief context.
|
||||
- **Key Highlights**: Bulleted list of fixes/features.
|
||||
- **Action**: "Download from [Market Link]"
|
||||
- **Closing**: Thanks and Star request.
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: doc-mirror-sync
|
||||
description: Automatically synchronizes plugin READMEs to the official documentation directory (docs/). Use after editing a plugin's local documentation to keep the MkDocs site up to date.
|
||||
---
|
||||
|
||||
# Doc Mirror Sync
|
||||
|
||||
## Overview
|
||||
Automates the mirroring of `plugins/{type}/{name}/README.md` to `docs/plugins/{type}/{name}.md`.
|
||||
|
||||
## Workflow
|
||||
1. Identify changed READMEs.
|
||||
2. Copy content to corresponding mirror paths.
|
||||
3. Update version badges in `docs/plugins/{type}/index.md`.
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import shutil
|
||||
import re
|
||||
|
||||
def sync_mirrors():
|
||||
plugins_root = "plugins"
|
||||
docs_root = "docs/plugins"
|
||||
|
||||
types = ["actions", "filters", "pipes", "pipelines", "tools"]
|
||||
|
||||
for t in types:
|
||||
src_type_dir = os.path.join(plugins_root, t)
|
||||
dest_type_dir = os.path.join(docs_root, t)
|
||||
|
||||
if not os.path.exists(src_type_dir): continue
|
||||
os.makedirs(dest_type_dir, exist_ok=True)
|
||||
|
||||
for name in os.listdir(src_type_dir):
|
||||
plugin_dir = os.path.join(src_type_dir, name)
|
||||
if not os.path.isdir(plugin_dir): continue
|
||||
|
||||
# Sync README.md -> docs/plugins/{type}/{name}.md
|
||||
src_readme = os.path.join(plugin_dir, "README.md")
|
||||
if os.path.exists(src_readme):
|
||||
dest_readme = os.path.join(dest_type_dir, f"{name}.md")
|
||||
shutil.copy(src_readme, dest_readme)
|
||||
print(f"✅ Mirrored: {t}/{name} (EN)")
|
||||
|
||||
# Sync README_CN.md -> docs/plugins/{type}/{name}.zh.md
|
||||
src_readme_cn = os.path.join(plugin_dir, "README_CN.md")
|
||||
if os.path.exists(src_readme_cn):
|
||||
dest_readme_zh = os.path.join(dest_type_dir, f"{name}.zh.md")
|
||||
shutil.copy(src_readme_cn, dest_readme_zh)
|
||||
print(f"✅ Mirrored: {t}/{name} (ZH)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
sync_mirrors()
|
||||
@@ -1,51 +0,0 @@
|
||||
---
|
||||
name: gh-issue-replier
|
||||
description: Professional English replier for GitHub issues. Use when a task is completed, a bug is fixed, or more info is needed from the user. Automates replying using the 'gh' CLI tool.
|
||||
---
|
||||
|
||||
# Gh Issue Replier
|
||||
|
||||
## Overview
|
||||
|
||||
The `gh-issue-replier` skill enables Gemini CLI to interact with GitHub issues professionally. It enforces English for all communications and leverages the `gh` CLI to post comments.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Identify the Issue**: Find the issue number (e.g., #49).
|
||||
2. **Check Star Status**: Run the bundled script to check if the author has starred the repo.
|
||||
* Command: `bash scripts/check_star.sh <issue-number>`
|
||||
* Interpretation:
|
||||
* Exit code **0**: User has starred. Use "Already Starred" templates.
|
||||
* Exit code **1**: User has NOT starred. Include "Star Request" in the reply.
|
||||
3. **Select a Template**: Load [templates.md](references/templates.md) to choose a suitable English response pattern.
|
||||
4. **Draft the Reply**: Compose a concise message based on the star status.
|
||||
5. **Post the Comment**: Use the `gh` tool to submit the reply.
|
||||
|
||||
## Tool Integration
|
||||
|
||||
### Check Star Status
|
||||
```bash
|
||||
bash scripts/check_star.sh <issue-number>
|
||||
```
|
||||
|
||||
### Post Comment
|
||||
```bash
|
||||
gh issue comment <issue-number> --body "<message-body>"
|
||||
```
|
||||
|
||||
Example (if user has NOT starred):
|
||||
```bash
|
||||
gh issue comment 49 --body "This has been fixed in v1.2.7. If you find this helpful, a star on the repo would be much appreciated! ⭐"
|
||||
```
|
||||
|
||||
Example (if user HAS starred):
|
||||
```bash
|
||||
gh issue comment 49 --body "This has been fixed in v1.2.7. Thanks for your support!"
|
||||
```
|
||||
|
||||
## Guidelines
|
||||
|
||||
- **Language**: ALWAYS use English for the comment body, even if the system prompt or user conversation is in another language.
|
||||
- **Tone**: Professional, helpful, and appreciative.
|
||||
- **Precision**: When announcing a fix, mention the specific version or the logic change (e.g., "Updated regex pattern").
|
||||
- **Closing**: If the issue is resolved and you have permission, you can also use `gh issue close <number>`.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Reference Documentation for Gh Issue Replier
|
||||
|
||||
This is a placeholder for detailed reference documentation.
|
||||
Replace with actual reference content or delete if not needed.
|
||||
|
||||
## Structure Suggestions
|
||||
|
||||
### API Reference Example
|
||||
- Overview
|
||||
- Authentication
|
||||
- Endpoints with examples
|
||||
- Error codes
|
||||
|
||||
### Workflow Guide Example
|
||||
- Prerequisites
|
||||
- Step-by-step instructions
|
||||
- Best practices
|
||||
@@ -1,45 +0,0 @@
|
||||
# Issue Reply Templates
|
||||
|
||||
Use these templates to craft professional English replies. Adjust placeholders like `@username`, `v1.2.x`, and `[commit hash]` as needed.
|
||||
|
||||
## 1. Acknowledging a New Issue
|
||||
Use when you first see an issue and want to let the user know you are working on it.
|
||||
|
||||
- "Thank you for reporting this! I'm looking into it right now."
|
||||
- "Thanks for bringing this to my attention. I'll try to reproduce this behavior and get back to you shortly."
|
||||
|
||||
## 2. Requesting More Information
|
||||
Use when you need logs or specific details to fix the bug.
|
||||
|
||||
- "Could you please provide the **'Original'** vs **'Normalized'** content from your browser console logs (F12)? It would help a lot in debugging."
|
||||
- "It would be very helpful if you could share the specific Markdown text that triggered this issue."
|
||||
|
||||
## 3. Announcing a Fix
|
||||
Use when you have pushed the fix to the repository.
|
||||
|
||||
- "This has been fixed in version **v1.2.x**. You can update the plugin to resolve it."
|
||||
- "I've just pushed a fix for this in [commit hash]. Please let me know if it works for you after updating."
|
||||
- "The issue was caused by a greedy regex pattern. I've updated it to use a tempered greedy token to prevent incorrect merging."
|
||||
|
||||
## 4. Guiding to Official Market
|
||||
Always provide the official market link to ensure the user gets the latest verified version.
|
||||
|
||||
- "The fix is now live! You can download the latest version from the official OpenWebUI Community page here: [Plugin Market Link]. Simply update the function in your OpenWebUI instance to apply the changes."
|
||||
- "I recommend getting the updated version from the official store: [Link]. It includes the fix for the spacing issue we discussed."
|
||||
|
||||
## 5. Closing the Issue
|
||||
Use when the issue is confirmed resolved.
|
||||
|
||||
- "Glad to hear it's working now! Closing this for now. Feel free to reopen it if the problem persists."
|
||||
- "Since this is resolved, I'm closing this issue. Thanks again for your feedback!"
|
||||
|
||||
## 5. Pro-tip: Star Request
|
||||
Gently handle star requests based on the user's current status.
|
||||
|
||||
### If User has NOT starred:
|
||||
- "If you find this plugin helpful, a star on the repo would be much appreciated! ⭐"
|
||||
- "We'd love your support! If this fixed your issue, please consider starring the repository. ⭐"
|
||||
|
||||
### If User HAS already starred:
|
||||
- "Thanks again for starring the project and for your continuous support!"
|
||||
- "I appreciate your support and for being a stargazer of this project!"
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Robust Star Checker v2
|
||||
# Usage: ./check_star.sh <issue_number>
|
||||
|
||||
ISSUE_NUM=$1
|
||||
if [ -z "$ISSUE_NUM" ]; then exit 2; fi
|
||||
|
||||
# 1. Get Repo and Author info
|
||||
REPO_FULL=$(gh repo view --json owner,name -q ".owner.login + \"/\" + .name")
|
||||
USER_LOGIN=$(gh issue view "$ISSUE_NUM" --json author -q ".author.login")
|
||||
|
||||
# 2. Use GraphQL for high precision (Detects stars even when REST 404s)
|
||||
IS_STARRED=$(gh api graphql -f query='
|
||||
query($owner:String!, $repo:String!, $user:String!) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
stargazers(query:$user, first:1) {
|
||||
nodes {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -f owner="${REPO_FULL%/*}" -f repo="${REPO_FULL#*/}" -f user="$USER_LOGIN" -q ".data.repository.stargazers.nodes[0].login")
|
||||
|
||||
if [ "$IS_STARRED" == "$USER_LOGIN" ]; then
|
||||
echo "Confirmed: @$USER_LOGIN HAS starred $REPO_FULL. ⭐"
|
||||
exit 0
|
||||
else
|
||||
echo "Confirmed: @$USER_LOGIN has NOT starred $REPO_FULL."
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
name: gh-issue-scheduler
|
||||
description: Finds all open GitHub issues that haven't been replied to by the owner, summarizes them, and generates a solution plan. Use when the user wants to audit pending tasks or plan maintenance work.
|
||||
---
|
||||
|
||||
# Gh Issue Scheduler
|
||||
|
||||
## Overview
|
||||
|
||||
The `gh-issue-scheduler` skill helps maintainers track community feedback by identifying unaddressed issues and drafting actionable technical plans to resolve them.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Identify Unanswered Issues**: Run the bundled script to fetch issues without owner replies.
|
||||
* Command: `bash scripts/find_unanswered.sh`
|
||||
2. **Analyze and Summarize**: For each identified issue, summarize the core problem and the user's intent.
|
||||
3. **Generate Solution Plans**: Draft a technical "Action Plan" for each issue, including:
|
||||
* **Root Cause Analysis** (if possible)
|
||||
* **Proposed Fix/Implementation**
|
||||
* **Verification Strategy**
|
||||
4. **Present to User**: Display a structured report of all pending issues and their respective plans.
|
||||
|
||||
## Tool Integration
|
||||
|
||||
### Find Unanswered Issues
|
||||
```bash
|
||||
bash scripts/find_unanswered.sh
|
||||
```
|
||||
|
||||
## Report Format
|
||||
|
||||
When presenting the summary, use the following Markdown structure:
|
||||
|
||||
### 📋 Unanswered Issues Audit
|
||||
|
||||
#### Issue #[Number]: [Title]
|
||||
- **Author**: @username
|
||||
- **Summary**: Concise description of the problem.
|
||||
- **Action Plan**:
|
||||
1. Step 1 (e.g., Investigate file X)
|
||||
2. Step 2 (e.g., Apply fix Y)
|
||||
3. Verification (e.g., Run test Z)
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Fetch all open issues and filter for those without responses from the owner/collaborators.
|
||||
# Uses 'gh' CLI.
|
||||
|
||||
REPO_FULL=$(gh repo view --json owner,name -q ".owner.login + "/" + .name")
|
||||
OWNER=${REPO_FULL%/*}
|
||||
|
||||
# 1. Get all open issues
|
||||
OPEN_ISSUES=$(gh issue list --state open --json number,title,author,createdAt --limit 100)
|
||||
|
||||
echo "Analysis for repository: $REPO_FULL"
|
||||
echo "------------------------------------"
|
||||
|
||||
# Process each issue
|
||||
echo "$OPEN_ISSUES" | jq -c '.[]' | while read -r issue; do
|
||||
NUMBER=$(echo "$issue" | jq -r '.number')
|
||||
TITLE=$(echo "$issue" | jq -r '.title')
|
||||
AUTHOR=$(echo "$issue" | jq -r '.author.login')
|
||||
|
||||
# Check comments for owner responses
|
||||
# We look for comments where the author is the repo owner
|
||||
COMMENTS=$(gh issue view "$NUMBER" --json comments -q ".comments[].author.login" 2>/dev/null)
|
||||
|
||||
HAS_OWNER_REPLY=false
|
||||
for COMMENT_AUTHOR in $COMMENTS; do
|
||||
if [ "$COMMENT_AUTHOR" == "$OWNER" ]; then
|
||||
HAS_OWNER_REPLY=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$HAS_OWNER_REPLY" == "false" ]; then
|
||||
echo "ISSUE_START"
|
||||
echo "ID: $NUMBER"
|
||||
echo "Title: $TITLE"
|
||||
echo "Author: $AUTHOR"
|
||||
echo "Description:"
|
||||
gh issue view "$NUMBER" --json body -q ".body"
|
||||
echo "ISSUE_END"
|
||||
fi
|
||||
done
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: i18n-validator
|
||||
description: Validates multi-language consistency in the TRANSLATIONS dictionary of a plugin. Use to check if any language keys are missing or if translations need updating.
|
||||
---
|
||||
|
||||
# I18n Validator
|
||||
|
||||
## Overview
|
||||
Ensures all 12 supported languages (en-US, zh-CN, etc.) have aligned translation keys.
|
||||
|
||||
## Features
|
||||
- Detects missing keys in non-English dictionaries.
|
||||
- Suggests translations using the core AI engine.
|
||||
- Validates the `fallback_map` for variant redirects.
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import ast
|
||||
import os
|
||||
|
||||
def check_i18n(file_path):
|
||||
if not os.path.exists(file_path):
|
||||
print(f"Error: File not found {file_path}")
|
||||
return
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
tree = ast.parse(f.read())
|
||||
|
||||
translations = {}
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and target.id == "TRANSLATIONS":
|
||||
translations = ast.literal_eval(node.value)
|
||||
break
|
||||
|
||||
if not translations:
|
||||
print("⚠️ No TRANSLATIONS dictionary found.")
|
||||
return
|
||||
|
||||
# Base keys from English
|
||||
base_lang = "en-US"
|
||||
if base_lang not in translations:
|
||||
print(f"❌ Error: {base_lang} missing in TRANSLATIONS.")
|
||||
return
|
||||
|
||||
base_keys = set(translations[base_lang].keys())
|
||||
print(f"🔍 Analyzing {file_path}...")
|
||||
print(f"Standard keys ({len(base_keys)}): {', '.join(sorted(base_keys))}
|
||||
")
|
||||
|
||||
for lang, keys in translations.items():
|
||||
if lang == base_lang: continue
|
||||
lang_keys = set(keys.keys())
|
||||
missing = base_keys - lang_keys
|
||||
extra = lang_keys - base_keys
|
||||
|
||||
if missing:
|
||||
print(f"❌ {lang}: Missing {len(missing)} keys: {', '.join(missing)}")
|
||||
if extra:
|
||||
print(f"⚠️ {lang}: Has {len(extra)} extra keys: {', '.join(extra)}")
|
||||
if not missing and not extra:
|
||||
print(f"✅ {lang}: Aligned.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: validate_i18n.py <path_to_plugin.py>")
|
||||
sys.exit(1)
|
||||
check_i18n(sys.argv[1])
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
name: plugin-scaffolder
|
||||
description: Generates a standardized single-file i18n Python plugin template based on project standards. Use when starting a new plugin development to skip boilerplate writing.
|
||||
---
|
||||
|
||||
# Plugin Scaffolder
|
||||
|
||||
## Overview
|
||||
Generates compliant OpenWebUI plugin templates with built-in i18n, common utility methods, and required docstring fields.
|
||||
|
||||
## Usage
|
||||
1. Provide the **Plugin Name** and **Type** (action/filter/pipe).
|
||||
2. The skill will generate the `.py` file and the bilingual `README` files.
|
||||
|
||||
## Template Standard
|
||||
- `Valves(BaseModel)` with `UPPER_SNAKE_CASE`
|
||||
- `_get_user_context` with JS fallback and timeout
|
||||
- `_emit_status` and `_emit_debug_log` methods
|
||||
- Standardized docstring metadata
|
||||
@@ -1,34 +0,0 @@
|
||||
# {{TITLE}}
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **Version:** 0.1.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
|
||||
{{DESCRIPTION}}
|
||||
|
||||
## 🔥 What's New in v0.1.0
|
||||
|
||||
* Initial release of {{TITLE}}.
|
||||
|
||||
## 🌐 Multilingual Support
|
||||
|
||||
Supports automatic interface and status switching for the following languages:
|
||||
`English`, `简体中文`, `繁體中文 (香港)`, `繁體中文 (台灣)`, `한국어`, `日本語`, `Français`, `Deutsch`, `Español`, `Italiano`, `Tiếng Việt`, `Bahasa Indonesia`.
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
* Feature 1
|
||||
* Feature 2
|
||||
|
||||
## How to Use 🛠️
|
||||
|
||||
1. Install the plugin in Open WebUI.
|
||||
2. Configure settings in Valves.
|
||||
|
||||
## Configuration (Valves) ⚙️
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `priority` | `50` | Execution priority. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) is a big motivation for me. Thank you for the support.
|
||||
@@ -1,80 +0,0 @@
|
||||
"""
|
||||
title: {{TITLE}}
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||
funding_url: https://github.com/open-webui
|
||||
version: 0.1.0
|
||||
description: {{DESCRIPTION}}
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import json
|
||||
from typing import Optional, Dict, Any, List, Callable, Awaitable
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi import Request
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TRANSLATIONS = {
|
||||
"en-US": {"status_starting": "Starting {{TITLE}}..."},
|
||||
"zh-CN": {"status_starting": "正在启动 {{TITLE}}..."},
|
||||
"zh-HK": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"zh-TW": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"ko-KR": {"status_starting": "{{TITLE}} 시작 중..."},
|
||||
"ja-JP": {"status_starting": "{{TITLE}} を起動中..."},
|
||||
"fr-FR": {"status_starting": "Démarrage de {{TITLE}}..."},
|
||||
"de-DE": {"status_starting": "{{TITLE}} wird gestartet..."},
|
||||
"es-ES": {"status_starting": "Iniciando {{TITLE}}..."},
|
||||
"it-IT": {"status_starting": "Avvio di {{TITLE}}..."},
|
||||
"vi-VN": {"status_starting": "Đang khởi động {{TITLE}}..."},
|
||||
"id-ID": {"status_starting": "Memulai {{TITLE}}..."},
|
||||
}
|
||||
|
||||
class {{CLASS_NAME}}:
|
||||
class Valves(BaseModel):
|
||||
priority: int = Field(default=50, description="Priority level (lower = earlier).")
|
||||
show_status: bool = Field(default=True, description="Show status updates in UI.")
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.fallback_map = {
|
||||
"zh": "zh-CN", "en": "en-US", "ko": "ko-KR", "ja": "ja-JP",
|
||||
"fr": "fr-FR", "de": "de-DE", "es": "es-ES", "it": "it-IT",
|
||||
"vi": "vi-VN", "id": "id-ID"
|
||||
}
|
||||
|
||||
def _get_translation(self, lang: str, key: str, **kwargs) -> str:
|
||||
target_lang = lang
|
||||
if target_lang not in TRANSLATIONS:
|
||||
base = target_lang.split("-")[0]
|
||||
target_lang = self.fallback_map.get(base, "en-US")
|
||||
|
||||
lang_dict = TRANSLATIONS.get(target_lang, TRANSLATIONS["en-US"])
|
||||
text = lang_dict.get(key, TRANSLATIONS["en-US"].get(key, key))
|
||||
return text.format(**kwargs) if kwargs else text
|
||||
|
||||
async def _get_user_context(self, __user__: Optional[dict], __event_call__: Optional[Callable] = None, __request__: Optional[Request] = None) -> dict:
|
||||
user_data = __user__ if isinstance(__user__, dict) else {}
|
||||
user_language = user_data.get("language", "en-US")
|
||||
if __event_call__:
|
||||
try:
|
||||
js = "try { return (document.documentElement.lang || localStorage.getItem('locale') || navigator.language || 'en-US'); } catch (e) { return 'en-US'; }"
|
||||
frontend_lang = await asyncio.wait_for(__event_call__({"type": "execute", "data": {"code": js}}), timeout=2.0)
|
||||
if frontend_lang: user_language = frontend_lang
|
||||
except: pass
|
||||
return {"user_language": user_language}
|
||||
|
||||
async def {{METHOD_NAME}}(self, body: dict, __user__: Optional[dict] = None, __event_emitter__=None, __event_call__=None, __request__: Optional[Request] = None) -> dict:
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
user_ctx = await self._get_user_context(__user__, __event_call__, __request__)
|
||||
msg = self._get_translation(user_ctx["user_language"], "status_starting")
|
||||
await __event_emitter__({"type": "status", "data": {"description": msg, "done": False}})
|
||||
|
||||
# Implement core logic here
|
||||
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
await __event_emitter__({"type": "status", "data": {"description": "Done", "done": True}})
|
||||
return body
|
||||
@@ -1,80 +0,0 @@
|
||||
"""
|
||||
title: {{TITLE}}
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||
funding_url: https://github.com/open-webui
|
||||
version: 0.1.0
|
||||
description: {{DESCRIPTION}}
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import json
|
||||
from typing import Optional, Dict, Any, List, Callable, Awaitable
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi import Request
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TRANSLATIONS = {
|
||||
"en-US": {"status_starting": "Starting {{TITLE}}..."},
|
||||
"zh-CN": {"status_starting": "正在启动 {{TITLE}}..."},
|
||||
"zh-HK": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"zh-TW": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"ko-KR": {"status_starting": "{{TITLE}} 시작 중..."},
|
||||
"ja-JP": {"status_starting": "{{TITLE}} を起動中..."},
|
||||
"fr-FR": {"status_starting": "Démarrage de {{TITLE}}..."},
|
||||
"de-DE": {"status_starting": "{{TITLE}} wird gestartet..."},
|
||||
"es-ES": {"status_starting": "Iniciando {{TITLE}}..."},
|
||||
"it-IT": {"status_starting": "Avvio di {{TITLE}}..."},
|
||||
"vi-VN": {"status_starting": "Đang khởi động {{TITLE}}..."},
|
||||
"id-ID": {"status_starting": "Memulai {{TITLE}}..."},
|
||||
}
|
||||
|
||||
class {{CLASS_NAME}}:
|
||||
class Valves(BaseModel):
|
||||
priority: int = Field(default=50, description="Priority level (lower = earlier).")
|
||||
show_status: bool = Field(default=True, description="Show status updates in UI.")
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.fallback_map = {
|
||||
"zh": "zh-CN", "en": "en-US", "ko": "ko-KR", "ja": "ja-JP",
|
||||
"fr": "fr-FR", "de": "de-DE", "es": "es-ES", "it": "it-IT",
|
||||
"vi": "vi-VN", "id": "id-ID"
|
||||
}
|
||||
|
||||
def _get_translation(self, lang: str, key: str, **kwargs) -> str:
|
||||
target_lang = lang
|
||||
if target_lang not in TRANSLATIONS:
|
||||
base = target_lang.split("-")[0]
|
||||
target_lang = self.fallback_map.get(base, "en-US")
|
||||
|
||||
lang_dict = TRANSLATIONS.get(target_lang, TRANSLATIONS["en-US"])
|
||||
text = lang_dict.get(key, TRANSLATIONS["en-US"].get(key, key))
|
||||
return text.format(**kwargs) if kwargs else text
|
||||
|
||||
async def _get_user_context(self, __user__: Optional[dict], __event_call__: Optional[Callable] = None, __request__: Optional[Request] = None) -> dict:
|
||||
user_data = __user__ if isinstance(__user__, dict) else {}
|
||||
user_language = user_data.get("language", "en-US")
|
||||
if __event_call__:
|
||||
try:
|
||||
js = "try { return (document.documentElement.lang || localStorage.getItem('locale') || navigator.language || 'en-US'); } catch (e) { return 'en-US'; }"
|
||||
frontend_lang = await asyncio.wait_for(__event_call__({"type": "execute", "data": {"code": js}}), timeout=2.0)
|
||||
if frontend_lang: user_language = frontend_lang
|
||||
except: pass
|
||||
return {"user_language": user_language}
|
||||
|
||||
async def {{METHOD_NAME}}(self, body: dict, __user__: Optional[dict] = None, __event_emitter__=None, __event_call__=None, __request__: Optional[Request] = None) -> dict:
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
user_ctx = await self._get_user_context(__user__, __event_call__, __request__)
|
||||
msg = self._get_translation(user_ctx["user_language"], "status_starting")
|
||||
await __event_emitter__({"type": "status", "data": {"description": msg, "done": False}})
|
||||
|
||||
# Implement core logic here
|
||||
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
await __event_emitter__({"type": "status", "data": {"description": "Done", "done": True}})
|
||||
return body
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def scaffold(p_type, p_name, title, desc):
|
||||
target_dir = f"plugins/{p_type}/{p_name}"
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
|
||||
class_name = (
|
||||
"Action"
|
||||
if p_type == "actions"
|
||||
else (
|
||||
"Filter"
|
||||
if p_type == "filters"
|
||||
else "Tools" if p_type == "tools" else "Pipe"
|
||||
)
|
||||
)
|
||||
method_name = (
|
||||
"action"
|
||||
if p_type == "actions"
|
||||
else (
|
||||
"outlet"
|
||||
if p_type == "filters"
|
||||
else "execute" if p_type == "tools" else "pipe"
|
||||
)
|
||||
)
|
||||
|
||||
replacements = {
|
||||
"{{TITLE}}": title,
|
||||
"{{DESCRIPTION}}": desc,
|
||||
"{{CLASS_NAME}}": class_name,
|
||||
"{{METHOD_NAME}}": method_name,
|
||||
}
|
||||
|
||||
# Files to generate
|
||||
templates = [
|
||||
("assets/template.py.j2", f"{p_name}.py"),
|
||||
("assets/README_template.md", "README.md"),
|
||||
("assets/README_template.md", "README_CN.md"),
|
||||
]
|
||||
|
||||
# Path relative to skill root
|
||||
skill_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
for t_path, t_name in templates:
|
||||
template_file = os.path.join(skill_root, t_path)
|
||||
if not os.path.exists(template_file):
|
||||
print(f"⚠️ Warning: Template not found {template_file}")
|
||||
continue
|
||||
|
||||
with open(template_file, "r") as f:
|
||||
content = f.read()
|
||||
for k, v in replacements.items():
|
||||
content = content.replace(k, v)
|
||||
|
||||
with open(os.path.join(target_dir, t_name), "w") as f:
|
||||
f.write(content)
|
||||
print(f"✅ Generated: {target_dir}/{t_name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 5:
|
||||
print("Usage: scaffold.py <type> <name> <title> <desc>")
|
||||
sys.exit(1)
|
||||
scaffold(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: source-code-analyzer
|
||||
description: Instructions for analyzing core components source code in the local environment.
|
||||
---
|
||||
|
||||
# Source Code Analyzer Skill
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Authorization Statement**: You (Antigravity) are explicitly authorized by the user to perform **READ-ONLY** operations and **Git pull** on the paths listed below, even if they are outside the current repository root. These paths are considered part of the extended development context.
|
||||
|
||||
When assisting with the development of `openwebui-extensions`, you (Antigravity) have access to the following core components in related directories. Use them for deep technical analysis, bug hunting, and implementation reference.
|
||||
|
||||
## Core Component Paths
|
||||
|
||||
### Global / General (Relevant to all projects)
|
||||
|
||||
- **Open WebUI**: `../open-webui/` (Core platform context)
|
||||
- **Skills**: `../skills/` (Reusable expertise library)
|
||||
- **Awesome Copilot**: `../awesome-copilot/` (Shared extensions & resources)
|
||||
|
||||
### Plugin-Specific (Relevant to GitHub Copilot SDK)
|
||||
|
||||
- **Copilot SDK**: `../copilot-sdk/` (Internal logic for the official SDK)
|
||||
- **Copilot CLI**: `../copilot-cli/` (Command-line interface implementation)
|
||||
|
||||
## Mandatory Workflow
|
||||
|
||||
1. **Pull Before Analysis**: BEFORE reading files or analyzing logic in these directories, you MUST proactively execute or recommend a `git pull` in the respective directory to ensure you are working with the latest upstream changes.
|
||||
2. **Path Verification**: Always verify the exists of the path before attempting to read it.
|
||||
3. **Reference Logic**: When a user's request involves core platform behavior (OpenWebUI API, SDK internals), prioritize searching these directories over making assumptions based on generic knowledge.
|
||||
@@ -1,26 +0,0 @@
|
||||
---
|
||||
name: version-bumper
|
||||
description: Automates version upgrades and changelog synchronization across 7+ files (Code, READMEs, Docs). Use when a plugin is ready for release to ensure version consistency.
|
||||
---
|
||||
|
||||
# Version Bumper
|
||||
|
||||
## Overview
|
||||
This skill ensures that every version upgrade is synchronized across the entire repository, following the strict "Documentation Sync" rule in GEMINI.md.
|
||||
|
||||
## Workflow
|
||||
1. **Prepare Info**: Gather the new version number and brief changelogs in both English and Chinese.
|
||||
2. **Auto-Patch**: The skill will help you identify and update:
|
||||
- `plugins/.../name.py` (docstring version)
|
||||
- `plugins/.../README.md` (metadata & What's New)
|
||||
- `plugins/.../README_CN.md` (metadata & 最新更新)
|
||||
- `docs/plugins/...md` (mirrors)
|
||||
- `docs/plugins/index.md` (version badge)
|
||||
- `README.md` (updated date badge)
|
||||
3. **Verify**: Check the diffs to ensure no formatting was broken.
|
||||
|
||||
## Tool Integration
|
||||
Execute the bump script (draft):
|
||||
```bash
|
||||
python3 scripts/bump.py <version> "<message_en>" "<message_zh>"
|
||||
```
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
def patch_file(file_path, old_pattern, new_content, is_regex=False):
|
||||
if not os.path.exists(file_path):
|
||||
print(f"Warning: File not found: {file_path}")
|
||||
return False
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
if is_regex:
|
||||
new_content_result = re.sub(old_pattern, new_content, content, flags=re.MULTILINE)
|
||||
else:
|
||||
new_content_result = content.replace(old_pattern, new_content)
|
||||
|
||||
if new_content_result != content:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content_result)
|
||||
print(f"✅ Patched: {file_path}")
|
||||
return True
|
||||
else:
|
||||
print(f"ℹ️ No change needed: {file_path}")
|
||||
return False
|
||||
|
||||
def bump_version(plugin_type, plugin_name, new_version, msg_en, msg_zh):
|
||||
print(f"🚀 Bumping {plugin_name} ({plugin_type}) to {new_version}...")
|
||||
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
today_badge = today.replace("-", "--")
|
||||
|
||||
# 1. Patch Plugin Python File
|
||||
py_file = f"plugins/{plugin_type}/{plugin_name}/{plugin_name}.py"
|
||||
patch_file(py_file, r"version: \d+\.\d+\.\d+", f"version: {new_version}", is_regex=True)
|
||||
|
||||
# 2. Patch Plugin READMEs
|
||||
readme_en = f"plugins/{plugin_type}/{plugin_name}/README.md"
|
||||
readme_zh = f"plugins/{plugin_type}/{plugin_name}/README_CN.md"
|
||||
|
||||
# Update version in metadata
|
||||
patch_file(readme_en, r"\*\*Version:\*\* \d+\.\d+\.\d+", f"**Version:** {new_version}", is_regex=True)
|
||||
patch_file(readme_zh, r"\*\*版本:\*\* \d+\.\d+\.\d+", f"**版本:** {new_version}", is_regex=True)
|
||||
|
||||
# Update What's New (Assuming standard headers)
|
||||
patch_file(readme_en, r"## 🔥 What's New in v.*?\n", f"## 🔥 What's New in v{new_version}\n\n* {msg_en}\n", is_regex=True)
|
||||
patch_file(readme_zh, r"## 🔥 最新更新 v.*?\n", f"## 🔥 最新更新 v{new_version}\n\n* {msg_zh}\n", is_regex=True)
|
||||
|
||||
# 3. Patch Docs Mirrors
|
||||
doc_en = f"docs/plugins/{plugin_type}/{plugin_name}.md"
|
||||
doc_zh = f"docs/plugins/{plugin_type}/{plugin_name}.zh.md"
|
||||
patch_file(doc_en, r"\*\*Version:\*\* \d+\.\d+\.\d+", f"**Version:** {new_version}", is_regex=True)
|
||||
patch_file(doc_zh, r"\*\*版本:\*\* \d+\.\d+\.\d+", f"**版本:** {new_version}", is_regex=True)
|
||||
|
||||
# 4. Patch Root READMEs (Updated Date Badge)
|
||||
patch_file("README.md", r"badge/202\d--\d\d--\d\d-gray", f"badge/{today_badge}-gray", is_regex=True)
|
||||
patch_file("README_CN.md", r"badge/202\d--\d\d--\d\d-gray", f"badge/{today_badge}-gray", is_regex=True)
|
||||
|
||||
print("\n✨ All synchronization tasks completed.")
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 6:
|
||||
print("Usage: bump.py <type> <name> <version> <msg_en> <msg_zh>")
|
||||
print("Example: bump.py filters markdown_normalizer 1.2.8 'Fix bug' '修复错误'")
|
||||
sys.exit(1)
|
||||
|
||||
bump_version(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5])
|
||||
62
.github/agents/plugin-implementer.agent.md
vendored
62
.github/agents/plugin-implementer.agent.md
vendored
@@ -1,62 +0,0 @@
|
||||
---
|
||||
name: Plugin Implementer
|
||||
description: Implement OpenWebUI plugin and docs updates with strict project standards
|
||||
argument-hint: Provide approved plan or feature request to implement
|
||||
tools: ['execute/getTerminalOutput', 'execute/runInTerminal', 'read/readFile', 'read/terminalSelection', 'read/terminalLastCommand', 'edit/createFile', 'edit/editFiles', 'search', 'web', 'web/fetch', 'web/githubRepo', 'agent']
|
||||
infer: true
|
||||
handoffs:
|
||||
- label: Run Review
|
||||
agent: Plugin Reviewer
|
||||
prompt: Review the implementation for i18n, safety, and consistency issues.
|
||||
send: false
|
||||
---
|
||||
You are the **implementation specialist** for the `openwebui-extensions` repository.
|
||||
|
||||
## Execution Rules
|
||||
1. **Minimal diffs**: Change only what the approved plan specifies.
|
||||
2. **Single-file i18n**: Every plugin is one `.py` file with built-in `TRANSLATIONS` dict. Never create `_cn.py` split files.
|
||||
3. **Context helpers**: Always use `_get_user_context(__user__)` and `_get_chat_context(body, __metadata__)` — never access dict keys directly.
|
||||
4. **Emitter guards**: Every `await emitter(...)` must be guarded by `if emitter:`.
|
||||
5. **Logging**: Use `logging.getLogger(__name__)` — no bare `print()` in production code.
|
||||
6. **Async safety**: Wrap all `__event_call__` with `asyncio.wait_for(..., timeout=2.0)` + inner JS `try { ... } catch(e) { return fallback; }`.
|
||||
|
||||
## Required Plugin Pattern
|
||||
```python
|
||||
# Docstring: title, author, author_url, funding_url, version, description
|
||||
# icon_url is REQUIRED for Action plugins (Lucide SVG, base64)
|
||||
|
||||
class Action: # or Filter / Pipe
|
||||
class Valves(BaseModel):
|
||||
SHOW_STATUS: bool = Field(default=True, description="...")
|
||||
# All fields UPPER_SNAKE_CASE
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
|
||||
def _get_user_context(self, __user__): ... # always implement
|
||||
def _get_chat_context(self, body, __metadata__=None): ... # always implement
|
||||
async def _emit_status(self, emitter, description, done=False): ...
|
||||
async def _emit_notification(self, emitter, content, ntype="info"): ...
|
||||
```
|
||||
|
||||
## Known Split-File Plugins (Legacy — Do NOT Add More)
|
||||
These still have `_cn.py` files. When touching any of them, migrate CN content into `TRANSLATIONS` dict:
|
||||
- `plugins/actions/deep-dive/deep_dive_cn.py`
|
||||
- `plugins/actions/export_to_docx/export_to_word_cn.py`
|
||||
- `plugins/actions/export_to_excel/export_to_excel_cn.py`
|
||||
- `plugins/actions/flash-card/flash_card_cn.py`
|
||||
- `plugins/actions/infographic/infographic_cn.py`
|
||||
- `plugins/filters/folder-memory/folder_memory_cn.py`
|
||||
|
||||
## Version Bump Rule
|
||||
Only bump version when user explicitly says "发布" / "release" / "bump version".
|
||||
When bumping, update ALL 7+ files (code docstring + 2× README + 2× doc detail + 2× doc index + 2× root README date badge).
|
||||
|
||||
## Git Policy
|
||||
- Never run `git commit`, `git push`, or create PRs automatically.
|
||||
- After all edits, list what changed and why, then stop.
|
||||
|
||||
## Completion Output
|
||||
- Modified files (full relative paths, one-line descriptions)
|
||||
- Remaining manual checks
|
||||
- Suggested handoff to **Plugin Reviewer**
|
||||
78
.github/agents/plugin-planner.agent.md
vendored
78
.github/agents/plugin-planner.agent.md
vendored
@@ -1,78 +0,0 @@
|
||||
---
|
||||
name: Plugin Planner
|
||||
description: Analyze requirements and produce a safe implementation plan for OpenWebUI plugins
|
||||
argument-hint: Describe the plugin goal, constraints, and target files
|
||||
tools: ['read/readFile', 'search', 'web', 'web/githubRepo', 'read/terminalLastCommand', 'read/terminalSelection', 'agent']
|
||||
infer: true
|
||||
handoffs:
|
||||
- label: Start Implementation
|
||||
agent: Plugin Implementer
|
||||
prompt: Implement the approved plan step by step with minimal diffs.
|
||||
send: false
|
||||
---
|
||||
You are the **planning specialist** for the `openwebui-extensions` repository.
|
||||
|
||||
## Your Responsibilities
|
||||
1. Read existing plugin code and docs **before** proposing any change.
|
||||
2. Produce a **small, reversible** plan (one logical change per file per step).
|
||||
3. Clearly list all impacted files including the docs sync chain.
|
||||
4. Flag risks: breaking changes, release implications, version bumps needed.
|
||||
|
||||
## Hard Rules
|
||||
- Never propose `git commit`, `git push`, or PR creation.
|
||||
- Every plan must end with an acceptance checklist for the user to approve before handing off.
|
||||
- Reference `.github/copilot-instructions.md` as the authoritative spec.
|
||||
|
||||
## Repository Plugin Inventory
|
||||
|
||||
### Actions (`plugins/actions/`)
|
||||
| Dir | Main file | Version | i18n status |
|
||||
|-----|-----------|---------|-------------|
|
||||
| `deep-dive` | `deep_dive.py` | 1.0.0 | ⚠️ has `deep_dive_cn.py` split |
|
||||
| `export_to_docx` | `export_to_word.py` | 0.4.4 | ⚠️ has `export_to_word_cn.py` split |
|
||||
| `export_to_excel` | `export_to_excel.py` | 0.3.7 | ⚠️ has `export_to_excel_cn.py` split |
|
||||
| `flash-card` | `flash_card.py` | 0.2.4 | ⚠️ has `flash_card_cn.py` split |
|
||||
| `infographic` | `infographic.py` | 1.5.0 | ⚠️ has `infographic_cn.py` split |
|
||||
| `smart-mind-map` | `smart_mind_map.py` | 1.0.0 | ✅ single file |
|
||||
| `smart-mermaid` | _(empty stub)_ | — | — |
|
||||
|
||||
### Filters (`plugins/filters/`)
|
||||
| Dir | Main file | Version | i18n status |
|
||||
|-----|-----------|---------|-------------|
|
||||
| `async-context-compression` | `async_context_compression.py` | 1.3.0 | ✅ |
|
||||
| `context_enhancement_filter` | `context_enhancement_filter.py` | 0.3 | ⚠️ non-SemVer version |
|
||||
| `copilot_files_preprocessor` | _(empty stub)_ | — | — |
|
||||
| `folder-memory` | `folder_memory.py` | 0.1.0 | ⚠️ has `folder_memory_cn.py` split |
|
||||
| `github_copilot_sdk_files_filter` | `github_copilot_sdk_files_filter.py` | 0.1.2 | ✅ |
|
||||
| `markdown_normalizer` | `markdown_normalizer.py` | 1.2.4 | ✅ |
|
||||
| `web_gemini_multimodel_filter` | `web_gemini_multimodel.py` | 0.3.2 | ✅ |
|
||||
|
||||
### Pipes / Pipelines / Tools
|
||||
| Path | Main file | Version |
|
||||
|------|-----------|---------|
|
||||
| `pipes/github-copilot-sdk` | `github_copilot_sdk.py` | 0.7.0 |
|
||||
| `pipelines/moe_prompt_refiner` | `moe_prompt_refiner.py` | — |
|
||||
| `tools/workspace-file-manager` | `workspace_file_manager.py` | 0.2.0 |
|
||||
|
||||
## Naming Conventions (Actual Mix)
|
||||
- Action dirs: some use **dashes** (`deep-dive`, `flash-card`, `smart-mind-map`), some **underscores** (`export_to_docx`, `export_to_excel`, `infographic`)
|
||||
- Filter dirs: similarly mixed — prefer underscores for new plugins
|
||||
- Main `.py` filenames always use **underscores**
|
||||
|
||||
## Docs Sync Chain (for every plugin change)
|
||||
For `plugins/{type}/{name}/`, these 7+ files must stay in sync:
|
||||
1. `plugins/{type}/{name}/{name}.py` — version in docstring
|
||||
2. `plugins/{type}/{name}/README.md` — version + What's New
|
||||
3. `plugins/{type}/{name}/README_CN.md` — version + 最新更新
|
||||
4. `docs/plugins/{type}/{name}.md`
|
||||
5. `docs/plugins/{type}/{name}.zh.md`
|
||||
6. `docs/plugins/{type}/index.md` — version badge
|
||||
7. `docs/plugins/{type}/index.zh.md` — version badge
|
||||
8. Root `README.md` / `README_CN.md` — date badge
|
||||
|
||||
## Output Format
|
||||
- **Scope summary**
|
||||
- **Affected files** (full relative paths)
|
||||
- **Step-by-step plan** (numbered, ≤10 steps)
|
||||
- **Risk flags** (version bump? breaking change? split-file migration needed?)
|
||||
- **Acceptance checklist** → user must approve before handoff to Implementer
|
||||
71
.github/agents/plugin-reviewer.agent.md
vendored
71
.github/agents/plugin-reviewer.agent.md
vendored
@@ -1,71 +0,0 @@
|
||||
---
|
||||
name: Plugin Reviewer
|
||||
description: Perform strict repository-aligned code review for OpenWebUI plugin changes
|
||||
argument-hint: Share changed files or branch diff to review
|
||||
tools: ['search', 'read/readFile', 'web', 'web/fetch', 'web/githubRepo', 'execute/getTerminalOutput', 'read/terminalLastCommand', 'read/terminalSelection']
|
||||
infer: true
|
||||
handoffs:
|
||||
- label: Prepare Release Draft
|
||||
agent: Release Prep
|
||||
prompt: Create a bilingual release draft and commit message based on reviewed changes.
|
||||
send: false
|
||||
---
|
||||
You are the **review specialist** for the `openwebui-extensions` repository.
|
||||
|
||||
Full review rules are in .github/instructions/code-review.instructions.md.
|
||||
|
||||
## Review Checklist
|
||||
|
||||
### 🔴 Blocking (must fix before release)
|
||||
|
||||
**1. Single-file i18n Architecture**
|
||||
- [ ] No new `_cn.py` split files created.
|
||||
- [ ] All user-visible strings go through `TRANSLATIONS[lang].get(key, fallback)`.
|
||||
- [ ] `FALLBACK_MAP` covers at least `zh → zh-CN` and `en → en-US`.
|
||||
- [ ] `format(**kwargs)` on translations wrapped in `try/except KeyError`.
|
||||
|
||||
**2. Context Helpers**
|
||||
- [ ] Uses `_get_user_context(__user__)` (not `__user__["name"]` directly).
|
||||
- [ ] Uses `_get_chat_context(body, __metadata__)` (not ad-hoc `body.get("chat_id")`).
|
||||
|
||||
**3. Antigravity Safety**
|
||||
- [ ] Every `__event_call__` wrapped: `asyncio.wait_for(..., timeout=2.0)`.
|
||||
- [ ] JS code passed to `__event_call__` has `try { ... } catch(e) { return fallback; }`.
|
||||
- [ ] File path operations validated against workspace root (no traversal).
|
||||
- [ ] Upload paths have dual-channel fallback (API → DB/local).
|
||||
|
||||
**4. Emitter Guards**
|
||||
- [ ] Every `await emitter(...)` guarded by `if emitter:`.
|
||||
- [ ] `_emit_status(done=False)` on start, `done=True` on success, `_emit_notification("error")` on failure.
|
||||
- [ ] No bare `print()` — use `logging.getLogger(__name__)`.
|
||||
|
||||
**5. Filter Singleton Safety**
|
||||
- [ ] No mutable per-request state stored on `self` in Filter plugins.
|
||||
|
||||
**6. Streaming Compatibility (OpenWebUI 0.8.x)**
|
||||
- [ ] `</think>` tag closed before any normal text or tool cards.
|
||||
- [ ] `<details type="tool_calls" ...>` attributes escape `"` as `"`.
|
||||
- [ ] `<details ...>` block has newline immediately after `>`.
|
||||
|
||||
**7. Version & Docs Sync**
|
||||
- [ ] Version bumped in docstring (if release).
|
||||
- [ ] `README.md` + `README_CN.md` updated (What's New + version).
|
||||
- [ ] `docs/plugins/{type}/{name}.md` and `.zh.md` match README.
|
||||
- [ ] `docs/plugins/{type}/index.md` and `.zh.md` version badges updated.
|
||||
- [ ] Root `README.md` / `README_CN.md` date badge updated.
|
||||
|
||||
### 🟡 Non-blocking (suggestions)
|
||||
- Copilot SDK tools: `params_type=MyParams` in `define_tool()`.
|
||||
- Long tasks (>3s): periodic `_emit_notification("info")` every 5s.
|
||||
- `icon_url` present for Action plugins (Lucide SVG, base64).
|
||||
|
||||
## Known Pre-existing Issues (Don't block on unless the PR introduces new ones)
|
||||
- `_cn.py` splits in: `deep-dive`, `export_to_docx`, `export_to_excel`, `flash-card`, `infographic`, `folder-memory` — legacy, not new.
|
||||
- `context_enhancement_filter` version is `0.3` (non-SemVer) — pre-existing.
|
||||
- `copilot_files_preprocessor` and `smart-mermaid` are empty stubs — pre-existing.
|
||||
|
||||
## Review Output
|
||||
- **Blocking issues** (file:line references)
|
||||
- **Non-blocking suggestions**
|
||||
- **Pass / Fail verdict**
|
||||
- **Next step**: Pass → handoff to Release Prep; Fail → return to Implementer with fix list
|
||||
82
.github/agents/release-prep.agent.md
vendored
82
.github/agents/release-prep.agent.md
vendored
@@ -1,82 +0,0 @@
|
||||
---
|
||||
name: Release Prep
|
||||
description: Prepare release-ready summaries and Conventional Commit drafts without pushing
|
||||
argument-hint: Provide final change list and target version (optional)
|
||||
tools: ['search', 'read/readFile', 'web', 'web/fetch', 'web/githubRepo', 'execute/getTerminalOutput', 'read/terminalLastCommand', 'read/terminalSelection']
|
||||
infer: true
|
||||
---
|
||||
You are the **release preparation specialist** for the `openwebui-extensions` repository.
|
||||
|
||||
Full commit message rules: .github/instructions/commit-message.instructions.md
|
||||
Full release workflow: .agent/workflows/plugin-development.md
|
||||
|
||||
## Responsibilities
|
||||
1. Generate a Conventional Commit message (English only).
|
||||
2. Draft bilingual release notes (EN + 中文).
|
||||
3. Verify ALL file sync locations are updated.
|
||||
4. **Stop before any commit or push** — wait for explicit user confirmation.
|
||||
|
||||
## Commit Message Format
|
||||
```text
|
||||
type(scope): brief imperative description
|
||||
|
||||
- Key change 1
|
||||
- Key change 2 (include migration note if needed)
|
||||
```
|
||||
- `type`: `feat` / `fix` / `docs` / `refactor` / `chore`
|
||||
- `scope`: plugin folder name (e.g., `smart-mind-map`, `github-copilot-sdk`, `folder-memory`)
|
||||
- Title ≤ 72 chars, imperative mood, no trailing period, no capital first letter
|
||||
|
||||
## 9-File Sync Checklist (fill in for each changed plugin)
|
||||
```text
|
||||
Plugin: {type}/{name} → v{new_version}
|
||||
[ ] 1. plugins/{type}/{name}/{name}.py → version in docstring
|
||||
[ ] 2. plugins/{type}/{name}/README.md → version + What's New
|
||||
[ ] 3. plugins/{type}/{name}/README_CN.md → version + 最新更新
|
||||
[ ] 4. docs/plugins/{type}/{name}.md → mirrors README
|
||||
[ ] 5. docs/plugins/{type}/{name}.zh.md → mirrors README_CN
|
||||
[ ] 6. docs/plugins/{type}/index.md → version badge updated
|
||||
[ ] 7. docs/plugins/{type}/index.zh.md → version badge updated
|
||||
[ ] 8. README.md (root) → date badge updated
|
||||
[ ] 9. README_CN.md (root) → date badge updated
|
||||
```
|
||||
|
||||
## Current Plugin Versions (as of last audit — 2026-02-23)
|
||||
| Plugin | Type | Version | Note |
|
||||
|--------|------|---------|------|
|
||||
| deep-dive | action | 1.0.0 | has `_cn.py` split |
|
||||
| export_to_docx | action | 0.4.4 | has `_cn.py` split |
|
||||
| export_to_excel | action | 0.3.7 | has `_cn.py` split |
|
||||
| flash-card | action | 0.2.4 | has `_cn.py` split |
|
||||
| infographic | action | 1.5.0 | has `_cn.py` split |
|
||||
| smart-mind-map | action | 1.0.0 | ✅ |
|
||||
| async-context-compression | filter | 1.3.0 | ✅ |
|
||||
| context_enhancement_filter | filter | 0.3 | ⚠️ non-SemVer |
|
||||
| folder-memory | filter | 0.1.0 | has `_cn.py` split |
|
||||
| github_copilot_sdk_files_filter | filter | 0.1.2 | ✅ |
|
||||
| markdown_normalizer | filter | 1.2.4 | ✅ |
|
||||
| web_gemini_multimodel_filter | filter | 0.3.2 | ✅ |
|
||||
| github-copilot-sdk | pipe | 0.7.0 | ✅ |
|
||||
| workspace-file-manager | tool | 0.2.0 | ✅ |
|
||||
|
||||
## Output Template
|
||||
|
||||
### Commit Message
|
||||
```text
|
||||
{type}({scope}): {description}
|
||||
|
||||
- {change 1}
|
||||
- {change 2}
|
||||
```
|
||||
|
||||
### Change Summary (EN)
|
||||
- {bullet list of user-visible changes}
|
||||
|
||||
### 变更摘要(中文)
|
||||
- {中文要点列表}
|
||||
|
||||
### Verification Status
|
||||
{filled-in 9-file checklist for each changed plugin}
|
||||
|
||||
---
|
||||
⚠️ **Waiting for user confirmation — no git operations will run until explicitly approved.**
|
||||
279
.github/copilot-instructions.md
vendored
279
.github/copilot-instructions.md
vendored
@@ -8,26 +8,27 @@ This document defines the standard conventions and best practices for OpenWebUI
|
||||
|
||||
## 🏗️ 项目结构与命名 (Project Structure & Naming)
|
||||
|
||||
### 1. 语言与代码规范 (Language & Code Requirements)
|
||||
### 1. 双语版本要求 (Bilingual Version Requirements)
|
||||
|
||||
#### 插件代码 (Plugin Code)
|
||||
|
||||
每个插件**必须**采用单文件国际化 (i18n) 设计。严禁为不同语言创建独立的源代码文件(如 `_cn.py`)。
|
||||
每个插件必须提供两个版本:
|
||||
|
||||
1. **单代码文件**: `plugins/{type}/{name}/{name}.py`
|
||||
2. **内置 i18n**: 必须在代码中根据前端传来的用户语言(如 `__user__` 中的 `language` 或通过 `get_user_language` 脚本读取)动态切换界面显示、提示词和状态日志。
|
||||
1. **英文版本**: `plugin_name.py` - 英文界面、提示词和注释
|
||||
2. **中文版本**: `plugin_name_cn.py` - 中文界面、提示词和注释
|
||||
|
||||
示例目录结构:
|
||||
示例:
|
||||
```
|
||||
plugins/actions/export_to_docx/
|
||||
├── export_to_word.py # 单个代码文件,内置多语言支持
|
||||
├── README.md # 英文文档 (English documentation)
|
||||
└── README_CN.md # 中文文档
|
||||
├── export_to_word.py # English version
|
||||
├── export_to_word_cn.py # Chinese version
|
||||
├── README.md # English documentation
|
||||
└── README_CN.md # Chinese documentation
|
||||
```
|
||||
|
||||
#### 文档 (Documentation)
|
||||
|
||||
尽管代码是合一的,但为了市场展示和 SEO,每个插件目录仍**必须**包含双语 README 文件:
|
||||
每个插件目录必须包含双语 README 文件:
|
||||
|
||||
- `README.md` - English documentation
|
||||
- `README_CN.md` - 中文文档
|
||||
@@ -57,10 +58,12 @@ plugins/actions/export_to_docx/
|
||||
plugins/
|
||||
├── actions/ # Action 插件 (用户触发的功能)
|
||||
│ ├── my_action/
|
||||
│ │ ├── my_action.py # 单文件,内置 i18n
|
||||
│ │ ├── my_action.py # English version
|
||||
│ │ ├── 我的动作.py # Chinese version
|
||||
│ │ ├── README.md # English documentation
|
||||
│ │ └── README_CN.md # Chinese documentation
|
||||
│ ├── ACTION_PLUGIN_TEMPLATE.py # 通用 i18n 模板
|
||||
│ ├── ACTION_PLUGIN_TEMPLATE.py # English template
|
||||
│ ├── ACTION_PLUGIN_TEMPLATE_CN.py # Chinese template
|
||||
│ └── README.md
|
||||
├── filters/ # Filter 插件 (输入处理)
|
||||
│ └── ...
|
||||
@@ -205,56 +208,19 @@ class Action:
|
||||
#### 用户上下文 (User Context)
|
||||
|
||||
```python
|
||||
async def _get_user_context(
|
||||
self,
|
||||
__user__: Optional[dict],
|
||||
__event_call__: Optional[callable] = None,
|
||||
__request__: Optional[Request] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Robust extraction of user context with multi-level fallback for language detection.
|
||||
Priority: localStorage (via JS) > HTTP headers > User profile > en-US
|
||||
"""
|
||||
user_data = __user__ if isinstance(__user__, dict) else {}
|
||||
user_id = user_data.get("id", "unknown_user")
|
||||
user_name = user_data.get("name", "User")
|
||||
user_language = user_data.get("language", "en-US")
|
||||
|
||||
# 1. Fallback: HTTP Accept-Language header
|
||||
if __request__ and hasattr(__request__, "headers"):
|
||||
accept_lang = __request__.headers.get("accept-language", "")
|
||||
if accept_lang:
|
||||
user_language = accept_lang.split(",")[0].split(";")[0]
|
||||
|
||||
# 2. Priority: Frontend localStorage via JS (requires timeout protection)
|
||||
if __event_call__:
|
||||
try:
|
||||
js_code = """
|
||||
try {
|
||||
return (
|
||||
document.documentElement.lang ||
|
||||
localStorage.getItem('locale') ||
|
||||
navigator.language ||
|
||||
'en-US'
|
||||
);
|
||||
} catch (e) {
|
||||
return 'en-US';
|
||||
}
|
||||
"""
|
||||
# MUST use wait_for with timeout (e.g., 2.0s) to prevent backend deadlock
|
||||
frontend_lang = await asyncio.wait_for(
|
||||
__event_call__({"type": "execute", "data": {"code": js_code}}),
|
||||
timeout=2.0
|
||||
)
|
||||
if frontend_lang and isinstance(frontend_lang, str):
|
||||
user_language = frontend_lang
|
||||
except Exception:
|
||||
pass # Fallback to existing language
|
||||
def _get_user_context(self, __user__: Optional[Dict[str, Any]]) -> Dict[str, str]:
|
||||
"""安全提取用户上下文信息。"""
|
||||
if isinstance(__user__, (list, tuple)):
|
||||
user_data = __user__[0] if __user__ else {}
|
||||
elif isinstance(__user__, dict):
|
||||
user_data = __user__
|
||||
else:
|
||||
user_data = {}
|
||||
|
||||
return {
|
||||
"user_id": user_id,
|
||||
"user_name": user_name,
|
||||
"user_language": user_language,
|
||||
"user_id": user_data.get("id", "unknown_user"),
|
||||
"user_name": user_data.get("name", "User"),
|
||||
"user_language": user_data.get("language", "en-US"),
|
||||
}
|
||||
```
|
||||
|
||||
@@ -508,129 +474,14 @@ async def get_user_language(self):
|
||||
|
||||
#### 适用场景与引导 (Usage Guidelines)
|
||||
|
||||
- **语言适配**: 动态获取界面语言 (`ru-RU`, `zh-CN`) 自动切换输出语言和 UI 翻译。这对于单文件 i18n 插件至关重要。
|
||||
- **语言适配**: 动态获取界面语言 (`ru-RU`, `zh-CN`) 自动切换输出语言。
|
||||
- **时区处理**: 获取 `Intl.DateTimeFormat().resolvedOptions().timeZone` 处理时间。
|
||||
- **客户端存储**: 读取 `localStorage` 中的用户偏好设置。
|
||||
- **硬件能力**: 获取 `navigator.clipboard` 或 `navigator.geolocation` (需授权)。
|
||||
|
||||
**注意**: 即使插件有 `Valves` 配置,也应优先尝试自动探测,提升用户体验。
|
||||
|
||||
### 8. 国际化 (i18n) 适配规范 (Internationalization Standards)
|
||||
|
||||
开发供全球用户使用的插件时,必须预置多语言支持(如中文、英文等)。
|
||||
|
||||
#### i18n 字典定义
|
||||
|
||||
在文件顶部定义 `TRANSLATIONS` 字典存储多语言字符串:
|
||||
|
||||
```python
|
||||
TRANSLATIONS = {
|
||||
"en-US": {
|
||||
"status_starting": "Smart Mind Map is starting...",
|
||||
},
|
||||
"zh-CN": {
|
||||
"status_starting": "智能思维导图正在启动...",
|
||||
},
|
||||
# ... 其他语言
|
||||
}
|
||||
|
||||
# 语言回退映射 (Fallback Map)
|
||||
FALLBACK_MAP = {
|
||||
"zh": "zh-CN",
|
||||
"zh-TW": "zh-CN",
|
||||
"zh-HK": "zh-CN",
|
||||
"en": "en-US",
|
||||
"en-GB": "en-US"
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取当前用户真实语言 (Robust Language Detection)
|
||||
|
||||
Open WebUI 的前端(localStorage)并未自动同步语言设置到后端数据库或通过标准 API 参数传递。为了获取精准的用户偏好语言,**必须**使用多层级回退机制(Multi-level Fallback):
|
||||
`JS 动态探测 (localStorage)` > `HTTP 浏览器头 (Accept-Language)` > `用户 Profile 默认设置` > `en-US`
|
||||
|
||||
> **注意!防卡死指南 (Anti-Deadlock Guide)**
|
||||
> 在通过 `__event_call__` 执行前端 JS 脚本时,如果前端脚本不慎抛出异常 (`Exception`) 会导致回调函数 `cb()` 永不执行,这会让后端的 `asyncio` 永远阻塞并卡死整个请求队列!
|
||||
> **必须**做两重防护:
|
||||
> 1. JS 内部包裹 `try...catch` 保证必须有 `return`。
|
||||
> 2. 后端使用 `asyncio.wait_for` 设置强制超时(建议 2 秒)。
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from fastapi import Request
|
||||
|
||||
async def _get_user_context(
|
||||
self,
|
||||
__user__: Optional[dict],
|
||||
__event_call__: Optional[callable] = None,
|
||||
__request__: Optional[Request] = None,
|
||||
) -> dict:
|
||||
user_language = __user__.get("language", "en-US") if __user__ else "en-US"
|
||||
|
||||
# 1st Fallback: HTTP Accept-Language header
|
||||
if __request__ and hasattr(__request__, "headers") and "accept-language" in __request__.headers:
|
||||
raw_lang = __request__.headers.get("accept-language", "")
|
||||
if raw_lang:
|
||||
user_language = raw_lang.split(",")[0].split(";")[0]
|
||||
|
||||
# 2nd Fallback (Best): Execute JS in frontend to read localStorage
|
||||
if __event_call__:
|
||||
try:
|
||||
js_code = """
|
||||
try {
|
||||
return (
|
||||
document.documentElement.lang ||
|
||||
localStorage.getItem('locale') ||
|
||||
navigator.language ||
|
||||
'en-US'
|
||||
);
|
||||
} catch (e) {
|
||||
return 'en-US';
|
||||
}
|
||||
"""
|
||||
# 【致命!】必须设置 wait_for 防止前端无响应卡死后端
|
||||
frontend_lang = await asyncio.wait_for(
|
||||
__event_call__({"type": "execute", "data": {"code": js_code}}),
|
||||
timeout=2.0
|
||||
)
|
||||
if frontend_lang and isinstance(frontend_lang, str):
|
||||
user_language = frontend_lang
|
||||
except Exception as e:
|
||||
pass # fallback to accept-language or en-US
|
||||
|
||||
return {
|
||||
"user_language": user_language,
|
||||
# ... user_name, user_id etc.
|
||||
}
|
||||
```
|
||||
|
||||
#### 实际使用 (Usage in Action/Filter)
|
||||
|
||||
```python
|
||||
async def action(self, body: dict, __user__: Optional[dict] = None, __event_call__: Optional[callable] = None, ...):
|
||||
user_ctx = await self._get_user_context(__user__, __event_call__)
|
||||
lang = user_ctx["user_language"]
|
||||
|
||||
# Use helper to get localized string with optional formatting
|
||||
msg = self._get_translation(lang, "status_starting", name=user_ctx["user_name"])
|
||||
await self._emit_status(emitter, msg)
|
||||
```
|
||||
|
||||
#### 提示词中的语言一致性 (Language Consistency in Prompts)
|
||||
|
||||
在为 LLM 生成系统提示词时,必须包含“输出语言与输入保持一致”的指令,以确保 i18n 逻辑在 AI 生成环节也不断裂。
|
||||
|
||||
**标准指令示例**:
|
||||
- `Language`: All output must be in the exact same language as the input text provided by the user.
|
||||
- `Format Consistency`: Even if this system prompt is in English, if the user input is in Chinese, your output must be in Chinese.
|
||||
|
||||
#### CJK 脚本的特殊考量 (CJK Script Considerations)
|
||||
|
||||
当涉及字符长度限制(如思维导图标题、卡片摘要)时,应区分 CJK(中日韩)和拉丁脚本。
|
||||
- **CJK (zh, ja, ko)**: 通常应设置更小的字符数限制(如 10 字以内)。
|
||||
- **Latin (en, es, fr)**: 可设置较长的字符限制(如 5-8 个词或 35 字符)。
|
||||
|
||||
### 9. 智能代理文件交付规范 (Agent File Delivery Standards)
|
||||
### 8. 智能代理文件交付规范 (Agent File Delivery Standards)
|
||||
|
||||
在开发具备文件生成能力的智能代理插件(如 GitHub Copilot SDK 集成)时,必须遵循以下标准流程,以确保文件在不同存储后端(本地/S3)下的可用性并绕过不必要的 RAG 处理。
|
||||
|
||||
@@ -650,7 +501,7 @@ async def action(self, body: dict, __user__: Optional[dict] = None, __event_call
|
||||
- 代理应始终将“当前目录”视为其受保护所在的私有工作空间。
|
||||
- `publish_file_from_workspace` 的参数 `filename` 仅需传入相对于当前目录的文件名。
|
||||
|
||||
### 10. Copilot SDK 插件工具定义规范 (Copilot SDK Tool Definition Standards)
|
||||
### 9. Copilot SDK 插件工具定义规范 (Copilot SDK Tool Definition Standards)
|
||||
|
||||
在为 GitHub Copilot SDK 开发自定义工具时,为了确保大模型能正确识别参数(避免生成空的 `properties` Schema),必须遵循以下定义模式:
|
||||
|
||||
@@ -684,63 +535,6 @@ my_tool = define_tool(
|
||||
2. **Field 描述**: 在 `BaseModel` 中使用 `Field(..., description="...")` 为每个参数提供详细的描述信息。
|
||||
3. **Required vs Optional**: 明确标注必填项(无默认值)和可选项(带 `default`)。
|
||||
|
||||
### 11. Copilot SDK 流式渲染与工具卡片规范 (Streaming & Tool Card Standards)
|
||||
|
||||
在处理大模型的思维链(Reasoning)输出和工具调用(Tool Calls)时,为了确保能完美兼容 OpenWebUI 0.8.x 前端的 Markdown 解析器及原生折叠 UI 组件,必须遵循以下极度严格的输出格式规范。
|
||||
|
||||
#### 思维链流式渲染 (Reasoning Streaming)
|
||||
|
||||
为了让前端能够正确显示“Thinking...”的折叠框和 Spinner 动画,**必须**使用原生的 `<think>` 标签。
|
||||
|
||||
- **正确的标签包裹**:
|
||||
```html
|
||||
<think>
|
||||
这里是思考过程...
|
||||
</think>
|
||||
```
|
||||
- **关键细节**:
|
||||
- **标签闭合检测**: 必须在代码内部维护状态(如 `state["thinking_started"]`)。当(1)正文内容即将开始输出,或(2)工具调用触发 (`tool.execution_start`) 时,**必须优先输出 `\n</think>\n` 强制闭合标签**。如果不闭合,后续的正文或工具面板会被全部吞进思考框内,导致页面完全崩坏!
|
||||
- **不要手动拼装**: 严禁通过手动输出 `<details type="reasoning">` 等大段 HTML 来模拟思考过程,这种方式极易在流式片段发送中破坏前端 DOM 树并导致错位。
|
||||
|
||||
#### 工具调用原生卡片 (Native Tool Calls Block)
|
||||
|
||||
为了在对话界面中生成标准、原生的下拉折叠“工具调用”卡片,当 `event_type == "tool.execution_complete"` 时,必须向队列输出如下严格格式的 HTML:
|
||||
|
||||
```python
|
||||
# 必须转义属性中的双引号为 "
|
||||
args_for_attr = args_json_str.replace('"', """)
|
||||
result_for_attr = result_content.replace('"', """)
|
||||
|
||||
tool_block = (
|
||||
f'\\n<details type="tool_calls"'
|
||||
f' id="{tool_call_id}"'
|
||||
f' name="{tool_name}"'
|
||||
f' arguments="{args_for_attr}"'
|
||||
f' result="{result_for_attr}"'
|
||||
f' done="true">\\n'
|
||||
f"<summary>Tool Executed</summary>\\n"
|
||||
f"</details>\\n\\n"
|
||||
)
|
||||
queue.put_nowait(tool_block)
|
||||
```
|
||||
|
||||
- **致命避坑点 (Critical Pitfalls)**:
|
||||
1. **属性转义 (Extremely Important)**: `<details>` 内的 `arguments` 和 `result` 属性**必须**将内部的所有双引号 `"` 替换为 `"`。因为 OpenWebUI 前端提取这些数据的 Regex 是严格的 `="([^"]*)"`,一旦内容中出现原生双引号,就会被瞬间截断,导致参数被渲染为空并引发解析错误!
|
||||
2. **换行符要求**: `<details ...>` 尖括号闭合后紧接着的内容**必须换行**(即 `>\\n`),否则 Markdown 扩展引擎无法将其识别为独立的 UI Block。
|
||||
3. **去除冗余通知**: 不要在 `tool.execution_start` 事件中提前向对话流输出普通的 `🔧 Executing...` 纯文本块,这会导致最终页面上同时出现两块工具提示(一个文本,一个折叠卡片)。
|
||||
|
||||
#### Debug 信息的解耦 (Decoupling Debug Logs)
|
||||
|
||||
对于连接建立、运行环境、缓存加载等属于 *脚本自身运行状态* 的 Debug 信息:
|
||||
- **禁止**: 不要将这些内容 yield 到最终的回答数据流(或塞进 `<think>` 标签内),这会污染回答的纯粹性。
|
||||
- **推荐**: 统一使用 OpenWebUI 顶部的原生状态反馈气泡(Status Events):
|
||||
```python
|
||||
await __event_emitter__({
|
||||
"type": "status",
|
||||
"data": {"description": "连接建立,正在等待响应...", "done": True}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Action 插件规范 (Action Plugin Standards)
|
||||
@@ -1138,7 +932,8 @@ Filter 实例是**单例 (Singleton)**。
|
||||
|
||||
### 1. ✅ 开发检查清单 (Development Checklist)
|
||||
|
||||
- [ ] 代码实现了内置 i18n 逻辑 (`.py`)
|
||||
- [ ] 创建英文版插件代码 (`plugin_name.py`)
|
||||
- [ ] 创建中文版插件代码 (`plugin_name_cn.py`)
|
||||
- [ ] 编写英文 README (`README.md`)
|
||||
- [ ] 编写中文 README (`README_CN.md`)
|
||||
- [ ] 包含标准化文档字符串
|
||||
@@ -1146,7 +941,7 @@ Filter 实例是**单例 (Singleton)**。
|
||||
- [ ] 使用 Lucide 图标
|
||||
- [ ] 实现 Valves 配置
|
||||
- [ ] 使用 logging 而非 print
|
||||
- [ ] 测试 i18n 界面适配
|
||||
- [ ] 测试双语界面
|
||||
- [ ] **一致性检查**: 确保文档、代码、README 同步
|
||||
- [ ] **README 结构**:
|
||||
- **Key Capabilities** (英文) / **核心功能** (中文): 必须包含所有核心功能
|
||||
@@ -1156,10 +951,8 @@ Filter 实例是**单例 (Singleton)**。
|
||||
|
||||
任何插件的**新增、修改或移除**,必须同时更新:
|
||||
1. **插件代码** (version)
|
||||
2. **插件自述文件** (`plugins/{type}/{name}/README.md` & `README_CN.md`)
|
||||
3. **项目文档** (`docs/plugins/{type}/{name}.md` & `.zh.md`)
|
||||
4. **项目文档索引** (`docs/plugins/{type}/index.md` & `index.zh.md` — 版本号)
|
||||
5. **项目根 README** (`README.md` & `README_CN.md` — 更新日期徽章 `` 必须同步为发布当天日期)
|
||||
2. **项目文档** (`docs/`)
|
||||
3. **自述文件** (`README.md`)
|
||||
|
||||
### 3. 发布工作流 (Release Workflow)
|
||||
|
||||
@@ -1195,14 +988,13 @@ Filter 实例是**单例 (Singleton)**。
|
||||
2. **变更列表 (Bilingual Changes)**:
|
||||
- 英文: Clear descriptions of technical/functional changes.
|
||||
- 中文: 清晰描述用户可见的功能改进或修复。
|
||||
3. **核查状态 (Verification)**: 确认版本号已在相关 7+ 处位置同步更新(1 个代码文件 + 2 个 README + 4 个 Docs 文件)。
|
||||
3. **核查状态 (Verification)**: 确认版本号已在相关 8+ 处位置同步更新。
|
||||
|
||||
### 4. 🤖 Git 提交与推送规范 (Git Operations & Push Rules)
|
||||
|
||||
- **核心原则**: 默认仅进行**本地文件准备**(更新代码、READMEs、Docs、版本号),**严禁**在未获用户明确许可的情况下自动执行 `git commit` 或 `git push`。
|
||||
- **允许 (需确认)**: 只有在用户明确表示“发布”、“Commit it”、“Release”或“提交”后,才允许直接推送到 `main` 分支或创建 PR。
|
||||
- **功能分支**: 推荐在进行大规模重构或实验性功能开发时,创建功能分支 (`feature/xxx`) 进行隔离。
|
||||
- **PR 提交**: 必须使用 GitHub CLI (`gh`) 创建 Pull Request。示例:`gh pr create --title "feat: ..." --body "..."`。
|
||||
|
||||
### 5. 🤝 贡献者认可规范 (Contributor Recognition)
|
||||
|
||||
@@ -1212,7 +1004,8 @@ Filter 实例是**单例 (Singleton)**。
|
||||
|
||||
## 📚 参考资源 (Reference Resources)
|
||||
|
||||
- [Action 插件模板](plugins/actions/ACTION_PLUGIN_TEMPLATE.py)
|
||||
- [Action 插件模板 (英文)](plugins/actions/ACTION_PLUGIN_TEMPLATE.py)
|
||||
- [Action 插件模板 (中文)](plugins/actions/ACTION_PLUGIN_TEMPLATE_CN.py)
|
||||
- [插件开发指南](plugins/actions/PLUGIN_DEVELOPMENT_GUIDE.md)
|
||||
- [Lucide Icons](https://lucide.dev/icons/)
|
||||
- [OpenWebUI 文档](https://docs.openwebui.com/)
|
||||
|
||||
54
.github/instructions/code-review.instructions.md
vendored
54
.github/instructions/code-review.instructions.md
vendored
@@ -1,54 +0,0 @@
|
||||
---
|
||||
name: Plugin Code Review
|
||||
description: Comprehensive OpenWebUI plugin review checklist covering i18n, context helpers, antigravity safety, and streaming compatibility
|
||||
applyTo: "plugins/**/*.py"
|
||||
---
|
||||
# Code Review Instructions — OpenWebUI Plugins
|
||||
|
||||
You are an expert Senior Software Engineer reviewing OpenWebUI plugins for the `openwebui-extensions` repository.
|
||||
When reviewing plugin code, you MUST verify each point below to ensure the code meets the strict repository standards.
|
||||
|
||||
## 1. Single-file i18n Pattern (CRITICAL)
|
||||
- **One File Rule**: One `.py` file per plugin. No `_cn.py` or language-split files.
|
||||
- **Translations**: All user-visible strings (status, notification, UI text) MUST go through a `TRANSLATIONS` dictionary and a `FALLBACK_MAP`.
|
||||
- **Safety**: `format(**kwargs)` calls on translated strings MUST be wrapped in `try/except KeyError` to prevent crashes if a translation is missing a placeholder.
|
||||
|
||||
## 2. Context Helpers (CRITICAL)
|
||||
- **User Context**: MUST use `_get_user_context(__user__)` instead of direct `__user__["name"]` access. `__user__` can be a list, dict, or None.
|
||||
- **Chat Context**: MUST use `_get_chat_context(body, __metadata__)` instead of ad-hoc `body.get("chat_id")` calls.
|
||||
|
||||
## 3. Event & Logging
|
||||
- **No Print**: No bare `print()` in production code. Use `logging.getLogger(__name__)`.
|
||||
- **Emitter Safety**: Every `await emitter(...)` call MUST be guarded by `if emitter:` (or equivalent).
|
||||
- **Status Lifecycle**:
|
||||
- `_emit_status(done=False)` at task start.
|
||||
- `_emit_status(done=True)` on completion.
|
||||
- `_emit_notification("error")` on failure.
|
||||
|
||||
## 4. Antigravity Safety (CRITICAL)
|
||||
- **Timeout Guards**: All `__event_call__` JS executions MUST be wrapped with `asyncio.wait_for(..., timeout=2.0)`. Failure to do this can hang the entire backend.
|
||||
- **JS Fallbacks**: JS code executed via `__event_call__` MUST have an internal `try { ... } catch (e) { return fallback; }` block.
|
||||
- **Path Sandboxing**: File path operations MUST be validated against the workspace root (no directory traversal vulnerabilities).
|
||||
- **Upload Fallbacks**: Upload paths MUST have a dual-channel fallback (API → local/DB).
|
||||
|
||||
## 5. Filter Singleton Safety
|
||||
- **No Mutable State**: Filter plugins are singletons. There MUST be NO request-scoped mutable state stored on `self` (e.g., `self.current_user = ...`).
|
||||
- **Statelessness**: Per-request values MUST be computed from `body` and context helpers on each call.
|
||||
|
||||
## 6. Copilot SDK Tools
|
||||
- **Pydantic Models**: Tool parameters MUST be defined as a `pydantic.BaseModel` subclass.
|
||||
- **Explicit Params**: `define_tool(...)` MUST include `params_type=MyParams`.
|
||||
- **Naming**: Tool names MUST match `^[a-zA-Z0-9_-]+$` (ASCII only).
|
||||
|
||||
## 7. Streaming Compatibility (OpenWebUI 0.8.x)
|
||||
- **Thinking Tags**: The `</think>` tag MUST be closed before any normal content or tool cards are emitted.
|
||||
- **Attribute Escaping**: Tool card `arguments` and `result` attributes MUST escape `"` as `"`.
|
||||
- **Newline Requirement**: The `<details type="tool_calls" ...>` block MUST be followed by a newline immediately after `>`.
|
||||
|
||||
## 8. Performance & Memory
|
||||
- **Streaming**: Large files or responses MUST be streamed, not loaded entirely into memory.
|
||||
- **Database Connections**: Plugins MUST reuse the OpenWebUI internal database connection (`owui_engine`, `owui_Session`) rather than creating new ones.
|
||||
|
||||
## 9. HTML Injection (Action Plugins)
|
||||
- **Wrapper Template**: HTML output MUST use the standard `<!-- OPENWEBUI_PLUGIN_OUTPUT -->` wrapper.
|
||||
- **Idempotency**: The plugin MUST implement `_remove_existing_html` to ensure multiple runs do not duplicate the HTML output.
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
name: Commit Message
|
||||
description: Comprehensive Conventional Commits guidelines for openwebui-extensions
|
||||
---
|
||||
# Commit Message Instructions
|
||||
|
||||
You are an expert developer generating commit messages for the `openwebui-extensions` repository.
|
||||
Always adhere to the following strict guidelines based on the Conventional Commits specification.
|
||||
|
||||
## 1. General Rules
|
||||
- **Language**: **English ONLY**. Never use Chinese or other languages in the commit title or body.
|
||||
- **Structure**:
|
||||
```text
|
||||
<type>(<scope>): <subject>
|
||||
<BLANK LINE>
|
||||
<body>
|
||||
<BLANK LINE>
|
||||
<footer>
|
||||
```
|
||||
|
||||
## 2. Type (`<type>`)
|
||||
Must be one of the following:
|
||||
- `feat`: A new feature or a new plugin.
|
||||
- `fix`: A bug fix.
|
||||
- `docs`: Documentation only changes (e.g., README, MkDocs).
|
||||
- `refactor`: A code change that neither fixes a bug nor adds a feature.
|
||||
- `perf`: A code change that improves performance.
|
||||
- `test`: Adding missing tests or correcting existing tests.
|
||||
- `chore`: Changes to the build process, CI/CD, or auxiliary tools/scripts.
|
||||
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, etc.).
|
||||
|
||||
## 3. Scope (`<scope>`)
|
||||
The scope should indicate the affected component or plugin.
|
||||
- **For Plugins**: Use the plugin's folder name or category (e.g., `actions`, `filters`, `pipes`, `export-to-docx`, `github-copilot-sdk`).
|
||||
- **For Docs**: Use `docs` or the specific doc section (e.g., `guide`, `readme`).
|
||||
- **For Infra**: Use `ci`, `scripts`, `deps`.
|
||||
- *Note*: Omit the scope if the change is global or spans too many components.
|
||||
|
||||
## 4. Subject Line (`<subject>`)
|
||||
- **Length**: Keep it under 50-72 characters.
|
||||
- **Mood**: Use the imperative, present tense: "change" not "changed" nor "changes" (e.g., "add feature" instead of "added feature").
|
||||
- **Formatting**: Do not capitalize the first letter. Do not place a period `.` at the end.
|
||||
- **Clarity**: State exactly *what* changed. Avoid vague terms like "update code" or "fix bug".
|
||||
|
||||
## 5. Body (`<body>`)
|
||||
- **When to use**: Highly recommended for `feat`, `fix`, and `refactor`.
|
||||
- **Content**: Explain *what* and *why* (motivation), not just *how* (the code diff shows the how).
|
||||
- **Format**: Use a bulleted list (1-3 points) for readability.
|
||||
- **Repo Specifics**: If the commit involves a plugin version bump, explicitly mention that the READMEs and docs were synced.
|
||||
|
||||
## 6. Footer / Breaking Changes (`<footer>`)
|
||||
- If the commit introduces a breaking change (e.g., changing a Valve configuration key, altering a plugin's output format), append `!` after the scope/type: `feat(pipes)!: ...`
|
||||
- Add a `BREAKING CHANGE:` block in the footer explaining the migration path.
|
||||
|
||||
## 7. Examples
|
||||
|
||||
**Example 1: Feature with Body**
|
||||
```text
|
||||
feat(github-copilot-sdk): add antigravity timeout guards
|
||||
|
||||
- Wrap all __event_call__ JS executions with asyncio.wait_for(timeout=2.0)
|
||||
- Add dual-channel upload fallback (API → local/DB)
|
||||
- Emit staged status events for tasks > 3 seconds
|
||||
```
|
||||
|
||||
**Example 2: Bug Fix**
|
||||
```text
|
||||
fix(export-to-docx): resolve missing title fallback
|
||||
|
||||
- Fallback to user_name + date when chat_title is empty
|
||||
- Prevent crash when metadata variables are missing
|
||||
```
|
||||
|
||||
**Example 3: Documentation Sync**
|
||||
```text
|
||||
docs(plugins): sync bilingual READMEs for v1.2.0 release
|
||||
|
||||
- Update What's New section for folder-memory plugin
|
||||
- Sync docs/plugins/filters/folder-memory.md
|
||||
```
|
||||
|
||||
**Example 4: Breaking Change**
|
||||
```text
|
||||
refactor(core)!: rename global configuration valves
|
||||
|
||||
- Standardize all valve keys to UPPER_SNAKE_CASE
|
||||
- Remove deprecated legacy_api_key field
|
||||
|
||||
BREAKING CHANGE: Users must reconfigure their API keys in the UI as the old `api_key` field is no longer read.
|
||||
```
|
||||
@@ -1,54 +0,0 @@
|
||||
---
|
||||
name: Test Generation
|
||||
description: Comprehensive Pytest conventions, mocking strategies, and model usage rules for OpenWebUI plugins
|
||||
applyTo: "plugins/debug/**,tests/**"
|
||||
---
|
||||
# Test Generation Instructions
|
||||
|
||||
You are an expert SDET (Software Development Engineer in Test) writing tests for the `openwebui-extensions` repository.
|
||||
Follow these comprehensive guidelines to ensure robust, reliable, and cost-effective testing.
|
||||
|
||||
## 1. Test Structure & Placement
|
||||
- **Unit Tests**: Place in the `tests/` directory at the root of the repository. Name files `test_<module>.py`.
|
||||
- **Integration/Debug Scripts**: Place in `plugins/debug/<plugin_name>/`. Name files `debug_<feature>.py` or `inspect_<feature>.py`.
|
||||
- **Fixtures**: Use `conftest.py` for shared fixtures (e.g., mock users, mock emitters, mock database sessions).
|
||||
|
||||
## 2. Model Usage & Cost Control (CRITICAL)
|
||||
When writing tests or debug scripts that actually invoke an LLM:
|
||||
- **Allowed Models**: You MUST use low-cost models: `gpt-5-mini` (Preferred) or `gpt-4.1`.
|
||||
- **Forbidden**: NEVER use expensive models (like `gpt-4-turbo`, `claude-3-opus`) in automated tests unless explicitly requested by the user.
|
||||
- **API Keys**: Never hardcode API keys. Always read from environment variables (`os.getenv("OPENAI_API_KEY")`) or a `.env` file.
|
||||
|
||||
## 3. Mocking OpenWebUI Internals
|
||||
OpenWebUI plugins rely heavily on injected runtime variables. Your tests must mock these accurately:
|
||||
- **`__user__`**: Mock as a dictionary. Always test both with a full user object and an empty/None object to ensure fallback logic works.
|
||||
```python
|
||||
mock_user_en = {"id": "u1", "name": "Alice", "language": "en-US"}
|
||||
mock_user_zh = {"id": "u2", "name": "Bob", "language": "zh-CN"}
|
||||
mock_user_none = None
|
||||
```
|
||||
- **`__event_emitter__`**: Mock as an async callable that records emitted events for assertion.
|
||||
```python
|
||||
async def mock_emitter(event: dict):
|
||||
emitted_events.append(event)
|
||||
```
|
||||
- **`__event_call__`**: Mock as an async callable. To test Antigravity timeout guards, you must occasionally mock this to sleep longer than the timeout (e.g., `await asyncio.sleep(3.0)`) to ensure `asyncio.wait_for` catches it.
|
||||
|
||||
## 4. Testing Async Code
|
||||
- All OpenWebUI plugin entry points (`action`, `inlet`, `outlet`) are asynchronous.
|
||||
- Use `@pytest.mark.asyncio` for all test functions.
|
||||
- Ensure you `await` all plugin method calls.
|
||||
|
||||
## 5. i18n (Internationalization) Testing
|
||||
Since all plugins must be single-file i18n:
|
||||
- **Mandatory**: Write parameterized tests to verify output in both English (`en-US`) and Chinese (`zh-CN`).
|
||||
- Verify that if an unsupported language is passed (e.g., `fr-FR`), the system correctly falls back to the default (usually `en-US`).
|
||||
|
||||
## 6. Antigravity & Safety Testing
|
||||
- **Timeout Guards**: Explicitly test that frontend JS executions (`__event_call__`) do not hang the backend. Assert that a `TimeoutError` is caught and handled gracefully.
|
||||
- **State Leakage**: For `Filter` plugins (which are singletons), write tests that simulate concurrent requests from different users to ensure no state leaks across `self`.
|
||||
|
||||
## 7. Assertions & Best Practices
|
||||
- Assert on **behavior and output**, not internal implementation details.
|
||||
- For HTML/Markdown generation plugins, use Regex or BeautifulSoup to assert the presence of required tags (e.g., `<!-- OPENWEBUI_PLUGIN_OUTPUT -->`) rather than exact string matching.
|
||||
- Keep tests isolated. Do not rely on the execution order of tests.
|
||||
44
.github/skills/README.md
vendored
44
.github/skills/README.md
vendored
@@ -1,44 +0,0 @@
|
||||
# Agent Skills Index
|
||||
|
||||
This folder contains reusable Agent Skills for GitHub Copilot / VS Code custom agent workflows.
|
||||
|
||||
## Available Skills
|
||||
|
||||
- **community-announcer**
|
||||
- Purpose: Generate community announcement content and related assets.
|
||||
- Entry: `community-announcer/SKILL.md`
|
||||
|
||||
- **doc-mirror-sync**
|
||||
- Purpose: Sync mirrored documentation content and helper scripts.
|
||||
- Entry: `doc-mirror-sync/SKILL.md`
|
||||
|
||||
- **gh-issue-replier**
|
||||
- Purpose: Draft standardized issue replies with templates.
|
||||
- Entry: `gh-issue-replier/SKILL.md`
|
||||
|
||||
- **gh-issue-scheduler**
|
||||
- Purpose: Schedule and discover unanswered issues for follow-up.
|
||||
- Entry: `gh-issue-scheduler/SKILL.md`
|
||||
|
||||
- **i18n-validator**
|
||||
- Purpose: Validate translation key consistency across i18n dictionaries.
|
||||
- Entry: `i18n-validator/SKILL.md`
|
||||
|
||||
- **plugin-scaffolder**
|
||||
- Purpose: Scaffold OpenWebUI plugin boilerplate with repository standards.
|
||||
- Entry: `plugin-scaffolder/SKILL.md`
|
||||
|
||||
- **version-bumper**
|
||||
- Purpose: Assist with semantic version bumping workflows.
|
||||
- Entry: `version-bumper/SKILL.md`
|
||||
|
||||
- **xlsx-single-file**
|
||||
- Purpose: Single-file spreadsheet operations workflow without LibreOffice.
|
||||
- Entry: `xlsx-single-file/SKILL.md`
|
||||
|
||||
## Notes
|
||||
|
||||
- Skill definitions follow the expected location pattern:
|
||||
- `.github/skills/<skill-name>/SKILL.md`
|
||||
- Each skill may include optional `assets/`, `references/`, and `scripts/` folders.
|
||||
- This directory mirrors `.gemini/skills` for compatibility.
|
||||
23
.github/skills/community-announcer/SKILL.md
vendored
23
.github/skills/community-announcer/SKILL.md
vendored
@@ -1,23 +0,0 @@
|
||||
---
|
||||
name: community-announcer
|
||||
description: Drafts engaging English and Chinese update announcements for the OpenWebUI Community and other social platforms. Use when a new version is released.
|
||||
---
|
||||
|
||||
# Community Announcer
|
||||
|
||||
## Overview
|
||||
Automates the drafting of high-impact update announcements.
|
||||
|
||||
## Workflow
|
||||
1. **Source Intel**: Read the latest version's `What's New` section from `README.md`.
|
||||
2. **Drafting**: Create two versions:
|
||||
- **Community Post**: Professional, structured, technical.
|
||||
- **Catchy Short**: For Discord/Twitter, use emojis and bullet points.
|
||||
3. **Multi-language**: Generate BOTH English and Chinese versions automatically.
|
||||
|
||||
## Announcement Structure (Recommended)
|
||||
- **Headline**: "Update vX.X.X - [Main Feature]"
|
||||
- **Introduction**: Brief context.
|
||||
- **Key Highlights**: Bulleted list of fixes/features.
|
||||
- **Action**: "Download from [Market Link]"
|
||||
- **Closing**: Thanks and Star request.
|
||||
14
.github/skills/doc-mirror-sync/SKILL.md
vendored
14
.github/skills/doc-mirror-sync/SKILL.md
vendored
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: doc-mirror-sync
|
||||
description: Automatically synchronizes plugin READMEs to the official documentation directory (docs/). Use after editing a plugin's local documentation to keep the MkDocs site up to date.
|
||||
---
|
||||
|
||||
# Doc Mirror Sync
|
||||
|
||||
## Overview
|
||||
Automates the mirroring of `plugins/{type}/{name}/README.md` to `docs/plugins/{type}/{name}.md`.
|
||||
|
||||
## Workflow
|
||||
1. Identify changed READMEs.
|
||||
2. Copy content to corresponding mirror paths.
|
||||
3. Update version badges in `docs/plugins/{type}/index.md`.
|
||||
38
.github/skills/doc-mirror-sync/scripts/sync.py
vendored
38
.github/skills/doc-mirror-sync/scripts/sync.py
vendored
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import shutil
|
||||
import re
|
||||
|
||||
def sync_mirrors():
|
||||
plugins_root = "plugins"
|
||||
docs_root = "docs/plugins"
|
||||
|
||||
types = ["actions", "filters", "pipes", "pipelines", "tools"]
|
||||
|
||||
for t in types:
|
||||
src_type_dir = os.path.join(plugins_root, t)
|
||||
dest_type_dir = os.path.join(docs_root, t)
|
||||
|
||||
if not os.path.exists(src_type_dir): continue
|
||||
os.makedirs(dest_type_dir, exist_ok=True)
|
||||
|
||||
for name in os.listdir(src_type_dir):
|
||||
plugin_dir = os.path.join(src_type_dir, name)
|
||||
if not os.path.isdir(plugin_dir): continue
|
||||
|
||||
# Sync README.md -> docs/plugins/{type}/{name}.md
|
||||
src_readme = os.path.join(plugin_dir, "README.md")
|
||||
if os.path.exists(src_readme):
|
||||
dest_readme = os.path.join(dest_type_dir, f"{name}.md")
|
||||
shutil.copy(src_readme, dest_readme)
|
||||
print(f"✅ Mirrored: {t}/{name} (EN)")
|
||||
|
||||
# Sync README_CN.md -> docs/plugins/{type}/{name}.zh.md
|
||||
src_readme_cn = os.path.join(plugin_dir, "README_CN.md")
|
||||
if os.path.exists(src_readme_cn):
|
||||
dest_readme_zh = os.path.join(dest_type_dir, f"{name}.zh.md")
|
||||
shutil.copy(src_readme_cn, dest_readme_zh)
|
||||
print(f"✅ Mirrored: {t}/{name} (ZH)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
sync_mirrors()
|
||||
51
.github/skills/gh-issue-replier/SKILL.md
vendored
51
.github/skills/gh-issue-replier/SKILL.md
vendored
@@ -1,51 +0,0 @@
|
||||
---
|
||||
name: gh-issue-replier
|
||||
description: Professional English replier for GitHub issues. Use when a task is completed, a bug is fixed, or more info is needed from the user. Automates replying using the 'gh' CLI tool.
|
||||
---
|
||||
|
||||
# Gh Issue Replier
|
||||
|
||||
## Overview
|
||||
|
||||
The `gh-issue-replier` skill enables Gemini CLI to interact with GitHub issues professionally. It enforces English for all communications and leverages the `gh` CLI to post comments.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Identify the Issue**: Find the issue number (e.g., #49).
|
||||
2. **Check Star Status**: Run the bundled script to check if the author has starred the repo.
|
||||
* Command: `bash scripts/check_star.sh <issue-number>`
|
||||
* Interpretation:
|
||||
* Exit code **0**: User has starred. Use "Already Starred" templates.
|
||||
* Exit code **1**: User has NOT starred. Include "Star Request" in the reply.
|
||||
3. **Select a Template**: Load [templates.md](references/templates.md) to choose a suitable English response pattern.
|
||||
4. **Draft the Reply**: Compose a concise message based on the star status.
|
||||
5. **Post the Comment**: Use the `gh` tool to submit the reply.
|
||||
|
||||
## Tool Integration
|
||||
|
||||
### Check Star Status
|
||||
```bash
|
||||
bash scripts/check_star.sh <issue-number>
|
||||
```
|
||||
|
||||
### Post Comment
|
||||
```bash
|
||||
gh issue comment <issue-number> --body "<message-body>"
|
||||
```
|
||||
|
||||
Example (if user has NOT starred):
|
||||
```bash
|
||||
gh issue comment 49 --body "This has been fixed in v1.2.7. If you find this helpful, a star on the repo would be much appreciated! ⭐"
|
||||
```
|
||||
|
||||
Example (if user HAS starred):
|
||||
```bash
|
||||
gh issue comment 49 --body "This has been fixed in v1.2.7. Thanks for your support!"
|
||||
```
|
||||
|
||||
## Guidelines
|
||||
|
||||
- **Language**: ALWAYS use English for the comment body, even if the system prompt or user conversation is in another language.
|
||||
- **Tone**: Professional, helpful, and appreciative.
|
||||
- **Precision**: When announcing a fix, mention the specific version or the logic change (e.g., "Updated regex pattern").
|
||||
- **Closing**: If the issue is resolved and you have permission, you can also use `gh issue close <number>`.
|
||||
@@ -1,17 +0,0 @@
|
||||
# Reference Documentation for Gh Issue Replier
|
||||
|
||||
This is a placeholder for detailed reference documentation.
|
||||
Replace with actual reference content or delete if not needed.
|
||||
|
||||
## Structure Suggestions
|
||||
|
||||
### API Reference Example
|
||||
- Overview
|
||||
- Authentication
|
||||
- Endpoints with examples
|
||||
- Error codes
|
||||
|
||||
### Workflow Guide Example
|
||||
- Prerequisites
|
||||
- Step-by-step instructions
|
||||
- Best practices
|
||||
@@ -1,45 +0,0 @@
|
||||
# Issue Reply Templates
|
||||
|
||||
Use these templates to craft professional English replies. Adjust placeholders like `@username`, `v1.2.x`, and `[commit hash]` as needed.
|
||||
|
||||
## 1. Acknowledging a New Issue
|
||||
Use when you first see an issue and want to let the user know you are working on it.
|
||||
|
||||
- "Thank you for reporting this! I'm looking into it right now."
|
||||
- "Thanks for bringing this to my attention. I'll try to reproduce this behavior and get back to you shortly."
|
||||
|
||||
## 2. Requesting More Information
|
||||
Use when you need logs or specific details to fix the bug.
|
||||
|
||||
- "Could you please provide the **'Original'** vs **'Normalized'** content from your browser console logs (F12)? It would help a lot in debugging."
|
||||
- "It would be very helpful if you could share the specific Markdown text that triggered this issue."
|
||||
|
||||
## 3. Announcing a Fix
|
||||
Use when you have pushed the fix to the repository.
|
||||
|
||||
- "This has been fixed in version **v1.2.x**. You can update the plugin to resolve it."
|
||||
- "I've just pushed a fix for this in [commit hash]. Please let me know if it works for you after updating."
|
||||
- "The issue was caused by a greedy regex pattern. I've updated it to use a tempered greedy token to prevent incorrect merging."
|
||||
|
||||
## 4. Guiding to Official Market
|
||||
Always provide the official market link to ensure the user gets the latest verified version.
|
||||
|
||||
- "The fix is now live! You can download the latest version from the official OpenWebUI Community page here: [Plugin Market Link]. Simply update the function in your OpenWebUI instance to apply the changes."
|
||||
- "I recommend getting the updated version from the official store: [Link]. It includes the fix for the spacing issue we discussed."
|
||||
|
||||
## 5. Closing the Issue
|
||||
Use when the issue is confirmed resolved.
|
||||
|
||||
- "Glad to hear it's working now! Closing this for now. Feel free to reopen it if the problem persists."
|
||||
- "Since this is resolved, I'm closing this issue. Thanks again for your feedback!"
|
||||
|
||||
## 5. Pro-tip: Star Request
|
||||
Gently handle star requests based on the user's current status.
|
||||
|
||||
### If User has NOT starred:
|
||||
- "If you find this plugin helpful, a star on the repo would be much appreciated! ⭐"
|
||||
- "We'd love your support! If this fixed your issue, please consider starring the repository. ⭐"
|
||||
|
||||
### If User HAS already starred:
|
||||
- "Thanks again for starring the project and for your continuous support!"
|
||||
- "I appreciate your support and for being a stargazer of this project!"
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Robust Star Checker v2
|
||||
# Usage: ./check_star.sh <issue_number>
|
||||
|
||||
ISSUE_NUM=$1
|
||||
if [ -z "$ISSUE_NUM" ]; then exit 2; fi
|
||||
|
||||
# 1. Get Repo and Author info
|
||||
REPO_FULL=$(gh repo view --json owner,name -q ".owner.login + \"/\" + .name")
|
||||
USER_LOGIN=$(gh issue view "$ISSUE_NUM" --json author -q ".author.login")
|
||||
|
||||
# 2. Use GraphQL for high precision (Detects stars even when REST 404s)
|
||||
IS_STARRED=$(gh api graphql -f query='
|
||||
query($owner:String!, $repo:String!, $user:String!) {
|
||||
repository(owner:$owner, name:$repo) {
|
||||
stargazers(query:$user, first:1) {
|
||||
nodes {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
}' -f owner="${REPO_FULL%/*}" -f repo="${REPO_FULL#*/}" -f user="$USER_LOGIN" -q ".data.repository.stargazers.nodes[0].login")
|
||||
|
||||
if [ "$IS_STARRED" == "$USER_LOGIN" ]; then
|
||||
echo "Confirmed: @$USER_LOGIN HAS starred $REPO_FULL. ⭐"
|
||||
exit 0
|
||||
else
|
||||
echo "Confirmed: @$USER_LOGIN has NOT starred $REPO_FULL."
|
||||
exit 1
|
||||
fi
|
||||
42
.github/skills/gh-issue-scheduler/SKILL.md
vendored
42
.github/skills/gh-issue-scheduler/SKILL.md
vendored
@@ -1,42 +0,0 @@
|
||||
---
|
||||
name: gh-issue-scheduler
|
||||
description: Finds all open GitHub issues that haven't been replied to by the owner, summarizes them, and generates a solution plan. Use when the user wants to audit pending tasks or plan maintenance work.
|
||||
---
|
||||
|
||||
# Gh Issue Scheduler
|
||||
|
||||
## Overview
|
||||
|
||||
The `gh-issue-scheduler` skill helps maintainers track community feedback by identifying unaddressed issues and drafting actionable technical plans to resolve them.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Identify Unanswered Issues**: Run the bundled script to fetch issues without owner replies.
|
||||
* Command: `bash scripts/find_unanswered.sh`
|
||||
2. **Analyze and Summarize**: For each identified issue, summarize the core problem and the user's intent.
|
||||
3. **Generate Solution Plans**: Draft a technical "Action Plan" for each issue, including:
|
||||
* **Root Cause Analysis** (if possible)
|
||||
* **Proposed Fix/Implementation**
|
||||
* **Verification Strategy**
|
||||
4. **Present to User**: Display a structured report of all pending issues and their respective plans.
|
||||
|
||||
## Tool Integration
|
||||
|
||||
### Find Unanswered Issues
|
||||
```bash
|
||||
bash scripts/find_unanswered.sh
|
||||
```
|
||||
|
||||
## Report Format
|
||||
|
||||
When presenting the summary, use the following Markdown structure:
|
||||
|
||||
### 📋 Unanswered Issues Audit
|
||||
|
||||
#### Issue #[Number]: [Title]
|
||||
- **Author**: @username
|
||||
- **Summary**: Concise description of the problem.
|
||||
- **Action Plan**:
|
||||
1. Step 1 (e.g., Investigate file X)
|
||||
2. Step 2 (e.g., Apply fix Y)
|
||||
3. Verification (e.g., Run test Z)
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Fetch all open issues and filter for those without responses from the owner/collaborators.
|
||||
# Uses 'gh' CLI.
|
||||
|
||||
REPO_FULL=$(gh repo view --json owner,name -q ".owner.login + "/" + .name")
|
||||
OWNER=${REPO_FULL%/*}
|
||||
|
||||
# 1. Get all open issues
|
||||
OPEN_ISSUES=$(gh issue list --state open --json number,title,author,createdAt --limit 100)
|
||||
|
||||
echo "Analysis for repository: $REPO_FULL"
|
||||
echo "------------------------------------"
|
||||
|
||||
# Process each issue
|
||||
echo "$OPEN_ISSUES" | jq -c '.[]' | while read -r issue; do
|
||||
NUMBER=$(echo "$issue" | jq -r '.number')
|
||||
TITLE=$(echo "$issue" | jq -r '.title')
|
||||
AUTHOR=$(echo "$issue" | jq -r '.author.login')
|
||||
|
||||
# Check comments for owner responses
|
||||
# We look for comments where the author is the repo owner
|
||||
COMMENTS=$(gh issue view "$NUMBER" --json comments -q ".comments[].author.login" 2>/dev/null)
|
||||
|
||||
HAS_OWNER_REPLY=false
|
||||
for COMMENT_AUTHOR in $COMMENTS; do
|
||||
if [ "$COMMENT_AUTHOR" == "$OWNER" ]; then
|
||||
HAS_OWNER_REPLY=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$HAS_OWNER_REPLY" == "false" ]; then
|
||||
echo "ISSUE_START"
|
||||
echo "ID: $NUMBER"
|
||||
echo "Title: $TITLE"
|
||||
echo "Author: $AUTHOR"
|
||||
echo "Description:"
|
||||
gh issue view "$NUMBER" --json body -q ".body"
|
||||
echo "ISSUE_END"
|
||||
fi
|
||||
done
|
||||
14
.github/skills/i18n-validator/SKILL.md
vendored
14
.github/skills/i18n-validator/SKILL.md
vendored
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: i18n-validator
|
||||
description: Validates multi-language consistency in the TRANSLATIONS dictionary of a plugin. Use to check if any language keys are missing or if translations need updating.
|
||||
---
|
||||
|
||||
# I18n Validator
|
||||
|
||||
## Overview
|
||||
Ensures all 12 supported languages (en-US, zh-CN, etc.) have aligned translation keys.
|
||||
|
||||
## Features
|
||||
- Detects missing keys in non-English dictionaries.
|
||||
- Suggests translations using the core AI engine.
|
||||
- Validates the `fallback_map` for variant redirects.
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import ast
|
||||
import os
|
||||
|
||||
def check_i18n(file_path):
|
||||
if not os.path.exists(file_path):
|
||||
print(f"Error: File not found {file_path}")
|
||||
return
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
tree = ast.parse(f.read())
|
||||
|
||||
translations = {}
|
||||
for node in tree.body:
|
||||
if isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and target.id == "TRANSLATIONS":
|
||||
translations = ast.literal_eval(node.value)
|
||||
break
|
||||
|
||||
if not translations:
|
||||
print("⚠️ No TRANSLATIONS dictionary found.")
|
||||
return
|
||||
|
||||
# Base keys from English
|
||||
base_lang = "en-US"
|
||||
if base_lang not in translations:
|
||||
print(f"❌ Error: {base_lang} missing in TRANSLATIONS.")
|
||||
return
|
||||
|
||||
base_keys = set(translations[base_lang].keys())
|
||||
print(f"🔍 Analyzing {file_path}...")
|
||||
print(f"Standard keys ({len(base_keys)}): {', '.join(sorted(base_keys))}
|
||||
")
|
||||
|
||||
for lang, keys in translations.items():
|
||||
if lang == base_lang: continue
|
||||
lang_keys = set(keys.keys())
|
||||
missing = base_keys - lang_keys
|
||||
extra = lang_keys - base_keys
|
||||
|
||||
if missing:
|
||||
print(f"❌ {lang}: Missing {len(missing)} keys: {', '.join(missing)}")
|
||||
if extra:
|
||||
print(f"⚠️ {lang}: Has {len(extra)} extra keys: {', '.join(extra)}")
|
||||
if not missing and not extra:
|
||||
print(f"✅ {lang}: Aligned.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: validate_i18n.py <path_to_plugin.py>")
|
||||
sys.exit(1)
|
||||
check_i18n(sys.argv[1])
|
||||
19
.github/skills/plugin-scaffolder/SKILL.md
vendored
19
.github/skills/plugin-scaffolder/SKILL.md
vendored
@@ -1,19 +0,0 @@
|
||||
---
|
||||
name: plugin-scaffolder
|
||||
description: Generates a standardized single-file i18n Python plugin template based on project standards. Use when starting a new plugin development to skip boilerplate writing.
|
||||
---
|
||||
|
||||
# Plugin Scaffolder
|
||||
|
||||
## Overview
|
||||
Generates compliant OpenWebUI plugin templates with built-in i18n, common utility methods, and required docstring fields.
|
||||
|
||||
## Usage
|
||||
1. Provide the **Plugin Name** and **Type** (action/filter/pipe).
|
||||
2. The skill will generate the `.py` file and the bilingual `README` files.
|
||||
|
||||
## Template Standard
|
||||
- `Valves(BaseModel)` with `UPPER_SNAKE_CASE`
|
||||
- `_get_user_context` with JS fallback and timeout
|
||||
- `_emit_status` and `_emit_debug_log` methods
|
||||
- Standardized docstring metadata
|
||||
@@ -1,34 +0,0 @@
|
||||
# {{TITLE}}
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **Version:** 0.1.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
|
||||
{{DESCRIPTION}}
|
||||
|
||||
## 🔥 What's New in v0.1.0
|
||||
|
||||
* Initial release of {{TITLE}}.
|
||||
|
||||
## 🌐 Multilingual Support
|
||||
|
||||
Supports automatic interface and status switching for the following languages:
|
||||
`English`, `简体中文`, `繁體中文 (香港)`, `繁體中文 (台灣)`, `한국어`, `日本語`, `Français`, `Deutsch`, `Español`, `Italiano`, `Tiếng Việt`, `Bahasa Indonesia`.
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
* Feature 1
|
||||
* Feature 2
|
||||
|
||||
## How to Use 🛠️
|
||||
|
||||
1. Install the plugin in Open WebUI.
|
||||
2. Configure settings in Valves.
|
||||
|
||||
## Configuration (Valves) ⚙️
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `priority` | `50` | Execution priority. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) is a big motivation for me. Thank you for the support.
|
||||
@@ -1,80 +0,0 @@
|
||||
"""
|
||||
title: {{TITLE}}
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||
funding_url: https://github.com/open-webui
|
||||
version: 0.1.0
|
||||
description: {{DESCRIPTION}}
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import json
|
||||
from typing import Optional, Dict, Any, List, Callable, Awaitable
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi import Request
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TRANSLATIONS = {
|
||||
"en-US": {"status_starting": "Starting {{TITLE}}..."},
|
||||
"zh-CN": {"status_starting": "正在启动 {{TITLE}}..."},
|
||||
"zh-HK": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"zh-TW": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"ko-KR": {"status_starting": "{{TITLE}} 시작 중..."},
|
||||
"ja-JP": {"status_starting": "{{TITLE}} を起動中..."},
|
||||
"fr-FR": {"status_starting": "Démarrage de {{TITLE}}..."},
|
||||
"de-DE": {"status_starting": "{{TITLE}} wird gestartet..."},
|
||||
"es-ES": {"status_starting": "Iniciando {{TITLE}}..."},
|
||||
"it-IT": {"status_starting": "Avvio di {{TITLE}}..."},
|
||||
"vi-VN": {"status_starting": "Đang khởi động {{TITLE}}..."},
|
||||
"id-ID": {"status_starting": "Memulai {{TITLE}}..."},
|
||||
}
|
||||
|
||||
class {{CLASS_NAME}}:
|
||||
class Valves(BaseModel):
|
||||
priority: int = Field(default=50, description="Priority level (lower = earlier).")
|
||||
show_status: bool = Field(default=True, description="Show status updates in UI.")
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.fallback_map = {
|
||||
"zh": "zh-CN", "en": "en-US", "ko": "ko-KR", "ja": "ja-JP",
|
||||
"fr": "fr-FR", "de": "de-DE", "es": "es-ES", "it": "it-IT",
|
||||
"vi": "vi-VN", "id": "id-ID"
|
||||
}
|
||||
|
||||
def _get_translation(self, lang: str, key: str, **kwargs) -> str:
|
||||
target_lang = lang
|
||||
if target_lang not in TRANSLATIONS:
|
||||
base = target_lang.split("-")[0]
|
||||
target_lang = self.fallback_map.get(base, "en-US")
|
||||
|
||||
lang_dict = TRANSLATIONS.get(target_lang, TRANSLATIONS["en-US"])
|
||||
text = lang_dict.get(key, TRANSLATIONS["en-US"].get(key, key))
|
||||
return text.format(**kwargs) if kwargs else text
|
||||
|
||||
async def _get_user_context(self, __user__: Optional[dict], __event_call__: Optional[Callable] = None, __request__: Optional[Request] = None) -> dict:
|
||||
user_data = __user__ if isinstance(__user__, dict) else {}
|
||||
user_language = user_data.get("language", "en-US")
|
||||
if __event_call__:
|
||||
try:
|
||||
js = "try { return (document.documentElement.lang || localStorage.getItem('locale') || navigator.language || 'en-US'); } catch (e) { return 'en-US'; }"
|
||||
frontend_lang = await asyncio.wait_for(__event_call__({"type": "execute", "data": {"code": js}}), timeout=2.0)
|
||||
if frontend_lang: user_language = frontend_lang
|
||||
except: pass
|
||||
return {"user_language": user_language}
|
||||
|
||||
async def {{METHOD_NAME}}(self, body: dict, __user__: Optional[dict] = None, __event_emitter__=None, __event_call__=None, __request__: Optional[Request] = None) -> dict:
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
user_ctx = await self._get_user_context(__user__, __event_call__, __request__)
|
||||
msg = self._get_translation(user_ctx["user_language"], "status_starting")
|
||||
await __event_emitter__({"type": "status", "data": {"description": msg, "done": False}})
|
||||
|
||||
# Implement core logic here
|
||||
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
await __event_emitter__({"type": "status", "data": {"description": "Done", "done": True}})
|
||||
return body
|
||||
@@ -1,80 +0,0 @@
|
||||
"""
|
||||
title: {{TITLE}}
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||
funding_url: https://github.com/open-webui
|
||||
version: 0.1.0
|
||||
description: {{DESCRIPTION}}
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import json
|
||||
from typing import Optional, Dict, Any, List, Callable, Awaitable
|
||||
from pydantic import BaseModel, Field
|
||||
from fastapi import Request
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TRANSLATIONS = {
|
||||
"en-US": {"status_starting": "Starting {{TITLE}}..."},
|
||||
"zh-CN": {"status_starting": "正在启动 {{TITLE}}..."},
|
||||
"zh-HK": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"zh-TW": {"status_starting": "正在啟動 {{TITLE}}..."},
|
||||
"ko-KR": {"status_starting": "{{TITLE}} 시작 중..."},
|
||||
"ja-JP": {"status_starting": "{{TITLE}} を起動中..."},
|
||||
"fr-FR": {"status_starting": "Démarrage de {{TITLE}}..."},
|
||||
"de-DE": {"status_starting": "{{TITLE}} wird gestartet..."},
|
||||
"es-ES": {"status_starting": "Iniciando {{TITLE}}..."},
|
||||
"it-IT": {"status_starting": "Avvio di {{TITLE}}..."},
|
||||
"vi-VN": {"status_starting": "Đang khởi động {{TITLE}}..."},
|
||||
"id-ID": {"status_starting": "Memulai {{TITLE}}..."},
|
||||
}
|
||||
|
||||
class {{CLASS_NAME}}:
|
||||
class Valves(BaseModel):
|
||||
priority: int = Field(default=50, description="Priority level (lower = earlier).")
|
||||
show_status: bool = Field(default=True, description="Show status updates in UI.")
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.fallback_map = {
|
||||
"zh": "zh-CN", "en": "en-US", "ko": "ko-KR", "ja": "ja-JP",
|
||||
"fr": "fr-FR", "de": "de-DE", "es": "es-ES", "it": "it-IT",
|
||||
"vi": "vi-VN", "id": "id-ID"
|
||||
}
|
||||
|
||||
def _get_translation(self, lang: str, key: str, **kwargs) -> str:
|
||||
target_lang = lang
|
||||
if target_lang not in TRANSLATIONS:
|
||||
base = target_lang.split("-")[0]
|
||||
target_lang = self.fallback_map.get(base, "en-US")
|
||||
|
||||
lang_dict = TRANSLATIONS.get(target_lang, TRANSLATIONS["en-US"])
|
||||
text = lang_dict.get(key, TRANSLATIONS["en-US"].get(key, key))
|
||||
return text.format(**kwargs) if kwargs else text
|
||||
|
||||
async def _get_user_context(self, __user__: Optional[dict], __event_call__: Optional[Callable] = None, __request__: Optional[Request] = None) -> dict:
|
||||
user_data = __user__ if isinstance(__user__, dict) else {}
|
||||
user_language = user_data.get("language", "en-US")
|
||||
if __event_call__:
|
||||
try:
|
||||
js = "try { return (document.documentElement.lang || localStorage.getItem('locale') || navigator.language || 'en-US'); } catch (e) { return 'en-US'; }"
|
||||
frontend_lang = await asyncio.wait_for(__event_call__({"type": "execute", "data": {"code": js}}), timeout=2.0)
|
||||
if frontend_lang: user_language = frontend_lang
|
||||
except: pass
|
||||
return {"user_language": user_language}
|
||||
|
||||
async def {{METHOD_NAME}}(self, body: dict, __user__: Optional[dict] = None, __event_emitter__=None, __event_call__=None, __request__: Optional[Request] = None) -> dict:
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
user_ctx = await self._get_user_context(__user__, __event_call__, __request__)
|
||||
msg = self._get_translation(user_ctx["user_language"], "status_starting")
|
||||
await __event_emitter__({"type": "status", "data": {"description": msg, "done": False}})
|
||||
|
||||
# Implement core logic here
|
||||
|
||||
if self.valves.show_status and __event_emitter__:
|
||||
await __event_emitter__({"type": "status", "data": {"description": "Done", "done": True}})
|
||||
return body
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def scaffold(p_type, p_name, title, desc):
|
||||
target_dir = f"plugins/{p_type}/{p_name}"
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
|
||||
class_name = (
|
||||
"Action"
|
||||
if p_type == "actions"
|
||||
else (
|
||||
"Filter"
|
||||
if p_type == "filters"
|
||||
else "Tools" if p_type == "tools" else "Pipe"
|
||||
)
|
||||
)
|
||||
method_name = (
|
||||
"action"
|
||||
if p_type == "actions"
|
||||
else (
|
||||
"outlet"
|
||||
if p_type == "filters"
|
||||
else "execute" if p_type == "tools" else "pipe"
|
||||
)
|
||||
)
|
||||
|
||||
replacements = {
|
||||
"{{TITLE}}": title,
|
||||
"{{DESCRIPTION}}": desc,
|
||||
"{{CLASS_NAME}}": class_name,
|
||||
"{{METHOD_NAME}}": method_name,
|
||||
}
|
||||
|
||||
# Files to generate
|
||||
templates = [
|
||||
("assets/template.py.j2", f"{p_name}.py"),
|
||||
("assets/README_template.md", "README.md"),
|
||||
("assets/README_template.md", "README_CN.md"),
|
||||
]
|
||||
|
||||
# Path relative to skill root
|
||||
skill_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
for t_path, t_name in templates:
|
||||
template_file = os.path.join(skill_root, t_path)
|
||||
if not os.path.exists(template_file):
|
||||
print(f"⚠️ Warning: Template not found {template_file}")
|
||||
continue
|
||||
|
||||
with open(template_file, "r") as f:
|
||||
content = f.read()
|
||||
for k, v in replacements.items():
|
||||
content = content.replace(k, v)
|
||||
|
||||
with open(os.path.join(target_dir, t_name), "w") as f:
|
||||
f.write(content)
|
||||
print(f"✅ Generated: {target_dir}/{t_name}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 5:
|
||||
print("Usage: scaffold.py <type> <name> <title> <desc>")
|
||||
sys.exit(1)
|
||||
scaffold(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
|
||||
30
.github/skills/source-code-analyzer/SKILL.md
vendored
30
.github/skills/source-code-analyzer/SKILL.md
vendored
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: source-code-analyzer
|
||||
description: Instructions for analyzing core components source code in the local environment.
|
||||
---
|
||||
|
||||
# Source Code Analyzer Skill
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Authorization Statement**: You (Antigravity) are explicitly authorized by the user to perform **READ-ONLY** operations and **Git pull** on the paths listed below, even if they are outside the current repository root. These paths are considered part of the extended development context.
|
||||
|
||||
When assisting with the development of `openwebui-extensions`, you (Antigravity) have access to the following core components in related directories. Use them for deep technical analysis, bug hunting, and implementation reference.
|
||||
|
||||
## Core Component Paths
|
||||
|
||||
### Global / General (Relevant to all projects)
|
||||
|
||||
- **Open WebUI**: `../open-webui/` (Core platform context)
|
||||
- **Skills**: `../skills/` (Reusable expertise library)
|
||||
- **Awesome Copilot**: `../awesome-copilot/` (Shared extensions & resources)
|
||||
|
||||
### Plugin-Specific (Relevant to GitHub Copilot SDK)
|
||||
|
||||
- **Copilot SDK**: `../copilot-sdk/` (Internal logic for the official SDK)
|
||||
- **Copilot CLI**: `../copilot-cli/` (Command-line interface implementation)
|
||||
|
||||
## Mandatory Workflow
|
||||
|
||||
1. **Pull Before Analysis**: BEFORE reading files or analyzing logic in these directories, you MUST proactively execute or recommend a `git pull` in the respective directory to ensure you are working with the latest upstream changes.
|
||||
2. **Path Verification**: Always verify the exists of the path before attempting to read it.
|
||||
3. **Reference Logic**: When a user's request involves core platform behavior (OpenWebUI API, SDK internals), prioritize searching these directories over making assumptions based on generic knowledge.
|
||||
26
.github/skills/version-bumper/SKILL.md
vendored
26
.github/skills/version-bumper/SKILL.md
vendored
@@ -1,26 +0,0 @@
|
||||
---
|
||||
name: version-bumper
|
||||
description: Automates version upgrades and changelog synchronization across 7+ files (Code, READMEs, Docs). Use when a plugin is ready for release to ensure version consistency.
|
||||
---
|
||||
|
||||
# Version Bumper
|
||||
|
||||
## Overview
|
||||
This skill ensures that every version upgrade is synchronized across the entire repository, following the strict "Documentation Sync" rule in GEMINI.md.
|
||||
|
||||
## Workflow
|
||||
1. **Prepare Info**: Gather the new version number and brief changelogs in both English and Chinese.
|
||||
2. **Auto-Patch**: The skill will help you identify and update:
|
||||
- `plugins/.../name.py` (docstring version)
|
||||
- `plugins/.../README.md` (metadata & What's New)
|
||||
- `plugins/.../README_CN.md` (metadata & 最新更新)
|
||||
- `docs/plugins/...md` (mirrors)
|
||||
- `docs/plugins/index.md` (version badge)
|
||||
- `README.md` (updated date badge)
|
||||
3. **Verify**: Check the diffs to ensure no formatting was broken.
|
||||
|
||||
## Tool Integration
|
||||
Execute the bump script (draft):
|
||||
```bash
|
||||
python3 scripts/bump.py <version> "<message_en>" "<message_zh>"
|
||||
```
|
||||
70
.github/skills/version-bumper/scripts/bump.py
vendored
70
.github/skills/version-bumper/scripts/bump.py
vendored
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
def patch_file(file_path, old_pattern, new_content, is_regex=False):
|
||||
if not os.path.exists(file_path):
|
||||
print(f"Warning: File not found: {file_path}")
|
||||
return False
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
if is_regex:
|
||||
new_content_result = re.sub(old_pattern, new_content, content, flags=re.MULTILINE)
|
||||
else:
|
||||
new_content_result = content.replace(old_pattern, new_content)
|
||||
|
||||
if new_content_result != content:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content_result)
|
||||
print(f"✅ Patched: {file_path}")
|
||||
return True
|
||||
else:
|
||||
print(f"ℹ️ No change needed: {file_path}")
|
||||
return False
|
||||
|
||||
def bump_version(plugin_type, plugin_name, new_version, msg_en, msg_zh):
|
||||
print(f"🚀 Bumping {plugin_name} ({plugin_type}) to {new_version}...")
|
||||
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
today_badge = today.replace("-", "--")
|
||||
|
||||
# 1. Patch Plugin Python File
|
||||
py_file = f"plugins/{plugin_type}/{plugin_name}/{plugin_name}.py"
|
||||
patch_file(py_file, r"version: \d+\.\d+\.\d+", f"version: {new_version}", is_regex=True)
|
||||
|
||||
# 2. Patch Plugin READMEs
|
||||
readme_en = f"plugins/{plugin_type}/{plugin_name}/README.md"
|
||||
readme_zh = f"plugins/{plugin_type}/{plugin_name}/README_CN.md"
|
||||
|
||||
# Update version in metadata
|
||||
patch_file(readme_en, r"\*\*Version:\*\* \d+\.\d+\.\d+", f"**Version:** {new_version}", is_regex=True)
|
||||
patch_file(readme_zh, r"\*\*版本:\*\* \d+\.\d+\.\d+", f"**版本:** {new_version}", is_regex=True)
|
||||
|
||||
# Update What's New (Assuming standard headers)
|
||||
patch_file(readme_en, r"## 🔥 What's New in v.*?\n", f"## 🔥 What's New in v{new_version}\n\n* {msg_en}\n", is_regex=True)
|
||||
patch_file(readme_zh, r"## 🔥 最新更新 v.*?\n", f"## 🔥 最新更新 v{new_version}\n\n* {msg_zh}\n", is_regex=True)
|
||||
|
||||
# 3. Patch Docs Mirrors
|
||||
doc_en = f"docs/plugins/{plugin_type}/{plugin_name}.md"
|
||||
doc_zh = f"docs/plugins/{plugin_type}/{plugin_name}.zh.md"
|
||||
patch_file(doc_en, r"\*\*Version:\*\* \d+\.\d+\.\d+", f"**Version:** {new_version}", is_regex=True)
|
||||
patch_file(doc_zh, r"\*\*版本:\*\* \d+\.\d+\.\d+", f"**版本:** {new_version}", is_regex=True)
|
||||
|
||||
# 4. Patch Root READMEs (Updated Date Badge)
|
||||
patch_file("README.md", r"badge/202\d--\d\d--\d\d-gray", f"badge/{today_badge}-gray", is_regex=True)
|
||||
patch_file("README_CN.md", r"badge/202\d--\d\d--\d\d-gray", f"badge/{today_badge}-gray", is_regex=True)
|
||||
|
||||
print("\n✨ All synchronization tasks completed.")
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 6:
|
||||
print("Usage: bump.py <type> <name> <version> <msg_en> <msg_zh>")
|
||||
print("Example: bump.py filters markdown_normalizer 1.2.8 'Fix bug' '修复错误'")
|
||||
sys.exit(1)
|
||||
|
||||
bump_version(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5])
|
||||
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@@ -329,7 +329,8 @@ jobs:
|
||||
DETECTED_CHANGES: ${{ needs.check-changes.outputs.release_notes }}
|
||||
COMMITS: ${{ steps.commits.outputs.commits }}
|
||||
run: |
|
||||
> release_notes.md
|
||||
echo "# ${VERSION} Release" > release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
|
||||
if [ -n "$TITLE" ]; then
|
||||
echo "## $TITLE" >> release_notes.md
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -139,4 +139,3 @@ logs/
|
||||
|
||||
# OpenWebUI specific
|
||||
# Add any specific ignores for OpenWebUI plugins if needed
|
||||
.git-worktrees/
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"default": true,
|
||||
"MD013": false,
|
||||
"MD033": false,
|
||||
"MD030": false,
|
||||
"MD051": false
|
||||
}
|
||||
157
GEMINI.md
157
GEMINI.md
@@ -1,157 +0,0 @@
|
||||
# OpenWebUI Extensions — Gemini CLI Project Context
|
||||
|
||||
> This file is loaded automatically by Gemini CLI as project-level instructions.
|
||||
> Full engineering spec: `.github/copilot-instructions.md`
|
||||
|
||||
---
|
||||
|
||||
## Project Overview
|
||||
|
||||
**openwebui-extensions** is a collection of OpenWebUI plugins authored by Fu-Jie.
|
||||
|
||||
Repository: `https://github.com/Fu-Jie/openwebui-extensions`
|
||||
|
||||
Plugin types: `actions` / `filters` / `pipes` / `pipelines` / `tools`
|
||||
|
||||
---
|
||||
|
||||
## Non-Negotiable Rules
|
||||
|
||||
1. **No auto-commit.** Never run `git commit`, `git push`, or `gh pr create` unless the user says "发布" / "release" / "commit it". Default output = local file changes only.
|
||||
2. **No silent failures.** All errors must surface via `__event_emitter__` notification or backend `logging`.
|
||||
3. **No hardcoded model IDs.** Default to the current conversation model; let `Valves` override.
|
||||
4. **Chinese responses.** Reply in Simplified Chinese for all planning, explanations, and status summaries. English only for code, commit messages, and docstrings.
|
||||
|
||||
---
|
||||
|
||||
## Plugin File Contract
|
||||
|
||||
Every plugin MUST be a **single-file i18n** Python module:
|
||||
|
||||
```text
|
||||
plugins/{type}/{name}/{name}.py ← single source file, built-in i18n
|
||||
plugins/{type}/{name}/README.md ← English docs
|
||||
plugins/{type}/{name}/README_CN.md ← Chinese docs
|
||||
```
|
||||
|
||||
### Docstring (required fields)
|
||||
|
||||
```python
|
||||
"""
|
||||
title: Plugin Display Name
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||
funding_url: https://github.com/open-webui
|
||||
version: 0.1.0
|
||||
description: One-line description.
|
||||
"""
|
||||
```
|
||||
|
||||
### Required patterns
|
||||
|
||||
- `Valves(BaseModel)` with `UPPER_SNAKE_CASE` fields
|
||||
- `_get_user_context(__user__)` — never access `__user__` directly
|
||||
- `_get_chat_context(body, __metadata__)` — never infer IDs ad-hoc
|
||||
- `_emit_status(emitter, msg, done)` / `_emit_notification(emitter, content, type)`
|
||||
- Async I/O only — wrap sync calls with `asyncio.to_thread`
|
||||
- `logging` for backend logs — no bare `print()` in production
|
||||
|
||||
---
|
||||
|
||||
## Antigravity Development Rules
|
||||
|
||||
When the user invokes antigravity mode (high-speed iteration), enforce these safeguards automatically:
|
||||
|
||||
| Rule | Detail |
|
||||
|------|--------|
|
||||
| Small reversible edits | One logical change per file per operation |
|
||||
| Timeout guards | `asyncio.wait_for(..., timeout=2.0)` on all `__event_call__` JS executions |
|
||||
| Path sandbox | Verify every workspace path stays inside the repo root before read/write |
|
||||
| Source Sensing | Use `source-code-analyzer` skill for `../open-webui`, `../copilot-sdk` etc. `git pull` before analysis. |
|
||||
| External Auth | **AUTHORIZED** to read (RO) from specified external paths (open-webui, copilot-sdk, etc.) for analysis. |
|
||||
| Fallback chains | API upload → DB + local copy; never a single point of failure |
|
||||
| Progressive status | `status(done=False)` at start, `status(done=True)` on end, `notification(error)` on failure |
|
||||
| Validate before emit | Check `emitter is not None` before every `await emitter(...)` |
|
||||
|
||||
---
|
||||
|
||||
## File Creation & Delivery Protocol (3-Step)
|
||||
|
||||
1. `local write` — create artifact inside workspace scope
|
||||
2. `publish_file_from_workspace(filename='...')` — migrate to OpenWebUI storage (S3-compatible)
|
||||
3. Return `/api/v1/files/{id}/content` download link in Markdown
|
||||
|
||||
Set `skip_rag=true` metadata on generated downloadable artifacts.
|
||||
|
||||
---
|
||||
|
||||
## Copilot SDK Tool Definition (critical)
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
from copilot import define_tool
|
||||
|
||||
class MyToolParams(BaseModel):
|
||||
query: str = Field(..., description="Search query")
|
||||
|
||||
my_tool = define_tool(
|
||||
name="my_tool",
|
||||
description="...",
|
||||
params_type=MyToolParams, # REQUIRED — prevents empty schema hallucination
|
||||
)(async_impl_fn)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Streaming Output Format (OpenWebUI 0.8.x)
|
||||
|
||||
- Reasoning: `<think>\n...\n</think>\n` — close BEFORE normal content or tool cards
|
||||
- Tool cards: `<details type="tool_calls" id="..." name="..." arguments=""..."" result=""..."" done="true">\n<summary>Tool Executed</summary>\n</details>\n\n`
|
||||
- Escape ALL `"` inside `arguments`/`result` attributes as `"`
|
||||
- Status events via `__event_emitter__` — do NOT pollute the content stream with debug text
|
||||
|
||||
---
|
||||
|
||||
## Documentation Sync (when changing a plugin)
|
||||
|
||||
Must update ALL of these or the PR check fails:
|
||||
|
||||
1. `plugins/{type}/{name}/{name}.py` — version in docstring
|
||||
2. `plugins/{type}/{name}/README.md` — version, What's New
|
||||
3. `plugins/{type}/{name}/README_CN.md` — same
|
||||
4. `docs/plugins/{type}/{name}.md` — mirror README
|
||||
5. `docs/plugins/{type}/{name}.zh.md` — mirror README_CN
|
||||
6. `docs/plugins/{type}/index.md` — version badge
|
||||
7. `docs/plugins/{type}/index.zh.md` — version badge
|
||||
|
||||
---
|
||||
|
||||
## i18n & Language Standards
|
||||
|
||||
1. **Alignment**: Keep the number of supported languages in `TRANSLATIONS` consistent with major plugins (e.g., `smart-mind-map`).
|
||||
2. **Supported Languages**: en-US, zh-CN, zh-HK, zh-TW, ko-KR, ja-JP, fr-FR, de-DE, es-ES, it-IT, vi-VN, id-ID.
|
||||
3. **Fallback Map**: Must include variant redirects (e.g., `es-MX` -> `es-ES`, `fr-CA` -> `fr-FR`).
|
||||
4. **Tooltips**: All `description` fields in `Valves` must be **English only** to maintain clean UI.
|
||||
|
||||
---
|
||||
|
||||
## Commit Message Format
|
||||
|
||||
```text
|
||||
type(scope): brief English description
|
||||
|
||||
- Key change 1
|
||||
- Key change 2
|
||||
```
|
||||
|
||||
Types: `feat` / `fix` / `docs` / `refactor` / `chore`
|
||||
Scope: plugin folder name (e.g., `github-copilot-sdk`)
|
||||
|
||||
---
|
||||
|
||||
## Full Reference
|
||||
|
||||
`.github/copilot-instructions.md` — complete engineering specification (1000+ lines)
|
||||
`.agent/workflows/plugin-development.md` — step-by-step development workflow
|
||||
`.agent/rules/antigravity.md` — antigravity mode detailed rules
|
||||
`docs/development/copilot-engineering-plan.md` — design baseline
|
||||
18
README.md
18
README.md
@@ -24,18 +24,12 @@ A collection of enhancements, plugins, and prompts for [OpenWebUI](https://githu
|
||||
|
||||
| Rank | Plugin | Version | Downloads | Views | 📅 Updated |
|
||||
| :---: | :--- | :---: | :---: | :---: | :---: |
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) |  |  |  |  |
|
||||
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) |  |  |  |  |
|
||||
| 🥉 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) |  |  |  |  |
|
||||
| 4️⃣ | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) |  |  |  |  |
|
||||
| 5️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) |  |  |  |  |
|
||||
| 6️⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) |  |  |  |  |
|
||||
|
||||
### 🛠️ Actively Developed Projects
|
||||
|
||||
| Status | Plugin | Version | Downloads | Views | 📅 Updated |
|
||||
| :---: | :--- | :---: | :---: | :---: | :---: |
|
||||
| 🆕 | [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) |  |  |  |  |
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) |  |  |  |  |
|
||||
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) |  |  |  |  |
|
||||
| 🥉 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) |  |  |  |  |
|
||||
| 4️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) |  |  |  |  |
|
||||
| 5️⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) |  |  |  |  |
|
||||
| 6️⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) |  |  |  |  |
|
||||
|
||||
### 📈 Total Downloads Trend
|
||||
|
||||
|
||||
18
README_CN.md
18
README_CN.md
@@ -21,18 +21,12 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
|
||||
| 排名 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 |
|
||||
| :---: | :--- | :---: | :---: | :---: | :---: |
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) |  |  |  |  |
|
||||
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) |  |  |  |  |
|
||||
| 🥉 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) |  |  |  |  |
|
||||
| 4️⃣ | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) |  |  |  |  |
|
||||
| 5️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) |  |  |  |  |
|
||||
| 6️⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) |  |  |  |  |
|
||||
|
||||
### 🛠️ 积极开发的项目
|
||||
|
||||
| 状态 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 |
|
||||
| :---: | :--- | :---: | :---: | :---: | :---: |
|
||||
| 🆕 | [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) |  |  |  |  |
|
||||
| 🥇 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) |  |  |  |  |
|
||||
| 🥈 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) |  |  |  |  |
|
||||
| 🥉 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) |  |  |  |  |
|
||||
| 4️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) |  |  |  |  |
|
||||
| 5️⃣ | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) |  |  |  |  |
|
||||
| 6️⃣ | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) |  |  |  |  |
|
||||
|
||||
### 📈 总下载量累计趋势
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "downloads",
|
||||
"message": "5.6k",
|
||||
"message": "4.2k",
|
||||
"color": "blue",
|
||||
"namedLogo": "openwebui"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "followers",
|
||||
"message": "270",
|
||||
"message": "220",
|
||||
"color": "blue"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "plugins",
|
||||
"message": "23",
|
||||
"message": "22",
|
||||
"color": "green"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "points",
|
||||
"message": "285",
|
||||
"message": "271",
|
||||
"color": "orange"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "upvotes",
|
||||
"message": "241",
|
||||
"message": "231",
|
||||
"color": "brightgreen"
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"total_posts": 23,
|
||||
"total_downloads": 5629,
|
||||
"total_views": 61059,
|
||||
"total_upvotes": 241,
|
||||
"total_downvotes": 3,
|
||||
"total_saves": 321,
|
||||
"total_posts": 22,
|
||||
"total_downloads": 4161,
|
||||
"total_views": 45988,
|
||||
"total_upvotes": 231,
|
||||
"total_downvotes": 2,
|
||||
"total_saves": 274,
|
||||
"total_comments": 55,
|
||||
"by_type": {
|
||||
"action": 12,
|
||||
"post": 4,
|
||||
"pipe": 1,
|
||||
"post": 3,
|
||||
"filter": 4,
|
||||
"pipe": 1,
|
||||
"action": 12,
|
||||
"prompt": 1,
|
||||
"review": 1
|
||||
},
|
||||
@@ -19,16 +19,16 @@
|
||||
"title": "Smart Mind Map",
|
||||
"slug": "turn_any_text_into_beautiful_mind_maps_3094c59a",
|
||||
"type": "action",
|
||||
"version": "1.0.0",
|
||||
"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": 1207,
|
||||
"views": 10434,
|
||||
"downloads": 954,
|
||||
"views": 8395,
|
||||
"upvotes": 22,
|
||||
"saves": 59,
|
||||
"saves": 50,
|
||||
"comments": 13,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-02-22",
|
||||
"created_at": "2025-12-31",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a"
|
||||
},
|
||||
{
|
||||
@@ -38,31 +38,15 @@
|
||||
"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": 966,
|
||||
"views": 9501,
|
||||
"downloads": 710,
|
||||
"views": 6719,
|
||||
"upvotes": 24,
|
||||
"saves": 39,
|
||||
"saves": 34,
|
||||
"comments": 10,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-01-31",
|
||||
"url": "https://openwebui.com/posts/smart_infographic_ad6f0c7f"
|
||||
},
|
||||
{
|
||||
"title": "Markdown Normalizer",
|
||||
"slug": "markdown_normalizer_baaa8732",
|
||||
"type": "filter",
|
||||
"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": 513,
|
||||
"views": 6087,
|
||||
"upvotes": 17,
|
||||
"saves": 36,
|
||||
"comments": 5,
|
||||
"created_at": "2026-01-12",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/markdown_normalizer_baaa8732"
|
||||
},
|
||||
{
|
||||
"title": "Export to Word Enhanced",
|
||||
"slug": "export_to_word_enhanced_formatting_fca6a315",
|
||||
@@ -70,29 +54,29 @@
|
||||
"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": 511,
|
||||
"views": 4090,
|
||||
"upvotes": 15,
|
||||
"saves": 29,
|
||||
"downloads": 383,
|
||||
"views": 3029,
|
||||
"upvotes": 14,
|
||||
"saves": 26,
|
||||
"comments": 5,
|
||||
"created_at": "2026-01-03",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-02-07",
|
||||
"url": "https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315"
|
||||
},
|
||||
{
|
||||
"title": "Async Context Compression",
|
||||
"slug": "async_context_compression_b1655bc8",
|
||||
"type": "filter",
|
||||
"version": "1.3.0",
|
||||
"version": "1.2.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Reduces token consumption in long conversations while maintaining coherence through intelligent summarization and message compression.",
|
||||
"downloads": 486,
|
||||
"views": 4865,
|
||||
"upvotes": 15,
|
||||
"saves": 40,
|
||||
"downloads": 363,
|
||||
"views": 3759,
|
||||
"upvotes": 14,
|
||||
"saves": 34,
|
||||
"comments": 0,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-02-21",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/async_context_compression_b1655bc8"
|
||||
},
|
||||
{
|
||||
@@ -102,30 +86,30 @@
|
||||
"version": "0.3.7",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Extracts tables from chat messages and exports them to Excel (.xlsx) files with smart formatting.",
|
||||
"downloads": 445,
|
||||
"views": 2377,
|
||||
"upvotes": 9,
|
||||
"saves": 7,
|
||||
"downloads": 342,
|
||||
"views": 1675,
|
||||
"upvotes": 7,
|
||||
"saves": 6,
|
||||
"comments": 0,
|
||||
"created_at": "2025-05-30",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-02-10",
|
||||
"url": "https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d"
|
||||
},
|
||||
{
|
||||
"title": "AI Task Instruction Generator",
|
||||
"slug": "ai_task_instruction_generator_9bab8b37",
|
||||
"type": "prompt",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 381,
|
||||
"views": 4636,
|
||||
"upvotes": 9,
|
||||
"saves": 11,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-28",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37"
|
||||
"title": "Markdown Normalizer",
|
||||
"slug": "markdown_normalizer_baaa8732",
|
||||
"type": "filter",
|
||||
"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": 341,
|
||||
"views": 4716,
|
||||
"upvotes": 17,
|
||||
"saves": 30,
|
||||
"comments": 5,
|
||||
"created_at": "2026-01-12",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/markdown_normalizer_baaa8732"
|
||||
},
|
||||
{
|
||||
"title": "Flash Card",
|
||||
@@ -134,30 +118,30 @@
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Quickly generates beautiful flashcards from text, extracting key points and categories.",
|
||||
"downloads": 264,
|
||||
"views": 3924,
|
||||
"downloads": 226,
|
||||
"views": 3387,
|
||||
"upvotes": 13,
|
||||
"saves": 18,
|
||||
"saves": 14,
|
||||
"comments": 2,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/flash_card_65a2ea8f"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot Official SDK Pipe",
|
||||
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
|
||||
"type": "pipe",
|
||||
"version": "0.7.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.",
|
||||
"downloads": 205,
|
||||
"views": 3522,
|
||||
"upvotes": 14,
|
||||
"saves": 9,
|
||||
"comments": 6,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-02-22",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
"title": "AI Task Instruction Generator",
|
||||
"slug": "ai_task_instruction_generator_9bab8b37",
|
||||
"type": "prompt",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 202,
|
||||
"views": 2784,
|
||||
"upvotes": 9,
|
||||
"saves": 6,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-28",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37"
|
||||
},
|
||||
{
|
||||
"title": "Deep Dive",
|
||||
@@ -166,10 +150,10 @@
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "A comprehensive thinking lens that dives deep into any content - from context to logic, insights, and action paths.",
|
||||
"downloads": 185,
|
||||
"views": 1519,
|
||||
"downloads": 147,
|
||||
"views": 1250,
|
||||
"upvotes": 6,
|
||||
"saves": 13,
|
||||
"saves": 11,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-08",
|
||||
"updated_at": "2026-01-08",
|
||||
@@ -182,15 +166,31 @@
|
||||
"version": "0.4.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "将对话导出为 Word (.docx),支持 Mermaid 图表 (客户端渲染 SVG+PNG)、LaTeX 数学公式、真实超链接、增强表格格式、代码高亮和引用块。",
|
||||
"downloads": 145,
|
||||
"views": 2507,
|
||||
"upvotes": 14,
|
||||
"downloads": 128,
|
||||
"views": 2219,
|
||||
"upvotes": 13,
|
||||
"saves": 7,
|
||||
"comments": 4,
|
||||
"created_at": "2026-01-04",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-02-07",
|
||||
"url": "https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot Official SDK Pipe",
|
||||
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
|
||||
"type": "pipe",
|
||||
"version": "0.6.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, and frontend debug logging.",
|
||||
"downloads": 107,
|
||||
"views": 2412,
|
||||
"upvotes": 14,
|
||||
"saves": 9,
|
||||
"comments": 6,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-02-10",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
},
|
||||
{
|
||||
"title": "📂 Folder Memory – Auto-Evolving Project Context",
|
||||
"slug": "folder_memory_auto_evolving_project_context_4a9875b2",
|
||||
@@ -198,10 +198,10 @@
|
||||
"version": "0.1.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Automatically extracts project rules from conversations and injects them into the folder's system prompt.",
|
||||
"downloads": 92,
|
||||
"views": 1721,
|
||||
"upvotes": 7,
|
||||
"saves": 11,
|
||||
"downloads": 61,
|
||||
"views": 1318,
|
||||
"upvotes": 6,
|
||||
"saves": 8,
|
||||
"comments": 0,
|
||||
"created_at": "2026-01-20",
|
||||
"updated_at": "2026-01-20",
|
||||
@@ -214,13 +214,13 @@
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "基于 AntV Infographic 的智能信息图生成插件。支持多种专业模板,自动图标匹配,并提供 SVG/PNG 下载功能。",
|
||||
"downloads": 62,
|
||||
"views": 1235,
|
||||
"downloads": 58,
|
||||
"views": 1066,
|
||||
"upvotes": 10,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/智能信息图_e04a48ff"
|
||||
},
|
||||
{
|
||||
@@ -230,13 +230,13 @@
|
||||
"version": "0.9.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "智能分析文本内容,生成交互式思维导图,帮助用户结构化和可视化知识。",
|
||||
"downloads": 41,
|
||||
"views": 658,
|
||||
"downloads": 39,
|
||||
"views": 589,
|
||||
"upvotes": 6,
|
||||
"saves": 2,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-31",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b"
|
||||
},
|
||||
{
|
||||
@@ -246,31 +246,15 @@
|
||||
"version": "1.2.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "通过智能摘要和消息压缩,降低长对话的 token 消耗,同时保持对话连贯性。",
|
||||
"downloads": 36,
|
||||
"views": 748,
|
||||
"downloads": 33,
|
||||
"views": 669,
|
||||
"upvotes": 7,
|
||||
"saves": 5,
|
||||
"comments": 0,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/异步上下文压缩_5c0617cb"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot SDK Files Filter",
|
||||
"slug": "github_copilot_sdk_files_filter_403a62ee",
|
||||
"type": "filter",
|
||||
"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": 35,
|
||||
"views": 1907,
|
||||
"upvotes": 3,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
"created_at": "2026-02-09",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee"
|
||||
},
|
||||
{
|
||||
"title": "闪记卡 (Flash Card)",
|
||||
"slug": "闪记卡生成插件_4a31eac3",
|
||||
@@ -278,13 +262,13 @@
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "快速将文本提炼为精美的学习记忆卡片,支持核心要点提取与分类。",
|
||||
"downloads": 30,
|
||||
"views": 783,
|
||||
"downloads": 27,
|
||||
"views": 690,
|
||||
"upvotes": 8,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/闪记卡生成插件_4a31eac3"
|
||||
},
|
||||
{
|
||||
@@ -294,8 +278,8 @@
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "全方位的思维透镜 —— 从背景全景到逻辑脉络,从深度洞察到行动路径。",
|
||||
"downloads": 25,
|
||||
"views": 545,
|
||||
"downloads": 24,
|
||||
"views": 444,
|
||||
"upvotes": 5,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
@@ -304,20 +288,20 @@
|
||||
"url": "https://openwebui.com/posts/精读_99830b0f"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.7.0: Native Tool UI & Zero-Config CLI 🛠️",
|
||||
"slug": "github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131",
|
||||
"type": "post",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 24,
|
||||
"upvotes": 2,
|
||||
"title": "GitHub Copilot SDK Files Filter",
|
||||
"slug": "github_copilot_sdk_files_filter_403a62ee",
|
||||
"type": "filter",
|
||||
"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": 16,
|
||||
"views": 867,
|
||||
"upvotes": 3,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
"created_at": "2026-02-22",
|
||||
"updated_at": "2026-02-22",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131"
|
||||
"created_at": "2026-02-09",
|
||||
"updated_at": "2026-02-10",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks",
|
||||
@@ -327,9 +311,9 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 2108,
|
||||
"upvotes": 7,
|
||||
"saves": 3,
|
||||
"views": 296,
|
||||
"upvotes": 5,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
"created_at": "2026-02-10",
|
||||
"updated_at": "2026-02-10",
|
||||
@@ -343,12 +327,12 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1767,
|
||||
"views": 1526,
|
||||
"upvotes": 12,
|
||||
"saves": 19,
|
||||
"comments": 8,
|
||||
"created_at": "2026-01-25",
|
||||
"updated_at": "2026-01-28",
|
||||
"updated_at": "2026-01-29",
|
||||
"url": "https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e"
|
||||
},
|
||||
{
|
||||
@@ -359,7 +343,7 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 222,
|
||||
"views": 161,
|
||||
"upvotes": 2,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
@@ -375,7 +359,7 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1475,
|
||||
"views": 1421,
|
||||
"upvotes": 14,
|
||||
"saves": 10,
|
||||
"comments": 2,
|
||||
@@ -389,11 +373,11 @@
|
||||
"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": 270,
|
||||
"following": 5,
|
||||
"total_points": 285,
|
||||
"post_points": 238,
|
||||
"comment_points": 47,
|
||||
"contributions": 51
|
||||
"followers": 220,
|
||||
"following": 4,
|
||||
"total_points": 271,
|
||||
"post_points": 229,
|
||||
"comment_points": 42,
|
||||
"contributions": 48
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
> *Blue: Downloads | Purple: Views (Real-time dynamic)*
|
||||
|
||||
### 📂 Content Distribution
|
||||

|
||||

|
||||
|
||||
|
||||
## 📈 Overview
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
## 📂 By Type
|
||||
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
|
||||
@@ -36,26 +36,25 @@
|
||||
|
||||
| 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 |  |  |  |  |  | 2026-02-22 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 3 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | filter |  |  |  |  |  | 2026-02-13 |
|
||||
| 4 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 5 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter |  |  |  |  |  | 2026-02-21 |
|
||||
| 6 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 7 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | prompt |  |  |  |  |  | 2026-01-28 |
|
||||
| 8 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 9 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe |  |  |  |  |  | 2026-02-22 |
|
||||
| 10 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 11 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action |  |  |  |  |  | 2026-01-31 |
|
||||
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action |  |  |  |  |  | 2026-02-07 |
|
||||
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter |  |  |  |  |  | 2026-01-29 |
|
||||
| 5 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action |  |  |  |  |  | 2026-02-10 |
|
||||
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | filter |  |  |  |  |  | 2026-01-29 |
|
||||
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | prompt |  |  |  |  |  | 2026-01-28 |
|
||||
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 10 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action |  |  |  |  |  | 2026-02-07 |
|
||||
| 11 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe |  |  |  |  |  | 2026-02-10 |
|
||||
| 12 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter |  |  |  |  |  | 2026-01-20 |
|
||||
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 16 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-02-13 |
|
||||
| 17 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 18 | [精读](https://openwebui.com/posts/精读_99830b0f) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 19 | [🚀 GitHub Copilot SDK Pipe v0.7.0: Native Tool UI & Zero-Config CLI 🛠️](https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131) | post |  |  |  |  |  | 2026-02-22 |
|
||||
| 20 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post |  |  |  |  |  | 2026-02-10 |
|
||||
| 21 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | post |  |  |  |  |  | 2026-01-28 |
|
||||
| 22 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 23 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post |  |  |  |  |  | 2026-01-10 |
|
||||
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-02-10 |
|
||||
| 19 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post |  |  |  |  |  | 2026-02-10 |
|
||||
| 20 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | post |  |  |  |  |  | 2026-01-29 |
|
||||
| 21 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 22 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post |  |  |  |  |  | 2026-01-10 |
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
> *蓝色: 总下载量 | 紫色: 总浏览量 (实时动态生成)*
|
||||
|
||||
### 📂 内容分类占比 (Distribution)
|
||||

|
||||

|
||||
|
||||
|
||||
## 📈 总览
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
## 📂 按类型分类
|
||||
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
|
||||
@@ -36,26 +36,25 @@
|
||||
|
||||
| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |
|
||||
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action |  |  |  |  |  | 2026-02-22 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 3 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | filter |  |  |  |  |  | 2026-02-13 |
|
||||
| 4 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 5 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter |  |  |  |  |  | 2026-02-21 |
|
||||
| 6 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 7 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | prompt |  |  |  |  |  | 2026-01-28 |
|
||||
| 8 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 9 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe |  |  |  |  |  | 2026-02-22 |
|
||||
| 10 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 11 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action |  |  |  |  |  | 2026-01-31 |
|
||||
| 3 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action |  |  |  |  |  | 2026-02-07 |
|
||||
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter |  |  |  |  |  | 2026-01-29 |
|
||||
| 5 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action |  |  |  |  |  | 2026-02-10 |
|
||||
| 6 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | filter |  |  |  |  |  | 2026-01-29 |
|
||||
| 7 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 8 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | prompt |  |  |  |  |  | 2026-01-28 |
|
||||
| 9 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 10 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action |  |  |  |  |  | 2026-02-07 |
|
||||
| 11 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe |  |  |  |  |  | 2026-02-10 |
|
||||
| 12 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter |  |  |  |  |  | 2026-01-20 |
|
||||
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 16 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-02-13 |
|
||||
| 17 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 18 | [精读](https://openwebui.com/posts/精读_99830b0f) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 19 | [🚀 GitHub Copilot SDK Pipe v0.7.0: Native Tool UI & Zero-Config CLI 🛠️](https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131) | post |  |  |  |  |  | 2026-02-22 |
|
||||
| 20 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post |  |  |  |  |  | 2026-02-10 |
|
||||
| 21 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | post |  |  |  |  |  | 2026-01-28 |
|
||||
| 22 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 23 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post |  |  |  |  |  | 2026-01-10 |
|
||||
| 13 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 14 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 15 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 16 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action |  |  |  |  |  | 2026-01-29 |
|
||||
| 17 | [精读](https://openwebui.com/posts/精读_99830b0f) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 18 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-02-10 |
|
||||
| 19 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | post |  |  |  |  |  | 2026-02-10 |
|
||||
| 20 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | post |  |  |  |  |  | 2026-01-29 |
|
||||
| 21 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 22 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post |  |  |  |  |  | 2026-01-10 |
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
# Copilot Engineering Configuration Plan
|
||||
|
||||
> This document defines production-grade engineering configuration for plugin development with GitHub Copilot, Gemini CLI, and antigravity development mode.
|
||||
|
||||
---
|
||||
|
||||
## 1. Goals
|
||||
|
||||
- Standardize plugin engineering workflow for AI-assisted development.
|
||||
- Support dual assistant stack:
|
||||
- GitHub Copilot (primary in-editor agent)
|
||||
- Gemini CLI (secondary external execution/research lane)
|
||||
- Introduce antigravity development mode for safer, reversible, high-velocity iteration.
|
||||
|
||||
---
|
||||
|
||||
## 2. Scope
|
||||
|
||||
This plan applies to:
|
||||
|
||||
- Plugin development (`actions`, `filters`, `pipes`, `pipelines`, `tools`)
|
||||
- Documentation synchronization
|
||||
- File generation/delivery workflow in OpenWebUI
|
||||
- Streaming/tool-call rendering compatibility
|
||||
|
||||
---
|
||||
|
||||
## 3. Engineering Configuration (Copilot-centered)
|
||||
|
||||
### 3.1 Source of truth
|
||||
|
||||
- Primary standard file: `.github/copilot-instructions.md`
|
||||
- Agent workflow file: `.agent/workflows/plugin-development.md`
|
||||
- Runtime guidance docs:
|
||||
- `docs/development/plugin-guide.md`
|
||||
- `docs/development/plugin-guide.zh.md`
|
||||
|
||||
### 3.2 Required development contract
|
||||
|
||||
- Single-file i18n plugin source.
|
||||
- Bilingual README (`README.md` + `README_CN.md`).
|
||||
- Safe context extraction (`_get_user_context`, `_get_chat_context`).
|
||||
- Structured event handling (`status`, `notification`, `execute`).
|
||||
- No silent failures; logging + user-visible status.
|
||||
|
||||
### 3.3 Tool definition contract (Copilot SDK)
|
||||
|
||||
- Define tool params explicitly with `pydantic.BaseModel`.
|
||||
- Use `params_type` in tool registration.
|
||||
- Preserve defaults by avoiding forced null overrides.
|
||||
- Keep tool names normalized and deterministic.
|
||||
|
||||
---
|
||||
|
||||
## 4. Gemini CLI Compatibility Profile
|
||||
|
||||
Gemini CLI is treated as a parallel capability channel, not a replacement.
|
||||
|
||||
### 4.1 Usage boundary
|
||||
|
||||
- Use for:
|
||||
- rapid drafts
|
||||
- secondary reasoning
|
||||
- cross-checking migration plans
|
||||
- Do not bypass repository conventions or plugin contracts.
|
||||
|
||||
### 4.2 Output normalization
|
||||
|
||||
All Gemini CLI outputs must be normalized before merge:
|
||||
|
||||
- Match repository style and naming rules.
|
||||
- Preserve OpenWebUI plugin signatures and context methods.
|
||||
- Convert speculative outputs into explicit, testable implementation points.
|
||||
|
||||
### 4.3 Conflict policy
|
||||
|
||||
When Copilot and Gemini suggestions differ:
|
||||
|
||||
1. Prefer repository standard compliance.
|
||||
2. Prefer safer fallback behavior.
|
||||
3. Prefer lower integration risk.
|
||||
|
||||
---
|
||||
|
||||
## 5. Antigravity Development Mode
|
||||
|
||||
Antigravity mode means high-speed delivery with strict reversibility.
|
||||
|
||||
### 5.1 Core principles
|
||||
|
||||
- Small, isolated edits
|
||||
- Deterministic interfaces
|
||||
- Multi-level fallback paths
|
||||
- Roll-forward and rollback both feasible
|
||||
|
||||
### 5.2 Required patterns
|
||||
|
||||
- Timeout guards on frontend execution calls.
|
||||
- Path sandbox validation for all workspace file operations.
|
||||
- Dual-channel upload fallback (API first, local/DB fallback).
|
||||
- Progressive status reporting for long-running tasks.
|
||||
|
||||
---
|
||||
|
||||
## 6. File Creation & Delivery Standard
|
||||
|
||||
### 6.1 Create files in controlled workspace
|
||||
|
||||
- Write artifacts in current workspace scope.
|
||||
- Never use paths outside workspace boundary for deliverables.
|
||||
|
||||
### 6.2 Publish protocol
|
||||
|
||||
Use 3-step delivery:
|
||||
|
||||
1. local write
|
||||
2. publish from workspace
|
||||
3. present `/api/v1/files/{id}/content` link
|
||||
|
||||
### 6.3 Metadata policy
|
||||
|
||||
- Set `skip_rag=true` for generated downloadable artifacts where applicable.
|
||||
- Keep filename generation deterministic (`chat_title -> markdown_title -> user+date`).
|
||||
|
||||
---
|
||||
|
||||
## 7. Plugin Development Norms for Multi-Agent Stack
|
||||
|
||||
- Compatible with GitHub Copilot and Gemini CLI under same coding contract.
|
||||
- Keep streaming compatible with OpenWebUI native blocks (`<think>`, `<details type="tool_calls">`).
|
||||
- Escape tool card attributes safely (`"`) for parser stability.
|
||||
- Preserve async non-blocking behavior.
|
||||
|
||||
---
|
||||
|
||||
## 8. Documentation Sync Rule
|
||||
|
||||
Any meaningful plugin engineering change must sync:
|
||||
|
||||
1. plugin code
|
||||
2. plugin bilingual README
|
||||
3. docs plugin detail pages (EN/ZH)
|
||||
4. docs plugin indexes (EN/ZH)
|
||||
5. root README update badge/date when release is prepared
|
||||
|
||||
---
|
||||
|
||||
## 9. Acceptance Checklist
|
||||
|
||||
- Copilot config and workflow references are valid.
|
||||
- Gemini CLI outputs can be merged without violating conventions.
|
||||
- Antigravity safety mechanisms are present.
|
||||
- File creation and publication flow is reproducible.
|
||||
- Streaming/tool-card output format remains OpenWebUI-compatible.
|
||||
@@ -1,149 +0,0 @@
|
||||
# Copilot 工程化配置设计
|
||||
|
||||
> 本文档定义面向插件开发的工程化配置方案:支持 GitHub Copilot、兼容 Gemini CLI,并引入“反重力开发”模式。
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标
|
||||
|
||||
- 建立统一、可落地的 AI 协同开发标准。
|
||||
- 支持双通道助手体系:
|
||||
- GitHub Copilot(编辑器内主通道)
|
||||
- Gemini CLI(外部补充通道)
|
||||
- 在高迭代速度下保障可回滚、可审计、可发布。
|
||||
|
||||
---
|
||||
|
||||
## 2. 适用范围
|
||||
|
||||
适用于以下类型开发:
|
||||
|
||||
- 插件代码(`actions` / `filters` / `pipes` / `pipelines` / `tools`)
|
||||
- 文档同步与发布准备
|
||||
- OpenWebUI 文件创建与交付流程
|
||||
- 流式输出与工具卡片兼容性
|
||||
|
||||
---
|
||||
|
||||
## 3. Copilot 工程化主配置
|
||||
|
||||
### 3.1 规范来源
|
||||
|
||||
- 主规范:`.github/copilot-instructions.md`
|
||||
- 工作流:`.agent/workflows/plugin-development.md`
|
||||
- 运行时开发指南:
|
||||
- `docs/development/plugin-guide.md`
|
||||
- `docs/development/plugin-guide.zh.md`
|
||||
|
||||
### 3.2 强制开发契约
|
||||
|
||||
- 单文件 i18n 插件源码。
|
||||
- README 双语(`README.md` + `README_CN.md`)。
|
||||
- 上下文统一入口(`_get_user_context`、`_get_chat_context`)。
|
||||
- 事件标准化(`status`、`notification`、`execute`)。
|
||||
- 禁止静默失败(用户可见状态 + 后端日志)。
|
||||
|
||||
### 3.3 Copilot SDK 工具契约
|
||||
|
||||
- 参数必须 `pydantic.BaseModel` 显式定义。
|
||||
- 工具注册必须声明 `params_type`。
|
||||
- 保留默认值语义,避免把未传参数强制覆盖为 `null`。
|
||||
- 工具名需可预测、可规范化。
|
||||
|
||||
---
|
||||
|
||||
## 4. Gemini CLI 兼容配置
|
||||
|
||||
Gemini CLI 作为补充通道,而不是替代主规范。
|
||||
|
||||
### 4.1 使用边界
|
||||
|
||||
- 适合:草案生成、方案对照、迁移校验。
|
||||
- 不得绕过仓库规范与插件契约。
|
||||
|
||||
### 4.2 输出归一化
|
||||
|
||||
Gemini CLI 输出合入前必须完成:
|
||||
|
||||
- 命名与结构对齐仓库约束。
|
||||
- 保留 OpenWebUI 插件标准签名与上下文方法。
|
||||
- 将“建议性文字”转换为可执行、可验证实现点。
|
||||
|
||||
### 4.3 冲突决策
|
||||
|
||||
Copilot 与 Gemini 建议冲突时按优先级处理:
|
||||
|
||||
1. 规范一致性优先
|
||||
2. 安全回退优先
|
||||
3. 低集成风险优先
|
||||
|
||||
---
|
||||
|
||||
## 5. 反重力开发(Antigravity)模式
|
||||
|
||||
反重力开发 = 高速迭代 + 强回退能力。
|
||||
|
||||
### 5.1 核心原则
|
||||
|
||||
- 小步、隔离、可逆变更
|
||||
- 接口稳定、行为可预测
|
||||
- 多级回退链路
|
||||
- 支持前滚与回滚
|
||||
|
||||
### 5.2 强制模式
|
||||
|
||||
- 前端执行调用必须设置超时保护。
|
||||
- 工作区文件操作必须做路径沙箱校验。
|
||||
- 上传链路采用 API 优先 + 本地/DB 回退。
|
||||
- 长任务必须分阶段状态反馈。
|
||||
|
||||
---
|
||||
|
||||
## 6. 文件创建与交付标准
|
||||
|
||||
### 6.1 创建范围
|
||||
|
||||
- 交付文件仅在受控 workspace 内创建。
|
||||
- 禁止将交付产物写到 workspace 边界之外。
|
||||
|
||||
### 6.2 三步交付协议
|
||||
|
||||
1. 本地写入
|
||||
2. 从 workspace 发布
|
||||
3. 返回并展示 `/api/v1/files/{id}/content`
|
||||
|
||||
### 6.3 元数据策略
|
||||
|
||||
- 需要绕过检索时为产物标记 `skip_rag=true`。
|
||||
- 文件名采用确定性策略:`chat_title -> markdown_title -> user+date`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 多助手并行下的插件开发规范
|
||||
|
||||
- 在统一契约下同时兼容 GitHub Copilot 与 Gemini CLI。
|
||||
- 流式输出保持 OpenWebUI 原生兼容(`<think>`、`<details type="tool_calls">`)。
|
||||
- 工具卡片属性严格转义(`"`)保证解析稳定。
|
||||
- 全链路保持异步非阻塞。
|
||||
|
||||
---
|
||||
|
||||
## 8. 文档同步规则
|
||||
|
||||
插件工程化变更发生时,至少同步:
|
||||
|
||||
1. 插件代码
|
||||
2. 插件双语 README
|
||||
3. docs 详情页(EN/ZH)
|
||||
4. docs 索引页(EN/ZH)
|
||||
5. 发布准备阶段同步根 README 日期徽章
|
||||
|
||||
---
|
||||
|
||||
## 9. 验收清单
|
||||
|
||||
- Copilot 配置与工作流引用有效。
|
||||
- Gemini CLI 输出可无缝合入且不破坏规范。
|
||||
- 反重力安全机制完整。
|
||||
- 文件创建/发布流程可复现。
|
||||
- 流式与工具卡片格式保持 OpenWebUI 兼容。
|
||||
@@ -1,126 +0,0 @@
|
||||
# GitHub Copilot SDK Tool Filtering Logic Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
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.
|
||||
|
||||
## Priority Hierarchy
|
||||
|
||||
Filtering is applied top-to-bottom. A higher layer can fully block a lower one:
|
||||
|
||||
| Priority | Layer | Controls |
|
||||
|---|---|---|
|
||||
| 1 (Highest) | **Plugin Valve toggles** | `ENABLE_OPENWEBUI_TOOLS`, `ENABLE_MCP_SERVER`, `ENABLE_OPENAPI_SERVER` — category master switches |
|
||||
| 2 | **Admin backend server toggle** | Per-server `config.enable` in OpenWebUI Connections panel — blocks specific servers |
|
||||
| 3 (Lowest) | **User Chat menu selection** | `tool_ids` from the chat UI — selects which enabled items to use |
|
||||
|
||||
---
|
||||
|
||||
## Core Decision Logic (Flowchart)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[New message arrives] --> V{Plugin Valve enabled\nfor this category?}
|
||||
V -- No --> VX[Drop all tools in this category]
|
||||
V -- Yes --> B{Admin backend:\nconfig.enable = True?}
|
||||
B -- No --> C[Skip this server]
|
||||
B -- Yes --> F{Built-in or Custom/Server tool?}
|
||||
|
||||
F -- Built-in --> G{Any builtin: IDs\nselected in Chat?}
|
||||
G -- Yes --> H[Enable ONLY the mapped categories\nunselected categories set to False]
|
||||
G -- No --> I[Enable default 4 categories:\nweb_search, image_generation,\ncode_interpreter, memory]
|
||||
|
||||
F -- Custom / Server --> J{Any custom IDs\nselected in Chat?}
|
||||
J -- Yes --> K[Load ONLY the selected IDs]
|
||||
J -- No --> L[Load ALL admin-enabled custom tools]
|
||||
|
||||
H & I & K & L --> M[Always inject: publish_file_from_workspace]
|
||||
M --> N[Start / Resume Copilot SDK Session]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scenario Reference Table
|
||||
|
||||
| User selects in Chat | Custom tools loaded | Built-in tools loaded |
|
||||
|---|---|---|
|
||||
| Nothing | All admin-enabled | Default 4 (search, image, code, memory) |
|
||||
| Only `builtin:xxx` | All admin-enabled (unaffected) | Only selected categories |
|
||||
| Only custom/server IDs | Only selected IDs | Default 4 |
|
||||
| Both builtin and custom | Only selected custom IDs | Only selected builtin categories |
|
||||
|
||||
---
|
||||
|
||||
## Technical Implementation Details
|
||||
|
||||
### 1. Real-time Admin Sync (No Caching)
|
||||
|
||||
Every request re-reads `TOOL_SERVER_CONNECTIONS.value` live. There is **no in-memory cache** for server state. As a result:
|
||||
|
||||
- Enable a server in the admin panel → it appears on the **next message**.
|
||||
- Disable a server → it is dropped on the **next message**.
|
||||
|
||||
```python
|
||||
# Read live on every request — no cache
|
||||
if hasattr(TOOL_SERVER_CONNECTIONS, "value"):
|
||||
raw_connections = TOOL_SERVER_CONNECTIONS.value
|
||||
|
||||
for server in connections:
|
||||
is_enabled = config.get("enable", False) # checked per-server, per-request
|
||||
if not is_enabled:
|
||||
continue # skipped immediately — hard block
|
||||
```
|
||||
|
||||
### 2. Built-in Tool Category Mapping
|
||||
|
||||
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:
|
||||
|
||||
```python
|
||||
if builtin_selected:
|
||||
# Strict mode: set every category explicitly
|
||||
for cat in all_builtin_categories: # all 9
|
||||
is_enabled = cat in enabled_categories # only selected ones are True
|
||||
builtin_tools_meta[cat] = is_enabled # unselected are explicitly False
|
||||
else:
|
||||
# Default mode: only the 4 core categories
|
||||
default_builtin_categories = [
|
||||
"web_search", "image_generation", "code_interpreter", "memory"
|
||||
]
|
||||
for cat in all_builtin_categories:
|
||||
builtin_tools_meta[cat] = cat in default_builtin_categories
|
||||
features.update(req_features) # merge backend feature flags
|
||||
```
|
||||
|
||||
### 3. Custom Tool "Select-All" Fallback
|
||||
|
||||
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:
|
||||
|
||||
```python
|
||||
# custom_selected contains only non-builtin: IDs
|
||||
if custom_selected:
|
||||
# Whitelist active: keep only what the user picked
|
||||
tool_ids = [tid for tid in available_ids if tid in custom_selected]
|
||||
else:
|
||||
# No custom selection: load everything enabled in backend
|
||||
tool_ids = available_ids
|
||||
```
|
||||
|
||||
The same rule applies to MCP servers in `_parse_mcp_servers`.
|
||||
|
||||
### 4. Admin Backend Strict Validation
|
||||
|
||||
Applied uniformly to both OpenAPI and MCP servers, handling both dict and Pydantic object shapes:
|
||||
|
||||
```python
|
||||
is_enabled = False
|
||||
config = server.get("config", {}) if isinstance(server, dict) else getattr(server, "config", {})
|
||||
is_enabled = config.get("enable", False) if isinstance(config, dict) else getattr(config, "enable", False)
|
||||
|
||||
if not is_enabled:
|
||||
continue # hard skip — no user or valve setting can override this
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **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.
|
||||
- **Persistent Tool**: `publish_file_from_workspace` is always injected after all filtering — it is required for the file delivery workflow regardless of any toggle.
|
||||
@@ -1,206 +0,0 @@
|
||||
# GitHub Copilot SDK 工具过滤逻辑开发文档
|
||||
|
||||
## 核心需求
|
||||
|
||||
**管理员在后台修改工具服务的启用状态后,用户发送下一条消息时立即生效,无需重启服务或刷新缓存。**
|
||||
|
||||
过滤逻辑同时兼顾两个目标:管理员管控权、用户自主选择权。内置工具则完全独立,仅由模型配置决定。
|
||||
|
||||
---
|
||||
|
||||
## 工具分类说明
|
||||
|
||||
本文档涉及两类完全独立的工具,权限控制机制不同:
|
||||
|
||||
| 工具类型 | 说明 | 权限控制来源 |
|
||||
|---|---|---|
|
||||
| **内置工具(Builtin Tools)** | OpenWebUI 原生能力:时间、知识库、记忆、联网搜索、图像生成、代码解释器等 | 仅由模型配置 `meta.builtinTools` 决定,**与 Chat 前端选择无关** |
|
||||
| **OpenWebUI Tools** | 用户安装的 Python 工具插件 | 插件 Valve + Chat 工具选择(tool_ids) |
|
||||
| **工具服务器(OpenAPI / MCP)** | 外部 OpenAPI Server、MCP Server | 插件 Valve + 管理员 `config.enable` + `function_name_filter_list` + Chat 工具选择(tool_ids) |
|
||||
|
||||
---
|
||||
|
||||
## 内置工具权限控制(模型配置驱动,与前端无关)
|
||||
|
||||
内置工具**完全由模型配置决定**,Chat 界面的工具选择对其没有任何影响。
|
||||
|
||||
### 模型 `meta.builtinTools` 字段
|
||||
|
||||
在模型(自定义模型或基础模型)的 `meta` 字段中有一个可选的 `builtinTools` 对象:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"capabilities": { "builtin_tools": true },
|
||||
"builtinTools": {
|
||||
"time": false,
|
||||
"memory": true,
|
||||
"chats": true,
|
||||
"notes": true,
|
||||
"knowledge": true,
|
||||
"channels": true,
|
||||
"web_search": true,
|
||||
"image_generation": true,
|
||||
"code_interpreter": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**判定规则(源码 `utils/tools.py`):**
|
||||
|
||||
```python
|
||||
def is_builtin_tool_enabled(category: str) -> bool:
|
||||
builtin_tools = model.get("info", {}).get("meta", {}).get("builtinTools", {})
|
||||
return builtin_tools.get(category, True) # 缺省时默认 True
|
||||
```
|
||||
|
||||
- `builtinTools` 字段**不存在** → 所有内置工具类别默认全部开启
|
||||
- `builtinTools` 字段**存在** → 仅值为 `true` 的类别开启,其余关闭
|
||||
|
||||
---
|
||||
|
||||
## OpenWebUI Tools 和工具服务器的优先级层级
|
||||
|
||||
这两类工具的过滤从上到下依次执行,**受 Chat 前端选择影响**:
|
||||
|
||||
| 优先级 | 层级 | 控制范围 |
|
||||
|---|---|---|
|
||||
| 1(最高) | **插件 Valve 开关** | `ENABLE_OPENWEBUI_TOOLS` / `ENABLE_MCP_SERVER` / `ENABLE_OPENAPI_SERVER` — 类别总开关 |
|
||||
| 2 | **管理员后端服务器开关** | OpenWebUI 连接面板中每个服务器的 `config.enable` — 控制具体服务器是否启用 |
|
||||
| 3 | **管理员函数名过滤列表** | 工具服务器 `config.function_name_filter_list` — 限制该服务器对外暴露的函数列表(逗号分隔) |
|
||||
| 4(最低) | **用户 Chat 工具选择** | Chat 界面的 `tool_ids` — 在已启用范围内进一步筛选:未选则全选,有选则仅选中的 |
|
||||
|
||||
### 管理员函数名过滤列表说明
|
||||
|
||||
OpenWebUI 后台的工具服务器连接配置中支持设置 `function_name_filter_list` 字段(逗号分隔的函数名),用于限制该服务器对外暴露的函数。源码逻辑:
|
||||
|
||||
```python
|
||||
# utils/tools.py
|
||||
function_name_filter_list = tool_server_connection.get("config", {}).get("function_name_filter_list", "")
|
||||
if isinstance(function_name_filter_list, str):
|
||||
function_name_filter_list = function_name_filter_list.split(",")
|
||||
|
||||
for spec in specs:
|
||||
function_name = spec["name"]
|
||||
if function_name_filter_list:
|
||||
if not is_string_allowed(function_name, function_name_filter_list):
|
||||
continue # 不在列表中的函数被跳过
|
||||
```
|
||||
|
||||
- 列表**为空** → 该服务器所有函数均可用
|
||||
- 列表**有值** → 只有名称匹配的函数会被暴露给用户
|
||||
|
||||
---
|
||||
|
||||
## 核心判定流程
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[新消息到来] --> BT[内置工具:读模型 meta.builtinTools]
|
||||
BT --> BT2{builtinTools 字段存在?}
|
||||
BT2 -- 否 --> BT3[开启全部内置工具]
|
||||
BT2 -- 是 --> BT4[仅开启值为 true 的类别]
|
||||
|
||||
A --> CT[OpenWebUI Tools / 工具服务器]
|
||||
CT --> V{插件 Valve 开启了该类别?}
|
||||
V -- 否 --> VX[丢弃该类别]
|
||||
V -- 是 --> B{后端 config.enable = True?}
|
||||
B -- 否 --> C[跳过该服务器]
|
||||
B -- 是 --> FL{function_name_filter_list 有值?}
|
||||
FL -- 是 --> FL2[过滤掉不在列表中的函数]
|
||||
FL -- 否 --> J
|
||||
FL2 --> J{Chat tool_ids 有勾选?}
|
||||
J -- 有 --> K[仅加载勾选的 ID]
|
||||
J -- 无 --> L[加载所有后台已启用工具]
|
||||
|
||||
BT3 & BT4 & K & L --> M[始终注入: publish_file_from_workspace]
|
||||
M --> N[启动/恢复 Copilot SDK 会话]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 场景速查表
|
||||
|
||||
### 内置工具(与前端选择无关)
|
||||
|
||||
| 模型配置 | 结果 |
|
||||
|---|---|
|
||||
| `meta.builtinTools` 字段不存在 | 全部内置工具类别开启 |
|
||||
| `meta.builtinTools` 字段存在 | 仅 `true` 的类别开启 |
|
||||
|
||||
### OpenWebUI Tools / 工具服务器(受 Chat 前端选择影响)
|
||||
|
||||
| Chat 工具选择情况 | 加载逻辑 |
|
||||
|---|---|
|
||||
| 什么都没选 | 加载所有 Valve 开启且后台已启用的工具(Python Tools + OpenAPI + MCP) |
|
||||
| 选了部分 tool_ids | 仅加载勾选的 ID(必须同时通过 Valve 和 config.enable 校验) |
|
||||
|
||||
---
|
||||
|
||||
## 代码实现详述
|
||||
|
||||
### 1. 管理员后台变更即时同步
|
||||
|
||||
OpenWebUI 通过 `PersistentConfig` + Redis 保证多 worker 之间的配置同步,插件直接读取 `request.app.state.config.TOOL_SERVER_CONNECTIONS` 即可获取最新值:
|
||||
|
||||
- 后台**启用**一个服务器 → **下一条消息**就出现。
|
||||
- 后台**禁用**一个服务器 → **下一条消息**就消失。
|
||||
|
||||
```python
|
||||
# 直接读取 OpenWebUI 的配置对象,有 Redis 时每次读取都会同步最新值
|
||||
connections = request.app.state.config.TOOL_SERVER_CONNECTIONS # list
|
||||
|
||||
for server in connections:
|
||||
config = server.get("config", {})
|
||||
is_enabled = config.get("enable", False) # 每条服务器、每次请求都检查
|
||||
if not is_enabled:
|
||||
continue # 立即跳过,硬性拦截
|
||||
```
|
||||
|
||||
### 2. 内置工具直接透传给 OpenWebUI 处理
|
||||
|
||||
插件调用 OpenWebUI 的 `get_builtin_tools(request, extra_params, model)` 时,将 `model` 原样传入即可。OpenWebUI 内部会自动读取 `model.info.meta.builtinTools` 来决定哪些内置工具生效:
|
||||
|
||||
```python
|
||||
# OpenWebUI 源码 utils/tools.py 中的判定逻辑(开发参考,非插件代码)
|
||||
def is_builtin_tool_enabled(category: str) -> bool:
|
||||
builtin_tools = model.get("info", {}).get("meta", {}).get("builtinTools", {})
|
||||
return builtin_tools.get(category, True) # 缺省值 True:未配置时全部开启
|
||||
```
|
||||
|
||||
插件无需自行维护内置工具分类映射,也不需要向 `builtinTools` 注入任何值。
|
||||
|
||||
### 3. 自定义工具"默认全选"(白名单仅在显式勾选时激活)
|
||||
|
||||
白名单**只有在用户明确勾选了 tool_ids 时才启用**。未勾选任何工具时,加载所有后台已启用工具:
|
||||
|
||||
```python
|
||||
# tool_ids 来自 Chat 请求体
|
||||
if tool_ids:
|
||||
# 白名单模式:严格只保留勾选项
|
||||
available_ids = [tid for tid in available_ids if tid in tool_ids]
|
||||
else:
|
||||
# 无勾选:加载所有后台已启用工具(免配置可用)
|
||||
pass # available_ids 保持不变
|
||||
```
|
||||
|
||||
MCP 服务器的 `_parse_mcp_servers` 遵循同样规则。
|
||||
|
||||
### 4. 后端状态硬校验(OpenAPI 和 MCP 统一处理)
|
||||
|
||||
```python
|
||||
is_enabled = False
|
||||
config = server.get("config", {}) if isinstance(server, dict) else getattr(server, "config", {})
|
||||
is_enabled = config.get("enable", False) if isinstance(config, dict) else getattr(config, "enable", False)
|
||||
|
||||
if not is_enabled:
|
||||
continue # 硬性跳过,任何用户或 Valve 设置都无法绕过
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
- **SDK 内部工具**:向会话传 `available_tools = None`,保证 `read_file`、`shell` 等 SDK 原生能力不被自定义工具列表意外屏蔽。
|
||||
- **始终注入的工具**:`publish_file_from_workspace` 在所有过滤完成后硬性追加,是文件交付工作流的必要依赖,不受任何开关影响。
|
||||
@@ -24,14 +24,6 @@ Learn how to develop plugins and contribute to OpenWebUI Extensions.
|
||||
|
||||
[:octicons-arrow-right-24: Read the Guide](documentation-guide.md)
|
||||
|
||||
- :material-robot:{ .lg .middle } **Copilot Engineering Plan**
|
||||
|
||||
---
|
||||
|
||||
Engineering configuration for GitHub Copilot + Gemini CLI + antigravity development mode.
|
||||
|
||||
[:octicons-arrow-right-24: Read the Plan](copilot-engineering-plan.md)
|
||||
|
||||
- :material-github:{ .lg .middle } **Contributing**
|
||||
|
||||
---
|
||||
@@ -172,6 +164,5 @@ user_language = __user__.get("language", "en-US")
|
||||
## Resources
|
||||
|
||||
- [Full Development Guide](plugin-guide.md)
|
||||
- [Copilot Engineering Plan](copilot-engineering-plan.md)
|
||||
- [Plugin Examples](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins)
|
||||
- [OpenWebUI Documentation](https://docs.openwebui.com/)
|
||||
|
||||
@@ -24,14 +24,6 @@
|
||||
|
||||
[:octicons-arrow-right-24: 阅读指南](documentation-guide.md)
|
||||
|
||||
- :material-robot:{ .lg .middle } **Copilot 工程化配置**
|
||||
|
||||
---
|
||||
|
||||
面向 GitHub Copilot + Gemini CLI + 反重力开发模式的工程化设计文档。
|
||||
|
||||
[:octicons-arrow-right-24: 阅读文档](copilot-engineering-plan.md)
|
||||
|
||||
- :material-github:{ .lg .middle } **贡献指南**
|
||||
|
||||
---
|
||||
@@ -172,6 +164,5 @@ user_language = __user__.get("language", "en-US")
|
||||
## 资源
|
||||
|
||||
- [完整开发指南](plugin-guide.md)
|
||||
- [Copilot 工程化配置](copilot-engineering-plan.md)
|
||||
- [插件示例](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins)
|
||||
- [OpenWebUI 文档](https://docs.openwebui.com/)
|
||||
|
||||
@@ -7,13 +7,11 @@
|
||||
## 📚 Table of Contents
|
||||
|
||||
1. [Quick Start](#1-quick-start)
|
||||
2. [Project Structure & Naming](#2-project-structure--naming)
|
||||
3. [Core Concepts & SDK Details](#3-core-concepts--sdk-details)
|
||||
4. [Deep Dive into Plugin Types](#4-deep-dive-into-plugin-types)
|
||||
5. [Advanced Development Patterns](#5-advanced-development-patterns)
|
||||
6. [Best Practices & Design Principles](#6-best-practices--design-principles)
|
||||
7. [Workflow & Process](#7-workflow--process)
|
||||
8. [Troubleshooting](#8-troubleshooting)
|
||||
2. [Core Concepts & SDK Details](#2-core-concepts-sdk-details)
|
||||
3. [Deep Dive into Plugin Types](#3-deep-dive-into-plugin-types)
|
||||
4. [Advanced Development Patterns](#4-advanced-development-patterns)
|
||||
5. [Best Practices & Design Principles](#5-best-practices-design-principles)
|
||||
6. [Troubleshooting](#6-troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
@@ -66,39 +64,9 @@ class Action:
|
||||
|
||||
---
|
||||
|
||||
## 2. Project Structure & Naming
|
||||
## 2. Core Concepts & SDK Details
|
||||
|
||||
### 2.1 Language & Code Requirements
|
||||
|
||||
- **Single Code File**: `plugins/{type}/{name}/{name}.py`. Never create separate source files for different languages.
|
||||
- **Built-in i18n**: Must dynamically switch UI, prompts, and logs based on user language.
|
||||
- **Documentation**: Must include both `README.md` (English) and `README_CN.md` (Chinese).
|
||||
|
||||
### 2.2 Docstring Standard
|
||||
|
||||
Each plugin file must start with a standardized docstring:
|
||||
|
||||
```python
|
||||
"""
|
||||
title: Plugin Name
|
||||
author: Fu-Jie
|
||||
author_url: https://github.com/Fu-Jie/openwebui-extensions
|
||||
funding_url: https://github.com/open-webui
|
||||
version: 0.1.0
|
||||
icon_url: data:image/svg+xml;base64,<base64-encoded-svg>
|
||||
requirements: dependency1==1.0.0, dependency2>=2.0.0
|
||||
description: Brief description of plugin functionality.
|
||||
"""
|
||||
```
|
||||
|
||||
- **icon_url**: Required for Action plugins. Must be Base64 encoded SVG from [Lucide Icons](https://lucide.dev/icons/).
|
||||
- **requirements**: Only list dependencies not installed in the OpenWebUI environment.
|
||||
|
||||
---
|
||||
|
||||
## 3. Core Concepts & SDK Details
|
||||
|
||||
### 3.1 ⚠️ Important: Sync vs Async
|
||||
### 2.1 ⚠️ Important: Sync vs Async
|
||||
|
||||
OpenWebUI plugins run within an `asyncio` event loop.
|
||||
|
||||
@@ -107,7 +75,7 @@ OpenWebUI plugins run within an `asyncio` event loop.
|
||||
- **Pitfall**: Calling synchronous methods directly (e.g., `time.sleep`, `requests.get`) will freeze the entire server
|
||||
- **Solution**: Wrap synchronous calls using `await asyncio.to_thread(sync_func, ...)`
|
||||
|
||||
### 3.2 Core Parameters
|
||||
### 2.2 Core Parameters
|
||||
|
||||
All plugin methods (`inlet`, `outlet`, `pipe`, `action`) support injecting the following special parameters:
|
||||
|
||||
@@ -120,43 +88,30 @@ All plugin methods (`inlet`, `outlet`, `pipe`, `action`) support injecting the f
|
||||
| `__event_emitter__` | `func` | **One-way Notification**. Used to send Toast notifications or status bar updates |
|
||||
| `__event_call__` | `func` | **Two-way Interaction**. Used to execute JS code, show confirmation dialogs, or input boxes |
|
||||
|
||||
### 3.3 Configuration System (Valves)
|
||||
### 2.3 Configuration System (Valves)
|
||||
|
||||
Use Pydantic BaseModel to define configurable parameters. All Valves fields must use **UPPER_SNAKE_CASE**.
|
||||
- **`Valves`**: Global admin configuration
|
||||
- **`UserValves`**: User-level configuration (higher priority, overrides global)
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class Action:
|
||||
class Filter:
|
||||
class Valves(BaseModel):
|
||||
SHOW_STATUS: bool = Field(default=True, description="Whether to show operation status updates.")
|
||||
# ...
|
||||
API_KEY: str = Field(default="", description="Global API Key")
|
||||
|
||||
class UserValves(BaseModel):
|
||||
API_KEY: str = Field(default="", description="User Private API Key")
|
||||
|
||||
def inlet(self, body, __user__):
|
||||
# Prioritize user's Key
|
||||
user_valves = __user__.get("valves", self.UserValves())
|
||||
api_key = user_valves.API_KEY or self.valves.API_KEY
|
||||
```
|
||||
|
||||
### 3.4 Context Access
|
||||
|
||||
All plugins **must** use `_get_user_context` and `_get_chat_context` methods to safely extract information, rather than accessing `__user__` or `body` directly.
|
||||
|
||||
### 3.5 Event Emission & Logging
|
||||
|
||||
- **Event Emission**: Implement helper methods `_emit_status` and `_emit_notification`.
|
||||
- **Frontend Console Debugging**: Highly recommended for real-time data flow viewing. Use `_emit_debug_log` to print structured debug logs in the browser console.
|
||||
- **Server-side Logging**: Use Python's standard `logging` module. Do not use `print()`.
|
||||
|
||||
### 3.6 Database & File Storage
|
||||
|
||||
- **Database**: Re-use Open WebUI's internal database connection (`open_webui.internal.db`).
|
||||
- **File Storage**: Implement multi-level fallback mechanisms (DB -> S3 -> Local -> URL -> API) to ensure compatibility across all storage configurations.
|
||||
|
||||
### 3.7 Internationalization (i18n)
|
||||
|
||||
Define a `TRANSLATIONS` dictionary and use a robust language detection mechanism (Multi-level Fallback: JS localStorage -> HTTP Accept-Language -> User Profile -> en-US).
|
||||
|
||||
---
|
||||
|
||||
## 4. Deep Dive into Plugin Types
|
||||
## 3. Deep Dive into Plugin Types
|
||||
|
||||
### 4.1 Action
|
||||
### 3.1 Action
|
||||
|
||||
**Role**: Adds buttons below messages that trigger upon user click.
|
||||
|
||||
@@ -181,7 +136,7 @@ async def action(self, body, __event_call__):
|
||||
await __event_call__({"type": "execute", "data": {"code": js}})
|
||||
```
|
||||
|
||||
### 4.2 Filter
|
||||
### 3.2 Filter
|
||||
|
||||
**Role**: Middleware that intercepts and modifies requests/responses.
|
||||
|
||||
@@ -202,7 +157,7 @@ async def inlet(self, body, __metadata__):
|
||||
return body
|
||||
```
|
||||
|
||||
### 4.3 Pipe
|
||||
### 3.3 Pipe
|
||||
|
||||
**Role**: Custom Model/Agent.
|
||||
|
||||
@@ -227,27 +182,18 @@ class Pipe:
|
||||
return r.iter_lines()
|
||||
```
|
||||
|
||||
### 4.4 Copilot SDK Tool Definition Standards
|
||||
|
||||
When developing custom tools for GitHub Copilot SDK, you **must** define a Pydantic `BaseModel` for parameters and explicitly reference it using `params_type` in `define_tool`.
|
||||
|
||||
### 4.5 Copilot SDK Streaming & Tool Card Standards
|
||||
|
||||
- **Reasoning Streaming**: Must use native `<think>` tags and ensure proper closure (`\n</think>\n`) before outputting main content or tool calls.
|
||||
- **Native Tool Calls Block**: Output strictly formatted HTML `<details type="tool_calls"...>` blocks. Ensure all double quotes in attributes are escaped as `"`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Advanced Development Patterns
|
||||
## 4. Advanced Development Patterns
|
||||
|
||||
### 5.1 Pipe & Filter Collaboration
|
||||
### 4.1 Pipe & Filter Collaboration
|
||||
|
||||
Use `__request__.app.state` to share data between plugins:
|
||||
|
||||
- **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
- **Filter (Outlet)**: Read `search_results` and format them as citation links
|
||||
|
||||
### 5.2 Async Background Tasks
|
||||
### 4.2 Async Background Tasks
|
||||
|
||||
Execute time-consuming operations without blocking the user response:
|
||||
|
||||
@@ -263,7 +209,7 @@ async def background_job(self, chat_id):
|
||||
pass
|
||||
```
|
||||
|
||||
### 5.3 Calling Built-in LLM
|
||||
### 4.3 Calling Built-in LLM
|
||||
|
||||
```python
|
||||
from open_webui.utils.chat import generate_chat_completion
|
||||
@@ -289,13 +235,13 @@ llm_response = await generate_chat_completion(
|
||||
)
|
||||
```
|
||||
|
||||
### 5.4 JS Render to Markdown (Data URL Embedding)
|
||||
### 4.4 JS Render to Markdown (Data URL Embedding)
|
||||
|
||||
For scenarios requiring complex frontend rendering (e.g., AntV charts, Mermaid diagrams) but wanting **persistent pure Markdown output**, use the Data URL embedding pattern:
|
||||
|
||||
#### Workflow
|
||||
|
||||
```text
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 1. Python Action │
|
||||
│ ├── Analyze message content │
|
||||
@@ -313,28 +259,116 @@ For scenarios requiring complex frontend rendering (e.g., AntV charts, Mermaid d
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5.5 Agent File Delivery Standards (3-Step Delivery Protocol)
|
||||
#### Python Side (Send JS for Execution)
|
||||
|
||||
1. **Write Local**: Create files in the current execution directory (`.`).
|
||||
2. **Publish**: Call `publish_file_from_workspace(filename='name.ext')`.
|
||||
3. **Display Link**: Present the returned `download_url` as a Markdown link.
|
||||
```python
|
||||
async def action(self, body, __event_call__, __metadata__, ...):
|
||||
chat_id = self._extract_chat_id(body, __metadata__)
|
||||
message_id = self._extract_message_id(body, __metadata__)
|
||||
|
||||
# Generate JS code
|
||||
js_code = self._generate_js_code(
|
||||
chat_id=chat_id,
|
||||
message_id=message_id,
|
||||
data=processed_data,
|
||||
)
|
||||
|
||||
# Execute JS
|
||||
if __event_call__:
|
||||
await __event_call__({
|
||||
"type": "execute",
|
||||
"data": {"code": js_code}
|
||||
})
|
||||
```
|
||||
|
||||
#### JavaScript Side (Render and Write-back)
|
||||
|
||||
```javascript
|
||||
(async function() {
|
||||
// 1. Load visualization library
|
||||
if (typeof VisualizationLib === 'undefined') {
|
||||
await new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdn.example.com/lib.min.js';
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Create offscreen container
|
||||
const container = document.createElement('div');
|
||||
container.style.cssText = 'position:absolute;left:-9999px;';
|
||||
document.body.appendChild(container);
|
||||
|
||||
// 3. Render visualization
|
||||
const instance = new VisualizationLib({ container });
|
||||
instance.render(data);
|
||||
|
||||
// 4. Export to Data URL
|
||||
const dataUrl = await instance.toDataURL({ type: 'svg', embedResources: true });
|
||||
|
||||
// 5. Cleanup
|
||||
instance.destroy();
|
||||
document.body.removeChild(container);
|
||||
|
||||
// 6. Generate Markdown image
|
||||
const markdownImage = ``;
|
||||
|
||||
// 7. Update message via API
|
||||
const token = localStorage.getItem("token");
|
||||
await fetch(`/api/v1/chats/${chatId}/messages/${messageId}/event`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${token}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: "chat:message",
|
||||
data: { content: originalContent + "\n\n" + markdownImage }
|
||||
})
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
#### Benefits
|
||||
|
||||
- **Pure Markdown Output**: Standard Markdown image syntax, no HTML code blocks
|
||||
- **Self-Contained**: Images embedded as Base64 Data URL, no external dependencies
|
||||
- **Persistent**: Via API write-back, images remain after page reload
|
||||
- **Cross-Platform**: Works on any client supporting Markdown images
|
||||
|
||||
#### HTML Injection vs JS Render to Markdown
|
||||
|
||||
| Feature | HTML Injection | JS Render + Markdown |
|
||||
|---------|----------------|----------------------|
|
||||
| Output Format | HTML code block | Markdown image |
|
||||
| Interactivity | ✅ Buttons, animations | ❌ Static image |
|
||||
| External Deps | Requires JS libraries | None (self-contained) |
|
||||
| Persistence | Depends on browser | ✅ Permanent |
|
||||
| File Export | Needs special handling | ✅ Direct export |
|
||||
| Use Case | Interactive content | Infographics, chart snapshots |
|
||||
|
||||
#### Reference Implementations
|
||||
|
||||
- `plugins/actions/infographic/infographic.py` - Production-ready implementation using AntV + Data URL
|
||||
|
||||
---
|
||||
|
||||
## 6. Best Practices & Design Principles
|
||||
## 5. Best Practices & Design Principles
|
||||
|
||||
### 6.1 Naming & Positioning
|
||||
### 5.1 Naming & Positioning
|
||||
|
||||
- **Short & Punchy**: e.g., "FlashCard", "DeepRead". Avoid generic terms like "Text Analysis Assistant"
|
||||
- **Complementary**: Don't reinvent the wheel; clarify what specific problem your plugin solves
|
||||
|
||||
### 6.2 User Experience (UX)
|
||||
### 5.2 User Experience (UX)
|
||||
|
||||
- **Timely Feedback**: Send a `notification` ("Generating...") before time-consuming operations
|
||||
- **Visual Appeal**: When Action outputs HTML, use modern CSS (rounded corners, shadows, gradients)
|
||||
- **Smart Guidance**: If text is too short, prompt the user: "Suggest entering more content for better results"
|
||||
|
||||
### 6.3 Error Handling
|
||||
### 5.3 Error Handling
|
||||
|
||||
!!! danger "Never fail silently"
|
||||
Always catch exceptions and inform the user via `__event_emitter__`.
|
||||
@@ -350,39 +384,9 @@ except Exception as e:
|
||||
})
|
||||
```
|
||||
|
||||
### 6.4 Long-running Task Notifications
|
||||
|
||||
If a foreground task is expected to take more than 3 seconds, implement a user notification mechanism (e.g., sending a notification every 5 seconds).
|
||||
|
||||
---
|
||||
|
||||
## 7. Workflow & Process
|
||||
|
||||
### 7.1 Source-derived Knowledge (from `plugins/`)
|
||||
|
||||
- **Input/context safety**: normalize multimodal text extraction, use `_get_user_context` / `_get_chat_context`, and protect frontend language detection with timeout guards.
|
||||
- **Long task UX**: emit immediate `status/notification`, then staged progress updates; keep full exception detail in backend logs.
|
||||
- **HTML merge strategy**: use stable wrapper markers (`OPENWEBUI_PLUGIN_OUTPUT`) and support both overwrite and merge modes.
|
||||
- **Theme consistency**: detect parent/system theme and apply theme-aware rendering/export styles for iframe-based outputs.
|
||||
- **Render-export-persist loop**: offscreen render (SVG/PNG) -> upload `/api/v1/files/` -> event update + persistence update to avoid refresh loss.
|
||||
- **DOCX production path**: `TITLE_SOURCE` fallback naming, reasoning-block stripping, native Word math (`latex2mathml + mathml2omml`), and citation/reference anchoring.
|
||||
- **File retrieval fallback chain**: DB inline -> S3 direct -> local path variants -> public URL -> internal API -> raw fields, with max-byte guards on each stage.
|
||||
- **Filter singleton discipline**: do not store request-scoped mutable state on `self`; compute from request context each run.
|
||||
- **Async compression pattern**: `inlet` summary injection + `outlet` background summary generation, with model-threshold override and system-message protection.
|
||||
- **Workspace/tool hardening**: explicit `params_type` schemas, strict path-boundary validation, and publish flow returning `/api/v1/files/{id}/content` with `skip_rag=true` metadata.
|
||||
- **MoE refinement pipeline**: detect aggregation prompts, parse segmented responses, and rewrite to synthesis-oriented master prompt with optional reroute model.
|
||||
|
||||
### 7.2 Copilot Engineering Configuration
|
||||
|
||||
- For repository-wide AI-assisted engineering setup (GitHub Copilot + Gemini CLI + antigravity mode), follow `docs/development/copilot-engineering-plan.md`.
|
||||
- This plan defines the shared contract for tool parameter schema/routing, file creation/publish protocol, rollback-safe delivery patterns, and streaming/tool-card compatibility.
|
||||
|
||||
- **Consistency Maintenance**: Any addition, modification, or removal of a plugin must simultaneously update the plugin code, READMEs, project docs, doc indexes, and the root README.
|
||||
- **Release Workflow**: Pushing to `main` triggers automatic release. Ensure version numbers are updated and follow SemVer. Use Conventional Commits.
|
||||
|
||||
---
|
||||
|
||||
## 8. Troubleshooting
|
||||
## 6. Troubleshooting
|
||||
|
||||
??? question "HTML not showing?"
|
||||
Ensure it's wrapped in a ` ```html ... ``` ` code block.
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
|
||||
## 📚 目录
|
||||
|
||||
1. [插件开发快速入门](#1-quick-start)
|
||||
2. [核心概念与 SDK 详解](#2-core-concepts-sdk-details)
|
||||
3. [插件类型深度解析](#3-plugin-types)
|
||||
* [Action (动作)](#31-action)
|
||||
* [Filter (过滤器)](#32-filter)
|
||||
* [Pipe (管道)](#33-pipe)
|
||||
4. [高级开发模式](#4-advanced-patterns)
|
||||
5. [最佳实践与设计原则](#5-best-practices)
|
||||
6. [仓库规范(openwebui-extensions)](#6-repo-standards)
|
||||
7. [故障排查](#7-troubleshooting)
|
||||
1. [插件开发快速入门](#1-quick-start)
|
||||
2. [核心概念与 SDK 详解](#2-core-concepts-sdk-details)
|
||||
3. [插件类型深度解析](#3-plugin-types)
|
||||
* [Action (动作)](#31-action)
|
||||
* [Filter (过滤器)](#32-filter)
|
||||
* [Pipe (管道)](#33-pipe)
|
||||
4. [高级开发模式](#4-advanced-patterns)
|
||||
5. [最佳实践与设计原则](#5-best-practices)
|
||||
6. [故障排查](#6-troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
@@ -22,10 +21,9 @@
|
||||
### 1.1 什么是 OpenWebUI 插件?
|
||||
|
||||
OpenWebUI 插件(官方称为 "Functions")是扩展平台功能的主要方式。它们运行在后端 Python 环境中,允许你:
|
||||
|
||||
* 🔌 **集成新模型**:通过 Pipe 接入 Claude、Gemini 或自定义 RAG。
|
||||
* 🎨 **增强交互**:通过 Action 在消息旁添加按钮(如"导出"、"生成图表")。
|
||||
* 🔧 **干预流程**:通过 Filter 在请求前后修改数据(如注入上下文、敏感词过滤)。
|
||||
* 🔌 **集成新模型**:通过 Pipe 接入 Claude、Gemini 或自定义 RAG。
|
||||
* 🎨 **增强交互**:通过 Action 在消息旁添加按钮(如"导出"、"生成图表")。
|
||||
* 🔧 **干预流程**:通过 Filter 在请求前后修改数据(如注入上下文、敏感词过滤)。
|
||||
|
||||
### 1.2 你的第一个插件 (Hello World)
|
||||
|
||||
@@ -71,10 +69,9 @@ class Action:
|
||||
### 2.1 ⚠️ 重要:同步与异步
|
||||
|
||||
OpenWebUI 插件运行在 `asyncio` 事件循环中。
|
||||
|
||||
* **原则**:所有 I/O 操作(数据库、文件、网络)必须非阻塞。
|
||||
* **陷阱**:直接调用同步方法(如 `time.sleep`, `requests.get`)会卡死整个服务器。
|
||||
* **解决**:使用 `await asyncio.to_thread(sync_func, ...)` 包装同步调用。
|
||||
* **原则**:所有 I/O 操作(数据库、文件、网络)必须非阻塞。
|
||||
* **陷阱**:直接调用同步方法(如 `time.sleep`, `requests.get`)会卡死整个服务器。
|
||||
* **解决**:使用 `await asyncio.to_thread(sync_func, ...)` 包装同步调用。
|
||||
|
||||
### 2.2 核心参数详解
|
||||
|
||||
@@ -91,8 +88,8 @@ OpenWebUI 插件运行在 `asyncio` 事件循环中。
|
||||
|
||||
### 2.3 配置系统 (Valves)
|
||||
|
||||
* **`Valves`**: 管理员全局配置。
|
||||
* **`UserValves`**: 用户级配置(优先级更高,可覆盖全局)。
|
||||
* **`Valves`**: 管理员全局配置。
|
||||
* **`UserValves`**: 用户级配置(优先级更高,可覆盖全局)。
|
||||
|
||||
```python
|
||||
class Filter:
|
||||
@@ -116,7 +113,7 @@ class Filter:
|
||||
|
||||
**定位**:在消息下方添加按钮,用户点击触发。
|
||||
|
||||
#### 高级用法:前端执行 JavaScript (文件下载示例)
|
||||
**高级用法:前端执行 JavaScript (文件下载示例)**
|
||||
|
||||
```python
|
||||
import base64
|
||||
@@ -141,11 +138,11 @@ async def action(self, body, __event_call__):
|
||||
|
||||
**定位**:中间件,拦截并修改请求/响应。
|
||||
|
||||
* **`inlet`**: 请求前。用于注入上下文、修改模型参数。
|
||||
* **`outlet`**: 响应后。用于格式化输出、保存日志。
|
||||
* **`stream`**: 流式处理中。用于实时敏感词过滤。
|
||||
* **`inlet`**: 请求前。用于注入上下文、修改模型参数。
|
||||
* **`outlet`**: 响应后。用于格式化输出、保存日志。
|
||||
* **`stream`**: 流式处理中。用于实时敏感词过滤。
|
||||
|
||||
#### 示例:注入环境变量
|
||||
**示例:注入环境变量**
|
||||
|
||||
```python
|
||||
async def inlet(self, body, __metadata__):
|
||||
@@ -162,7 +159,7 @@ async def inlet(self, body, __metadata__):
|
||||
|
||||
**定位**:自定义模型/代理。
|
||||
|
||||
#### 示例:简单的 OpenAI 代理
|
||||
**示例:简单的 OpenAI 代理**
|
||||
|
||||
```python
|
||||
import requests
|
||||
@@ -183,14 +180,11 @@ class Pipe:
|
||||
## 4. 高级开发模式 {: #4-advanced-patterns }
|
||||
|
||||
### 4.1 Pipe 与 Filter 协同
|
||||
|
||||
利用 `__request__.app.state` 在不同插件间共享数据。
|
||||
|
||||
* **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
* **Filter (Outlet)**: 读取 `search_results` 并将其格式化为引用链接附加到回复末尾。
|
||||
* **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
* **Filter (Outlet)**: 读取 `search_results` 并将其格式化为引用链接附加到回复末尾。
|
||||
|
||||
### 4.2 异步后台任务
|
||||
|
||||
不阻塞用户响应,在后台执行耗时操作(如生成总结、存库)。
|
||||
|
||||
```python
|
||||
@@ -211,7 +205,7 @@ async def background_job(self, chat_id):
|
||||
|
||||
#### 工作流程
|
||||
|
||||
```text
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 1. Python Action │
|
||||
│ ├── 分析消息内容 │
|
||||
@@ -303,10 +297,10 @@ async def action(self, body, __event_call__, __metadata__, ...):
|
||||
|
||||
#### 优势
|
||||
|
||||
* **纯 Markdown 输出**:结果是标准的 Markdown 图片语法,无需 HTML 代码块
|
||||
* **自包含**:图片以 Base64 Data URL 嵌入,无外部依赖
|
||||
* **持久化**:通过 API 回写,消息重新加载后图片仍然存在
|
||||
* **跨平台**:任何支持 Markdown 图片的客户端都能显示
|
||||
- **纯 Markdown 输出**:结果是标准的 Markdown 图片语法,无需 HTML 代码块
|
||||
- **自包含**:图片以 Base64 Data URL 嵌入,无外部依赖
|
||||
- **持久化**:通过 API 回写,消息重新加载后图片仍然存在
|
||||
- **跨平台**:任何支持 Markdown 图片的客户端都能显示
|
||||
|
||||
#### HTML 注入 vs JS 渲染嵌入 Markdown
|
||||
|
||||
@@ -321,23 +315,20 @@ async def action(self, body, __event_call__, __metadata__, ...):
|
||||
|
||||
#### 参考实现
|
||||
|
||||
* `plugins/actions/infographic/infographic.py` - 基于 AntV + Data URL 的生产级实现
|
||||
- `plugins/actions/infographic/infographic.py` - 基于 AntV + Data URL 的生产级实现
|
||||
|
||||
## 5. 最佳实践与设计原则 {: #5-best-practices }
|
||||
|
||||
### 5.1 命名与定位
|
||||
|
||||
* **简短有力**:如 "闪记卡", "精读"。避免 "文本分析助手" 这种泛词。
|
||||
* **功能互补**:不要重复造轮子,明确你的插件解决了什么特定问题。
|
||||
* **简短有力**:如 "闪记卡", "精读"。避免 "文本分析助手" 这种泛词。
|
||||
* **功能互补**:不要重复造轮子,明确你的插件解决了什么特定问题。
|
||||
|
||||
### 5.2 用户体验 (UX)
|
||||
|
||||
* **反馈及时**:耗时操作前先发送 `notification` ("正在生成...")。
|
||||
* **视觉美观**:Action 输出 HTML 时,使用现代化的 CSS(圆角、阴影、渐变)。
|
||||
* **智能引导**:检测到文本过短时,提示用户"建议输入更多内容以获得更好结果"。
|
||||
* **反馈及时**:耗时操作前先发送 `notification` ("正在生成...")。
|
||||
* **视觉美观**:Action 输出 HTML 时,使用现代化的 CSS(圆角、阴影、渐变)。
|
||||
* **智能引导**:检测到文本过短时,提示用户"建议输入更多内容以获得更好结果"。
|
||||
|
||||
### 5.3 错误处理
|
||||
|
||||
永远不要让插件静默失败。捕获异常并通过 `__event_emitter__` 告知用户。
|
||||
|
||||
```python
|
||||
@@ -352,76 +343,8 @@ except Exception as e:
|
||||
|
||||
---
|
||||
|
||||
## 6. 仓库规范(openwebui-extensions) {: #6-repo-standards }
|
||||
## 6. 故障排查 {: #6-troubleshooting }
|
||||
|
||||
### 6.1 单文件 i18n 规范
|
||||
|
||||
本仓库要求每个插件采用**单文件源码 + 内置多语言**方案,禁止按语言拆分多个 `.py` 文件。
|
||||
|
||||
* 代码路径规范:`plugins/{type}/{name}/{name}.py`
|
||||
* 文档规范:必须同时提供 `README.md` 与 `README_CN.md`
|
||||
|
||||
### 6.2 上下文访问规范(必选)
|
||||
|
||||
优先通过 `_get_user_context` 与 `_get_chat_context` 提取上下文,避免直接硬编码读取 `__user__` 或 `body` 字段。
|
||||
|
||||
### 6.3 事件与日志规范
|
||||
|
||||
* 用状态/通知事件给用户反馈进度。
|
||||
* 前端调试优先使用 `execute` 注入的控制台日志。
|
||||
* 后端统一使用 Python `logging`,生产代码避免 `print()`。
|
||||
|
||||
### 6.4 前端语言探测防卡死
|
||||
|
||||
通过 `__event_call__` 获取前端语言时,必须同时满足:
|
||||
|
||||
* JS 端 `try...catch` 并保证返回值
|
||||
* 后端 `asyncio.wait_for(..., timeout=2.0)`
|
||||
|
||||
这样可以避免前端异常导致后端永久等待。
|
||||
|
||||
### 6.5 Copilot SDK 工具参数定义
|
||||
|
||||
开发 Copilot SDK 工具时,应使用 `pydantic.BaseModel` 显式声明参数,并在 `define_tool(...)` 中通过 `params_type` 传入。
|
||||
|
||||
### 6.6 Copilot SDK 流式输出格式
|
||||
|
||||
* 思考过程使用原生 `<think>...</think>`。
|
||||
* 正文或工具卡片输出前,必须先闭合 `</think>`。
|
||||
* 工具卡片使用 `<details type="tool_calls" ...>` 原生结构。
|
||||
* `arguments` 与 `result` 属性中的双引号必须转义为 `"`。
|
||||
|
||||
### 6.7 从 `plugins/` 全量提炼的关键开发知识
|
||||
|
||||
* **输入与上下文**:统一做多模态文本抽取;优先 `_get_user_context` / `_get_chat_context`;前端语言探测必须 `wait_for` 超时保护。
|
||||
* **长任务反馈**:执行前立即发送 `status/notification`,过程分阶段汇报,失败时用户提示简洁、后台日志完整。
|
||||
* **HTML/渲染输出**:使用固定包装器与插入点,支持覆盖与合并两种模式;主题跟随父页面与系统主题。
|
||||
* **前端导出闭环**:离屏渲染 SVG/PNG -> 上传 `/api/v1/files/` -> 事件更新 + 持久化更新,避免刷新丢失。
|
||||
* **DOCX 生产模式**:`TITLE_SOURCE` 多级回退;导出前剔除 reasoning;LaTeX 转 OMML;支持引用锚点与参考文献。
|
||||
* **文件访问回退链**:DB 内联 -> S3 -> 本地路径变体 -> 公网 URL -> 内部 API -> 原始字段,并在每层限制字节上限。
|
||||
* **Filter 单例安全**:禁止在 `self` 保存请求态;上下文压缩采用 inlet/outlet 双阶段 + 异步后台任务。
|
||||
* **工具与工作区安全**:工具参数用 `params_type` 显式建模;路径解析后必须二次校验在 workspace 根目录内。
|
||||
* **文件交付标准**:本地生成 -> 发布工具 -> 返回 `/api/v1/files/{id}/content`,并带 `skip_rag=true` 元数据。
|
||||
* **MoE 聚合优化**:识别聚合提示词后重写为结构化综合分析任务,并可在聚合阶段切换模型。
|
||||
|
||||
### 6.8 Copilot 工程化配置(GitHub Copilot + Gemini CLI + 反重力开发)
|
||||
|
||||
统一工程化配置请参考:
|
||||
|
||||
* `docs/development/copilot-engineering-plan.md`
|
||||
* `docs/development/copilot-engineering-plan.zh.md`
|
||||
|
||||
该设计文档规定了:
|
||||
|
||||
* 工具参数建模与路由规则
|
||||
* 文件创建与发布协议
|
||||
* 可回滚的高迭代交付模式
|
||||
* 流式输出与工具卡片兼容要求
|
||||
|
||||
---
|
||||
|
||||
## 7. 故障排查 {: #7-troubleshooting }
|
||||
|
||||
* **HTML 不显示?** 确保包裹在 ` ```html ... ``` ` 代码块中。
|
||||
* **数据库报错?** 检查是否在 `async` 函数中直接调用了同步的 DB 方法,请使用 `asyncio.to_thread`。
|
||||
* **参数未生效?** 检查 `Valves` 定义是否正确,以及是否被 `UserValves` 覆盖。
|
||||
* **HTML 不显示?** 确保包裹在 ` ```html ... ``` ` 代码块中。
|
||||
* **数据库报错?** 检查是否在 `async` 函数中直接调用了同步的 DB 方法,请使用 `asyncio.to_thread`。
|
||||
* **参数未生效?** 检查 `Valves` 定义是否正确,以及是否被 `UserValves` 覆盖。
|
||||
|
||||
@@ -1,46 +1,50 @@
|
||||
# Implementation Plan (Current)
|
||||
# 开源项目重组实施计划
|
||||
|
||||
## 1. Objective
|
||||
## 1. 目标
|
||||
将 `openwebui-extras` 打造为一个 **OpenWebUI 增强功能集合库**,专注于分享个人开发和收集的优质插件、提示词,而非作为一个独立的 Python 应用程序发布。
|
||||
|
||||
Define an engineering-ready design baseline for OpenWebUI plugin development that:
|
||||
## 2. 当前状态分析
|
||||
- **定位明确**:项目核心价值在于内容(Plugins, Prompts, Docs),而非运行环境。
|
||||
- **结构已优化**:
|
||||
- `plugins/`:核心插件资源。
|
||||
- `prompts/`:提示词资源。
|
||||
- `docs/`:详细的使用和开发文档。
|
||||
- `scripts/`:辅助工具脚本(如本地测试用的 `run.py`)。
|
||||
- **已移除不必要文件**:移除了 `requirements.txt`,避免用户误以为需要配置 Python 环境。
|
||||
|
||||
- uses GitHub Copilot as the primary coding agent,
|
||||
- supports Gemini CLI as a secondary execution/research lane,
|
||||
- adopts antigravity development mode for reversible, low-risk iteration.
|
||||
## 3. 重组方案
|
||||
|
||||
## 2. Current Decision
|
||||
### 3.1 目录结构
|
||||
保持当前的清晰结构,强调“拿来即用”:
|
||||
|
||||
The active design document is:
|
||||
```
|
||||
openwebui-extras/
|
||||
├── docs/ # 文档与教程
|
||||
├── plugins/ # 插件库 (核心资源)
|
||||
│ ├── actions/
|
||||
│ ├── filters/
|
||||
│ ├── pipelines/
|
||||
│ └── pipes/
|
||||
├── prompts/ # 提示词库 (核心资源)
|
||||
├── scripts/ # 维护者工具 (非用户必须)
|
||||
├── LICENSE # MIT 许可证
|
||||
├── README.md # 项目入口与资源索引
|
||||
└── index.html # 项目展示页
|
||||
```
|
||||
|
||||
- `docs/development/copilot-engineering-plan.md`
|
||||
- `docs/development/copilot-engineering-plan.zh.md`
|
||||
### 3.2 核心调整
|
||||
1. **移除依赖管理**:删除了 `requirements.txt`。用户不需要 `pip install` 任何东西,只需下载对应的 `.py` 或 `.md` 文件导入 OpenWebUI 即可。
|
||||
2. **文档侧重**:README 和文档将侧重于“如何下载”和“如何导入”,而不是“如何安装项目”。
|
||||
|
||||
This file is retained as a stable pointer to avoid design drift.
|
||||
### 3.3 后续建议
|
||||
1. **资源索引**:建议在 `README.md` 中维护一个高质量的插件/提示词索引表,方便用户快速查找。
|
||||
2. **贡献指南**:制定简单的 `CONTRIBUTING.md`,告诉其他人如何提交他们的插件或提示词(例如:只需提交文件到对应目录)。
|
||||
3. **版本控制**:虽然不需要 Python 环境,但建议在插件文件的头部注释中保留版本号和兼容性说明(如 `Compatible with OpenWebUI v0.3.x`)。
|
||||
|
||||
## 3. Engineering Baseline
|
||||
|
||||
- Single-file i18n plugin code architecture.
|
||||
- Bilingual documentation contract.
|
||||
- Copilot SDK tool schema discipline (`params_type`).
|
||||
- Gemini CLI output normalization before merge.
|
||||
- Workspace file sandbox + publish protocol.
|
||||
- Streaming compatibility with native `<think>` and `<details type="tool_calls">`.
|
||||
|
||||
## 4. File Creation & Delivery Baseline
|
||||
|
||||
- Create artifacts in workspace-scoped paths.
|
||||
- Publish artifacts via workspace publish flow.
|
||||
- Return and display `/api/v1/files/{id}/content` links for delivery.
|
||||
|
||||
## 5. Maintenance Rule
|
||||
|
||||
Any update to plugin engineering standards must be reflected in:
|
||||
|
||||
1. `docs/development/copilot-engineering-plan.md`
|
||||
2. `docs/development/copilot-engineering-plan.zh.md`
|
||||
3. `docs/development/plugin-guide.md`
|
||||
4. `docs/development/plugin-guide.zh.md`
|
||||
## 4. 发布流程
|
||||
1. **提交更改**:`git add . && git commit -m "Update project structure for resource sharing"`
|
||||
2. **推送到 GitHub**。
|
||||
3. **宣传**:在 OpenWebUI 社区分享此仓库链接。
|
||||
|
||||
---
|
||||
|
||||
Updated: 2026-02-23
|
||||
*生成时间:2025-12-19*
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
|
||||
## 📚 Table of Contents
|
||||
|
||||
1. [Quick Start](#1-quick-start)
|
||||
2. [Core Concepts & SDK Details](#2-core-concepts--sdk-details)
|
||||
3. [Deep Dive into Plugin Types](#3-deep-dive-into-plugin-types)
|
||||
* [Action](#31-action)
|
||||
* [Filter](#32-filter)
|
||||
* [Pipe](#33-pipe)
|
||||
4. [Advanced Development Patterns](#4-advanced-development-patterns)
|
||||
5. [Best Practices & Design Principles](#5-best-practices--design-principles)
|
||||
6. [Repository Standards (openwebui-extensions)](#6-repository-standards-openwebui-extensions)
|
||||
7. [Custom Agent Design Recommendations](#7-custom-agent-design-recommendations)
|
||||
8. [Troubleshooting](#8-troubleshooting)
|
||||
1. [Quick Start](#1-quick-start)
|
||||
2. [Core Concepts & SDK Details](#2-core-concepts--sdk-details)
|
||||
3. [Deep Dive into Plugin Types](#3-deep-dive-into-plugin-types)
|
||||
* [Action](#31-action)
|
||||
* [Filter](#32-filter)
|
||||
* [Pipe](#33-pipe)
|
||||
4. [Advanced Development Patterns](#4-advanced-development-patterns)
|
||||
5. [Best Practices & Design Principles](#5-best-practices--design-principles)
|
||||
6. [Troubleshooting](#6-troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
@@ -23,10 +21,9 @@
|
||||
### 1.1 What are OpenWebUI Plugins?
|
||||
|
||||
OpenWebUI Plugins (officially called "Functions") are the primary way to extend the platform's capabilities. Running in a backend Python environment, they allow you to:
|
||||
|
||||
* 🔌 **Integrate New Models**: Connect to Claude, Gemini, or custom RAGs via Pipes.
|
||||
* 🎨 **Enhance Interaction**: Add buttons (e.g., "Export", "Generate Chart") next to messages via Actions.
|
||||
* 🔧 **Intervene in Processes**: modify data before requests or after responses (e.g., inject context, filter sensitive words) via Filters.
|
||||
* 🔌 **Integrate New Models**: Connect to Claude, Gemini, or custom RAGs via Pipes.
|
||||
* 🎨 **Enhance Interaction**: Add buttons (e.g., "Export", "Generate Chart") next to messages via Actions.
|
||||
* 🔧 **Intervene in Processes**: Modify data before requests or after responses (e.g., inject context, filter sensitive words) via Filters.
|
||||
|
||||
### 1.2 Your First Plugin (Hello World)
|
||||
|
||||
@@ -72,10 +69,9 @@ class Action:
|
||||
### 2.1 ⚠️ Important: Sync vs Async
|
||||
|
||||
OpenWebUI plugins run within an `asyncio` event loop.
|
||||
|
||||
* **Principle**: All I/O operations (database, file, network) must be non-blocking.
|
||||
* **Pitfall**: Calling synchronous methods directly (e.g., `time.sleep`, `requests.get`) will freeze the entire server.
|
||||
* **Solution**: Wrap synchronous calls using `await asyncio.to_thread(sync_func, ...)`.
|
||||
* **Principle**: All I/O operations (database, file, network) must be non-blocking.
|
||||
* **Pitfall**: Calling synchronous methods directly (e.g., `time.sleep`, `requests.get`) will freeze the entire server.
|
||||
* **Solution**: Wrap synchronous calls using `await asyncio.to_thread(sync_func, ...)`.
|
||||
|
||||
### 2.2 Core Parameters
|
||||
|
||||
@@ -92,8 +88,8 @@ All plugin methods (`inlet`, `outlet`, `pipe`, `action`) support injecting the f
|
||||
|
||||
### 2.3 Configuration System (Valves)
|
||||
|
||||
* **`Valves`**: Global admin configuration.
|
||||
* **`UserValves`**: User-level configuration (higher priority, overrides global).
|
||||
* **`Valves`**: Global admin configuration.
|
||||
* **`UserValves`**: User-level configuration (higher priority, overrides global).
|
||||
|
||||
```python
|
||||
class Filter:
|
||||
@@ -117,7 +113,7 @@ class Filter:
|
||||
|
||||
**Role**: Adds buttons below messages that trigger upon user click.
|
||||
|
||||
#### Advanced Usage: Execute JavaScript on Frontend (File Download Example)
|
||||
**Advanced Usage: Execute JavaScript on Frontend (File Download Example)**
|
||||
|
||||
```python
|
||||
import base64
|
||||
@@ -142,11 +138,11 @@ async def action(self, body, __event_call__):
|
||||
|
||||
**Role**: Middleware that intercepts and modifies requests/responses.
|
||||
|
||||
* **`inlet`**: Before request. Used for injecting context, modifying model parameters.
|
||||
* **`outlet`**: After response. Used for formatting output, logging.
|
||||
* **`stream`**: During streaming. Used for real-time sensitive word filtering.
|
||||
* **`inlet`**: Before request. Used for injecting context, modifying model parameters.
|
||||
* **`outlet`**: After response. Used for formatting output, logging.
|
||||
* **`stream`**: During streaming. Used for real-time sensitive word filtering.
|
||||
|
||||
#### Example: Injecting Environment Variables
|
||||
**Example: Injecting Environment Variables**
|
||||
|
||||
```python
|
||||
async def inlet(self, body, __metadata__):
|
||||
@@ -163,7 +159,7 @@ async def inlet(self, body, __metadata__):
|
||||
|
||||
**Role**: Custom Model/Agent.
|
||||
|
||||
#### Example: Simple OpenAI Wrapper
|
||||
**Example: Simple OpenAI Wrapper**
|
||||
|
||||
```python
|
||||
import requests
|
||||
@@ -184,14 +180,11 @@ class Pipe:
|
||||
## 4. Advanced Development Patterns
|
||||
|
||||
### 4.1 Pipe & Filter Collaboration
|
||||
|
||||
Use `__request__.app.state` to share data between plugins.
|
||||
|
||||
* **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
* **Filter (Outlet)**: Read `search_results` and format them as citation links appended to the response.
|
||||
* **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
* **Filter (Outlet)**: Read `search_results` and format them as citation links appended to the response.
|
||||
|
||||
### 4.2 Async Background Tasks
|
||||
|
||||
Execute time-consuming operations (e.g., summarization, database storage) in the background without blocking the user response.
|
||||
|
||||
```python
|
||||
@@ -211,18 +204,15 @@ async def background_job(self, chat_id):
|
||||
## 5. Best Practices & Design Principles
|
||||
|
||||
### 5.1 Naming & Positioning
|
||||
|
||||
* **Short & Punchy**: e.g., "FlashCard", "DeepRead". Avoid generic terms like "Text Analysis Assistant".
|
||||
* **Complementary**: Don't reinvent the wheel; clarify what specific problem your plugin solves.
|
||||
* **Short & Punchy**: e.g., "FlashCard", "DeepRead". Avoid generic terms like "Text Analysis Assistant".
|
||||
* **Complementary**: Don't reinvent the wheel; clarify what specific problem your plugin solves.
|
||||
|
||||
### 5.2 User Experience (UX)
|
||||
|
||||
* **Timely Feedback**: Send a `notification` ("Generating...") before time-consuming operations.
|
||||
* **Visual Appeal**: When Action outputs HTML, use modern CSS (rounded corners, shadows, gradients).
|
||||
* **Smart Guidance**: If text is too short, prompt the user: "Suggest entering more content for better results".
|
||||
* **Timely Feedback**: Send a `notification` ("Generating...") before time-consuming operations.
|
||||
* **Visual Appeal**: When Action outputs HTML, use modern CSS (rounded corners, shadows, gradients).
|
||||
* **Smart Guidance**: If text is too short, prompt the user: "Suggest entering more content for better results".
|
||||
|
||||
### 5.3 Error Handling
|
||||
|
||||
Never let a plugin fail silently. Catch exceptions and inform the user via `__event_emitter__`.
|
||||
|
||||
```python
|
||||
@@ -237,127 +227,8 @@ except Exception as e:
|
||||
|
||||
---
|
||||
|
||||
## 6. Repository Standards (openwebui-extensions)
|
||||
## 6. Troubleshooting
|
||||
|
||||
### 6.1 Single-file i18n Requirement
|
||||
|
||||
In this repository, each plugin must use a **single source file** with built-in i18n logic. Do not split source code by language.
|
||||
|
||||
* Required pattern: `plugins/{type}/{name}/{name}.py`
|
||||
* Required docs: `README.md` + `README_CN.md`
|
||||
|
||||
### 6.2 Safe Context Access (Required)
|
||||
|
||||
Prefer helper methods like `_get_user_context` and `_get_chat_context` instead of direct, fragile field access from `__user__` / `body`.
|
||||
|
||||
### 6.3 Event and Logging Conventions
|
||||
|
||||
* Use status/notification events for user-visible progress.
|
||||
* Use frontend console debug logs (`execute`) for live debugging during development.
|
||||
* Use Python `logging` for backend logs; avoid `print()` in production plugin code.
|
||||
|
||||
### 6.4 Frontend Language Detection and Timeout Guard
|
||||
|
||||
When reading frontend language via `__event_call__`, always use:
|
||||
|
||||
* JS `try...catch` fallback return
|
||||
* backend `asyncio.wait_for(..., timeout=2.0)`
|
||||
|
||||
This prevents deadlocks when frontend execution fails.
|
||||
|
||||
### 6.5 Copilot SDK Tool Definition
|
||||
|
||||
For custom Copilot SDK tools, define explicit parameter schema using a `pydantic.BaseModel` and pass it with `params_type` in `define_tool(...)`.
|
||||
|
||||
### 6.6 Copilot SDK Streaming Output Format
|
||||
|
||||
* Use native `<think>...</think>` for reasoning output.
|
||||
* Ensure `</think>` is closed before normal content or tool cards.
|
||||
* For tool result cards, use native `<details type="tool_calls" ...>` format.
|
||||
* Escape attribute quotes in `arguments` and `result` as `"`.
|
||||
|
||||
### 6.7 Source-derived Production Patterns (Recommended)
|
||||
|
||||
The following patterns are extracted from `github_copilot_sdk.py` and `workspace_file_manager.py`:
|
||||
|
||||
* **Tool parameter anti-drift**: define tools with `params_type=BaseModel`, and execute with `model_dump(exclude_unset=True)` so missing params do not become explicit `None`.
|
||||
* **Tool name normalization**: enforce `^[a-zA-Z0-9_-]+$`; if non-ASCII names collapse, use an `md5` suffix fallback to keep registration stable.
|
||||
* **Workspace sandboxing**: resolve and verify every path stays inside the workspace root to prevent traversal.
|
||||
* **3-step file delivery**: local write -> `publish_file_from_workspace` -> return `/api/v1/files/{id}/content`, with `skip_rag=true` metadata.
|
||||
* **Dual upload channel**: prefer API upload (S3-compatible), fallback to DB + local copy.
|
||||
* **Streaming stability**: close `<think>` before emitting `assistant.message_delta` content.
|
||||
* **Native tool cards**: emit `<details type="tool_calls">` on `tool.execution_complete` with strict HTML escaping (`"`, newline escaping).
|
||||
* **TODO persistence linkage**: on successful `update_todo`, sync both `TODO.md` and database state.
|
||||
|
||||
### 6.8 Full Source-derived Knowledge Base (from `plugins/`)
|
||||
|
||||
The following is a broader extraction from `actions/`, `filters/`, `pipes/`, `pipelines/`, and `tools/`:
|
||||
|
||||
* **Action input hygiene**: normalize multimodal message content, strip old plugin HTML blocks (`OPENWEBUI_PLUGIN_OUTPUT`), and enforce minimum text length before expensive model calls.
|
||||
* **Action i18n hardening**: use `TRANSLATIONS + fallback_map + base-lang fallback` (`fr-CA -> fr-FR`, `en-GB -> en-US`), keep all status/UI/JS strings in i18n keys, and protect `format(**kwargs)` formatting.
|
||||
* **Frontend language detection (production-safe)**: use priority chain `document.lang -> localStorage(locale/language) -> navigator.language -> profile/request`, and always wrap `__event_call__(execute)` with timeout.
|
||||
* **Long-running UX pattern**: emit immediate `status + notification`, report staged progress (`analyzing/rendering/saving`), and keep detailed exception data in backend logs.
|
||||
* **HTML plugin composability**: use insertion markers for style/content/script, support both overwrite (`CLEAR_PREVIOUS_HTML`) and merge mode, and keep wrappers deterministic.
|
||||
* **Theme-aware iframe rendering**: detect theme from parent meta/class/data-theme with system fallback, and inject theme-aware colors for SVG/PNG export.
|
||||
* **Client-side render-and-export pipeline**: render offscreen chart/mindmap, export SVG/PNG, upload via `/api/v1/files/`, and persist updates through event API + chat persistence API.
|
||||
* **DOCX export production patterns**: apply `TITLE_SOURCE` fallback chain (`chat_title -> markdown_title -> user+date`), remove reasoning blocks, convert LaTeX via `latex2mathml + mathml2omml`, and emit citation-aware references/bookmarks.
|
||||
* **OpenWebUI file retrieval fallback ladder**: DB inline bytes/base64 -> S3 direct read -> local path variants -> public URL -> internal `/api/v1/files/{id}/content` -> raw object attrs, with max-byte guards at every stage.
|
||||
* **Filter singleton-safe design**: never store request-scoped mutable state on `self`; compute per-request values from `body` and context helpers.
|
||||
* **Async context compression patterns**: two-phase flow (`inlet` apply summary, `outlet` async generate summary), model-level threshold overrides, fast estimate + precise count near limit, and system-message protection (`effective_keep_first`).
|
||||
* **Model compatibility guardrails**: skip incompatible model families (e.g., `copilot_sdk` paths) and avoid hardcoded default model IDs.
|
||||
* **Folder memory pattern**: trigger periodic rule extraction (`every N messages`), replace rules idempotently using block markers (`RULES_BLOCK_START/END`), and optionally update root folder.
|
||||
* **Tool workspace hardening**: all file APIs (`list/read/write/delete/publish`) must re-check sandbox boundary, enforce size limits, and return user-ready download hints.
|
||||
* **MoE prompt refiner pattern (pipeline)**: detect aggregation prompts via trigger prefix, parse original query + segmented responses, then rewrite to synthesis-oriented master prompt with optional aggregation model reroute.
|
||||
|
||||
### 6.9 Copilot-related Engineering Configuration
|
||||
|
||||
To support plugin engineering with **GitHub Copilot + Gemini CLI + antigravity mode**, adopt these controls:
|
||||
|
||||
* **Primary/secondary assistant lanes**: Copilot is primary implementation lane; Gemini CLI is secondary draft/verification lane.
|
||||
* **Single merge contract**: both lanes must pass the same repository constraints (single-file i18n, context helpers, event conventions, release workflow rules).
|
||||
* **Tool schema discipline**: all Copilot SDK tools use explicit `params_type` with Pydantic models.
|
||||
* **Antigravity safety**: small reversible edits, timeout guards, fallback routing, and deterministic file/output paths.
|
||||
* **File creation protocol**: write in workspace scope, publish via workspace publish flow, return `/api/v1/files/{id}/content` for delivery.
|
||||
|
||||
Detailed design document:
|
||||
|
||||
* `docs/development/copilot-engineering-plan.md`
|
||||
|
||||
---
|
||||
|
||||
## 7. Custom Agent Design Recommendations
|
||||
|
||||
### 7.1 Suggested architecture (for this repo)
|
||||
|
||||
* **Orchestrator Pipe**: session lifecycle, model routing, streaming events.
|
||||
* **Tool Adapter Layer**: unify OpenWebUI Tools / OpenAPI / MCP with param validation and name normalization.
|
||||
* **Workspace I/O Layer**: sandboxed file operations + publish pipeline.
|
||||
* **Render Layer**: `<think>` lifecycle, tool cards, status/notification events.
|
||||
|
||||
### 7.2 MVP checklist
|
||||
|
||||
1. Dual config model: `Valves + UserValves` (user overrides first).
|
||||
2. Unified context helpers: `_get_user_context` / `_get_chat_context`.
|
||||
3. At least one artifact-delivery tool (e.g., `publish_file_from_workspace`).
|
||||
4. Minimal streaming loop: `reasoning_delta`, `message_delta`, `tool.execution_complete`.
|
||||
5. Unified error reporting via notification events.
|
||||
|
||||
### 7.3 Three high-impact agents you can build now
|
||||
|
||||
* **Repo Analyst Agent**: output architecture map, risk list, and refactor proposals.
|
||||
* **Release Draft Agent**: generate Conventional Commit title/body + bilingual release summary.
|
||||
* **Docs Sync Agent**: compare source/doc versions and output a concrete sync file list.
|
||||
|
||||
### 7.4 Implementation priority
|
||||
|
||||
* **P0**: Release Draft Agent (highest ROI, lowest risk).
|
||||
* **P1**: Docs Sync Agent (reduces doc drift).
|
||||
* **P2**: Repo Analyst Agent (medium/long-term evolution).
|
||||
|
||||
---
|
||||
|
||||
## 8. Troubleshooting
|
||||
|
||||
* **HTML not showing?** Ensure it's wrapped in a ` ```html ... ``` ` code block.
|
||||
* **Database error?** Check if you called synchronous DB methods directly in an `async` function; use `asyncio.to_thread`.
|
||||
* **Parameters not working?** Check if `Valves` are defined correctly and if they are being overridden by `UserValves`.
|
||||
* **HTML not showing?** Ensure it's wrapped in a ` ```html ... ``` ` code block.
|
||||
* **Database error?** Check if you called synchronous DB methods directly in an `async` function; use `asyncio.to_thread`.
|
||||
* **Parameters not working?** Check if `Valves` are defined correctly and if they are being overridden by `UserValves`.
|
||||
|
||||
@@ -23,7 +23,7 @@ Actions are interactive plugins that:
|
||||
|
||||
Intelligently analyzes text content and generates interactive mind maps with beautiful visualizations.
|
||||
|
||||
**Version:** 1.0.0
|
||||
**Version:** 0.9.2
|
||||
|
||||
[:octicons-arrow-right-24: Documentation](smart-mind-map.md)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ Actions 是交互式插件,能够:
|
||||
|
||||
智能分析文本并生成交互式、精美的思维导图。
|
||||
|
||||
**版本:** 1.0.0
|
||||
**版本:** 0.8.0
|
||||
|
||||
[:octicons-arrow-right-24: 查看文档](smart-mind-map.md)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Smart Mind Map
|
||||
|
||||
<span class="category-badge action">Action</span>
|
||||
<span class="version-badge">v1.0.0</span>
|
||||
<span class="version-badge">v0.9.2</span>
|
||||
|
||||
Intelligently analyzes text content and generates interactive mind maps for better visualization and understanding.
|
||||
|
||||
@@ -17,8 +17,7 @@ The Smart Mind Map plugin transforms text content into beautiful, interactive mi
|
||||
- :material-gesture-swipe: **Rich Controls**: Zoom, reset view, expand level selector (All/2/3) and fullscreen
|
||||
- :material-palette: **Theme Aware**: Auto-detects OpenWebUI light/dark theme with manual toggle
|
||||
- :material-download: **One-Click Export**: Download high-res PNG, copy SVG, or copy Markdown source
|
||||
- :material-translate: **i18n Embedded**: One code file smartly detects frontend languages and translates the output.
|
||||
- :material-arrow-all: **Auto-Sizing & Direct Embed**: Seamlessly scales to display massive canvas inline (requires setting toggle).
|
||||
- :material-translate: **Multi-language**: Matches output language to the input text
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +50,6 @@ The Smart Mind Map plugin transforms text content into beautiful, interactive mi
|
||||
| `MIN_TEXT_LENGTH` | integer | `100` | Minimum characters required before analysis runs |
|
||||
| `CLEAR_PREVIOUS_HTML` | boolean | `false` | Clear previous plugin HTML instead of merging |
|
||||
| `MESSAGE_COUNT` | integer | `1` | Number of recent messages to include (1–5) |
|
||||
| `ENABLE_DIRECT_EMBED_MODE` | boolean | `false` | Enable inline full-width UI for OpenWebUI 0.8.0+ |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Smart Mind Map(智能思维导图)
|
||||
|
||||
<span class="category-badge action">Action</span>
|
||||
<span class="version-badge">v1.0.0</span>
|
||||
<span class="version-badge">v0.9.2</span>
|
||||
|
||||
智能分析文本内容,生成交互式思维导图,帮助你更直观地理解信息结构。
|
||||
|
||||
@@ -17,8 +17,7 @@ Smart Mind Map 会将文本转换成漂亮的交互式思维导图。插件会
|
||||
- :material-gesture-swipe: **丰富控制**:缩放/重置、展开层级(全部/2/3 级)与全屏
|
||||
- :material-palette: **主题感知**:自动检测 OpenWebUI 亮/暗色主题并支持手动切换
|
||||
- :material-download: **一键导出**:下载高分辨率 PNG、复制 SVG 或 Markdown
|
||||
- :material-translate: **内置 i18n 语言识别**:单个文件自动检测控制台前端语言,无需繁杂的各种语言包版本。
|
||||
- :material-arrow-all: **直出全屏版体验 (需配置开启)**:新版直出渲染抛开沙盒限制,纵情铺满屏幕,享受原生的图表体验。
|
||||
- :material-translate: **多语言**:输出语言与输入文本一致
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +50,6 @@ Smart Mind Map 会将文本转换成漂亮的交互式思维导图。插件会
|
||||
| `MIN_TEXT_LENGTH` | integer | `100` | 开始分析所需的最少字符数 |
|
||||
| `CLEAR_PREVIOUS_HTML` | boolean | `false` | 生成新导图时是否清除之前的插件 HTML |
|
||||
| `MESSAGE_COUNT` | integer | `1` | 用于生成的最近消息数量(1–5) |
|
||||
| `ENABLE_DIRECT_EMBED_MODE` | boolean | `false` | 是否开启沉浸式直出模式 (需要 Open WebUI 0.8.0+ ) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,81 +1,137 @@
|
||||
# Async Context Compression Filter
|
||||
# Async Context Compression
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **Version:** 1.3.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
<span class="category-badge filter">Filter</span>
|
||||
<span class="version-badge">v1.2.2</span>
|
||||
|
||||
This filter reduces token consumption in long conversations through intelligent summarization and message compression while keeping conversations coherent.
|
||||
|
||||
## What's new in 1.3.0
|
||||
|
||||
- **Internationalization (i18n)**: Complete localization of user-facing messages across 9 languages (English, Chinese, Japanese, Korean, French, German, Spanish, Italian).
|
||||
- **Smart Status Display**: Added `token_usage_status_threshold` valve (default 80%) to intelligently control when token usage status is shown.
|
||||
- **Improved Performance**: Frontend language detection and logging are optimized to be completely non-blocking, maintaining lightning-fast TTFB.
|
||||
- **Copilot SDK Integration**: Automatically detects and skips compression for copilot_sdk based models to prevent conflicts.
|
||||
- **Configuration**: `debug_mode` is now set to `false` by default for a quieter production experience.
|
||||
Reduces token consumption in long conversations through intelligent summarization while maintaining conversational coherence.
|
||||
|
||||
---
|
||||
|
||||
## Core Features
|
||||
## Overview
|
||||
|
||||
- ✅ **Full i18n Support**: Native localization across 9 languages.
|
||||
- ✅ Automatic compression triggered by token thresholds.
|
||||
- ✅ Asynchronous summarization that does not block chat responses.
|
||||
- ✅ Persistent storage via Open WebUI's shared database connection (PostgreSQL, SQLite, etc.).
|
||||
- ✅ Flexible retention policy to keep the first and last N messages.
|
||||
- ✅ Smart injection of historical summaries back into the context.
|
||||
- ✅ Structure-aware trimming that preserves document structure (headers, intro, conclusion).
|
||||
- ✅ Native tool output trimming for cleaner context when using function calling.
|
||||
- ✅ Real-time context usage monitoring with warning notifications (>90%).
|
||||
- ✅ Detailed token logging for precise debugging and optimization.
|
||||
- ✅ **Smart Model Matching**: Automatically inherits configuration from base models for custom presets.
|
||||
- ⚠ **Multimodal Support**: Images are preserved but their tokens are **NOT** calculated. Please adjust thresholds accordingly.
|
||||
The Async Context Compression filter helps manage token usage in long conversations by:
|
||||
|
||||
- Intelligently summarizing older messages
|
||||
- Preserving important context
|
||||
- Reducing API costs
|
||||
- Maintaining conversation coherence
|
||||
|
||||
This is especially useful for:
|
||||
|
||||
- Long-running conversations
|
||||
- Complex multi-turn discussions
|
||||
- Cost optimization
|
||||
- Token limit management
|
||||
|
||||
## Features
|
||||
|
||||
- :material-arrow-collapse-vertical: **Smart Compression**: AI-powered context summarization
|
||||
- :material-clock-fast: **Async Processing**: Non-blocking background compression
|
||||
- :material-memory: **Context Preservation**: Keeps important information
|
||||
- :material-currency-usd-off: **Cost Reduction**: Minimize token usage
|
||||
- :material-console: **Frontend Debugging**: Debug logs in browser console
|
||||
- :material-alert-circle-check: **Enhanced Error Reporting**: Clear error status notifications
|
||||
- :material-check-all: **Open WebUI v0.7.x Compatibility**: Dynamic DB session handling
|
||||
- :material-account-convert: **Improved Compatibility**: Summary role changed to `assistant`
|
||||
- :material-shield-check: **Enhanced Stability**: Resolved race conditions in state management
|
||||
- :material-ruler: **Preflight Context Check**: Validates context fit before sending
|
||||
- :material-format-align-justify: **Structure-Aware Trimming**: Preserves document structure
|
||||
- :material-content-cut: **Native Tool Output Trimming**: Trims verbose tool outputs (Note: Non-native tool outputs are not fully injected into context)
|
||||
- :material-chart-bar: **Detailed Token Logging**: Granular token breakdown
|
||||
- :material-account-search: **Smart Model Matching**: Inherit config from base models
|
||||
- :material-image-off: **Multimodal Support**: Images are preserved but tokens are **NOT** calculated
|
||||
|
||||
---
|
||||
|
||||
## Installation & Configuration
|
||||
## Installation
|
||||
|
||||
### 1) Database (automatic)
|
||||
|
||||
- Uses Open WebUI's shared database connection; no extra configuration needed.
|
||||
- The `chat_summary` table is created on first run.
|
||||
|
||||
### 2) Filter order
|
||||
|
||||
- Recommended order: pre-filters (<10) → this filter (10) → post-filters (>10).
|
||||
1. Download the plugin file: [`async_context_compression.py`](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/filters/async-context-compression)
|
||||
2. Upload to OpenWebUI: **Admin Panel** → **Settings** → **Functions**
|
||||
3. Configure compression settings
|
||||
4. Enable the filter
|
||||
|
||||
---
|
||||
|
||||
## Configuration Parameters
|
||||
## How It Works
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| :----------------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `priority` | `10` | Execution order; lower runs earlier. |
|
||||
| `compression_threshold_tokens` | `64000` | Trigger asynchronous summary when total tokens exceed this value. Set to 50%-70% of your model's context window. |
|
||||
| `max_context_tokens` | `128000` | Hard cap for context; older messages (except protected ones) are dropped if exceeded. |
|
||||
| `keep_first` | `1` | Always keep the first N messages (protects system prompts). |
|
||||
| `keep_last` | `6` | Always keep the last N messages to preserve recent context. |
|
||||
| `summary_model` | `None` | Model for summaries. Strongly recommended to set a fast, economical model (e.g., `gemini-2.5-flash`, `deepseek-v3`). Falls back to the current chat model when empty. |
|
||||
| `summary_model_max_context` | `0` | Max context tokens for the summary model. If 0, falls back to `model_thresholds` or global `max_context_tokens`. |
|
||||
| `max_summary_tokens` | `16384` | Maximum tokens for the generated summary. |
|
||||
| `summary_temperature` | `0.3` | Randomness for summary generation. Lower is more deterministic. |
|
||||
| `model_thresholds` | `{}` | Per-model overrides for `compression_threshold_tokens` and `max_context_tokens` (useful for mixed models). |
|
||||
| `enable_tool_output_trimming` | `false` | When enabled and `function_calling: "native"` is active, trims verbose tool outputs to extract only the final answer. |
|
||||
| `debug_mode` | `false` | Log verbose debug info. Set to `false` in production. |
|
||||
| `show_debug_log` | `false` | Print debug logs to browser console (F12). Useful for frontend debugging. |
|
||||
| `show_token_usage_status` | `true` | Show token usage status notification in the chat interface. |
|
||||
| `token_usage_status_threshold` | `80` | The minimum usage percentage (0-100) required to show a context usage status notification. |
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Incoming Messages] --> B{Token Count > Threshold?}
|
||||
B -->|No| C[Pass Through]
|
||||
B -->|Yes| D[Summarize Older Messages]
|
||||
D --> E[Preserve Recent Messages]
|
||||
E --> F[Combine Summary + Recent]
|
||||
F --> G[Send to LLM]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⭐ Support
|
||||
## Configuration
|
||||
|
||||
If this plugin has been useful, a star on [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) is a big motivation for me. Thank you for the support.
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `compression_threshold_tokens` | integer | `64000` | Trigger compression above this token count |
|
||||
| `max_context_tokens` | integer | `128000` | Hard limit for context |
|
||||
| `keep_first` | integer | `1` | Always keep the first N messages |
|
||||
| `keep_last` | integer | `6` | Always keep the last N messages |
|
||||
| `summary_model` | string | `None` | Model to use for summarization |
|
||||
| `summary_model_max_context` | integer | `0` | Max context tokens for summary model |
|
||||
| `max_summary_tokens` | integer | `16384` | Maximum tokens for the summary |
|
||||
| `enable_tool_output_trimming` | boolean | `false` | Enable trimming of large tool outputs |
|
||||
|
||||
## Troubleshooting ❓
|
||||
---
|
||||
|
||||
- **Initial system prompt is lost**: Keep `keep_first` greater than 0 to protect the initial message.
|
||||
- **Compression effect is weak**: Raise `compression_threshold_tokens` or lower `keep_first` / `keep_last` to allow more aggressive compression.
|
||||
- **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [OpenWebUI Extensions Issues](https://github.com/Fu-Jie/openwebui-extensions/issues)
|
||||
## Example
|
||||
|
||||
## Changelog
|
||||
### Before Compression
|
||||
|
||||
See the full history on GitHub: [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||
```
|
||||
[Message 1] User: Tell me about Python...
|
||||
[Message 2] AI: Python is a programming language...
|
||||
[Message 3] User: What about its history?
|
||||
[Message 4] AI: Python was created by Guido...
|
||||
[Message 5] User: And its features?
|
||||
[Message 6] AI: Python has many features...
|
||||
... (many more messages)
|
||||
[Message 20] User: Current question
|
||||
```
|
||||
|
||||
### After Compression
|
||||
|
||||
```
|
||||
[Summary] Previous conversation covered Python basics,
|
||||
history, features, and common use cases...
|
||||
|
||||
[Message 18] User: Recent question about decorators
|
||||
[Message 19] AI: Decorators in Python are...
|
||||
[Message 20] User: Current question
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
!!! note "Prerequisites"
|
||||
- OpenWebUI v0.3.0 or later
|
||||
- Access to an LLM for summarization
|
||||
|
||||
!!! tip "Best Practices"
|
||||
- Set appropriate token thresholds based on your model's context window
|
||||
- Preserve more recent messages for technical discussions
|
||||
- Test compression settings in non-critical conversations first
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
??? question "Compression not triggering?"
|
||||
Check if the token count exceeds your configured threshold. Enable debug logging for more details.
|
||||
|
||||
??? question "Important context being lost?"
|
||||
Increase the `preserve_recent` setting or lower the compression ratio.
|
||||
|
||||
---
|
||||
|
||||
## Source Code
|
||||
|
||||
[:fontawesome-brands-github: View on GitHub](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/filters/async-context-compression){ .md-button }
|
||||
|
||||
@@ -1,119 +1,137 @@
|
||||
# 异步上下文压缩过滤器
|
||||
# Async Context Compression(异步上下文压缩)
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **版本:** 1.3.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
|
||||
<span class="category-badge filter">Filter</span>
|
||||
<span class="version-badge">v1.2.2</span>
|
||||
|
||||
> **重要提示**:为了确保所有过滤器的可维护性和易用性,每个过滤器都应附带清晰、完整的文档,以确保其功能、配置和使用方法得到充分说明。
|
||||
|
||||
本过滤器通过智能摘要和消息压缩技术,在保持对话连贯性的同时,显著降低长对话的 Token 消耗。
|
||||
|
||||
## 1.3.0 版本更新
|
||||
|
||||
- **国际化 (i18n) 支持**: 完成了所有用户可见消息的本地化,现已原生支持 9 种语言(含中、英、日、韩及欧洲主要语言)。
|
||||
- **智能状态显示**: 新增 `token_usage_status_threshold` 阀门(默认 80%),可以智能控制何时显示 Token 用量状态,减少不必要的打扰。
|
||||
- **性能大幅优化**: 对前端语言检测和日志处理流程进行了非阻塞重构,完全不影响首字节响应时间(TTFB),保持毫秒级极速推流。
|
||||
- **Copilot SDK 兼容**: 自动检测并跳过基于 `copilot_sdk` 模型的上下文压缩,避免冲突。
|
||||
- **配置项调整**: 为了提供更安静的生产环境体验,`debug_mode` 现已默认设置为 `false`。
|
||||
通过智能摘要减少长对话的 token 消耗,同时保持对话连贯。
|
||||
|
||||
---
|
||||
|
||||
## 核心特性
|
||||
## 概览
|
||||
|
||||
- ✅ **全方位国际化**: 原生支持 9 种界面语言。
|
||||
- ✅ **自动压缩**: 基于 Token 阈值自动触发上下文压缩。
|
||||
- ✅ **异步摘要**: 后台生成摘要,不阻塞当前对话响应。
|
||||
- ✅ **持久化存储**: 复用 Open WebUI 共享数据库连接,自动支持 PostgreSQL/SQLite 等。
|
||||
- ✅ **灵活保留策略**: 可配置保留对话头部和尾部消息,确保关键信息连贯。
|
||||
- ✅ **智能注入**: 将历史摘要智能注入到新上下文中。
|
||||
- ✅ **结构感知裁剪**: 智能折叠过长消息,保留文档骨架(标题、首尾)。
|
||||
- ✅ **原生工具输出裁剪**: 支持裁剪冗长的工具调用输出。
|
||||
- ✅ **实时监控**: 实时监控上下文使用情况,超过 90% 发出警告。
|
||||
- ✅ **详细日志**: 提供精确的 Token 统计日志,便于调试。
|
||||
- ✅ **智能模型匹配**: 自定义模型自动继承基础模型的阈值配置。
|
||||
- ⚠ **多模态支持**: 图片内容会被保留,但其 Token **不参与计算**。请相应调整阈值。
|
||||
Async Context Compression 过滤器通过以下方式帮助管理长对话的 token 使用:
|
||||
|
||||
详细的工作原理和流程请参考 [工作流程指南](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/filters/async-context-compression/WORKFLOW_GUIDE_CN.md)。
|
||||
- 智能总结较早的消息
|
||||
- 保留关键信息
|
||||
- 降低 API 成本
|
||||
- 保持对话一致性
|
||||
|
||||
特别适用于:
|
||||
|
||||
- 长时间会话
|
||||
- 多轮复杂讨论
|
||||
- 成本优化
|
||||
- 上下文长度控制
|
||||
|
||||
## 功能特性
|
||||
|
||||
- :material-arrow-collapse-vertical: **智能压缩**:AI 驱动的上下文摘要
|
||||
- :material-clock-fast: **异步处理**:后台非阻塞压缩
|
||||
- :material-memory: **保留上下文**:尽量保留重要信息
|
||||
- :material-currency-usd-off: **降低成本**:减少 token 使用
|
||||
- :material-console: **前端调试**:支持浏览器控制台日志
|
||||
- :material-alert-circle-check: **增强错误报告**:清晰的错误状态通知
|
||||
- :material-check-all: **Open WebUI v0.7.x 兼容性**:动态数据库会话处理
|
||||
- :material-account-convert: **兼容性提升**:摘要角色改为 `assistant`
|
||||
- :material-shield-check: **稳定性增强**:解决状态管理竞态条件
|
||||
- :material-ruler: **预检上下文检查**:发送前验证上下文是否超限
|
||||
- :material-format-align-justify: **结构感知裁剪**:保留文档结构的智能裁剪
|
||||
- :material-content-cut: **原生工具输出裁剪**:自动裁剪冗长的工具输出(注意:非原生工具调用输出不会完整注入上下文)
|
||||
- :material-chart-bar: **详细 Token 日志**:提供细粒度的 Token 统计
|
||||
- :material-account-search: **智能模型匹配**:自定义模型自动继承基础模型配置
|
||||
- :material-image-off: **多模态支持**:图片内容保留但 Token **不参与计算**
|
||||
|
||||
---
|
||||
|
||||
## 安装与配置
|
||||
## 安装
|
||||
|
||||
### 1. 数据库(自动)
|
||||
|
||||
- 自动使用 Open WebUI 的共享数据库连接,**无需额外配置**。
|
||||
- 首次运行自动创建 `chat_summary` 表。
|
||||
|
||||
### 2. 过滤器顺序
|
||||
|
||||
- 建议顺序:前置过滤器(<10)→ 本过滤器(10)→ 后置过滤器(>10)。
|
||||
1. 下载插件文件:[`async_context_compression.py`](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/filters/async-context-compression)
|
||||
2. 上传到 OpenWebUI:**Admin Panel** → **Settings** → **Functions**
|
||||
3. 配置压缩参数
|
||||
4. 启用过滤器
|
||||
|
||||
---
|
||||
|
||||
## 配置参数
|
||||
## 工作原理
|
||||
|
||||
您可以在过滤器的设置中调整以下参数:
|
||||
|
||||
### 核心参数
|
||||
|
||||
| 参数 | 默认值 | 描述 |
|
||||
| :----------------------------- | :------- | :------------------------------------------------------------------------------------ |
|
||||
| `priority` | `10` | 过滤器执行顺序,数值越小越先执行。 |
|
||||
| `compression_threshold_tokens` | `64000` | **重要**: 当上下文总 Token 超过此值时后台生成摘要,建议设为模型上下文窗口的 50%-70%。 |
|
||||
| `max_context_tokens` | `128000` | **重要**: 上下文硬上限,超过即移除最早消息(保留受保护消息)。 |
|
||||
| `keep_first` | `1` | 始终保留对话开始的 N 条消息,保护系统提示或环境变量。 |
|
||||
| `keep_last` | `6` | 始终保留对话末尾的 N 条消息,确保最近上下文连贯。 |
|
||||
|
||||
### 摘要生成配置
|
||||
|
||||
| 参数 | 默认值 | 描述 |
|
||||
| :-------------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `summary_model` | `None` | 用于生成摘要的模型 ID。**强烈建议**配置快速、经济、上下文窗口大的模型(如 `gemini-2.5-flash`、`deepseek-v3`)。留空则尝试复用当前对话模型。 |
|
||||
| `summary_model_max_context` | `0` | 摘要模型的最大上下文 Token 数。如果为 0,则回退到 `model_thresholds` 或全局 `max_context_tokens`。 |
|
||||
| `max_summary_tokens` | `16384` | 生成摘要时允许的最大 Token 数。 |
|
||||
| `summary_temperature` | `0.1` | 控制摘要生成的随机性,较低的值结果更稳定。 |
|
||||
|
||||
### 高级配置
|
||||
|
||||
#### `model_thresholds` (模型特定阈值)
|
||||
|
||||
这是一个字典配置,可为特定模型 ID 覆盖全局 `compression_threshold_tokens` 与 `max_context_tokens`,适用于混合不同上下文窗口的模型。
|
||||
|
||||
**默认包含 GPT-4、Claude 3.5、Gemini 1.5/2.0、Qwen 2.5/3、DeepSeek V3 等推荐阈值。**
|
||||
|
||||
**配置示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"gpt-4": {
|
||||
"compression_threshold_tokens": 8000,
|
||||
"max_context_tokens": 32000
|
||||
},
|
||||
"gemini-2.5-flash": {
|
||||
"compression_threshold_tokens": 734000,
|
||||
"max_context_tokens": 1048576
|
||||
}
|
||||
}
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Incoming Messages] --> B{Token Count > Threshold?}
|
||||
B -->|No| C[Pass Through]
|
||||
B -->|Yes| D[Summarize Older Messages]
|
||||
D --> E[Preserve Recent Messages]
|
||||
E --> F[Combine Summary + Recent]
|
||||
F --> G[Send to LLM]
|
||||
```
|
||||
|
||||
| 参数 | 默认值 | 描述 |
|
||||
| :----------------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `enable_tool_output_trimming` | `false` | 启用时,若 `function_calling: "native"` 激活,将裁剪冗长的工具输出以仅提取最终答案。 |
|
||||
| `debug_mode` | `false` | 是否在 Open WebUI 的控制台日志中打印详细的调试信息。生产环境默认且建议设为 `false`。 |
|
||||
| `show_debug_log` | `false` | 是否在浏览器控制台 (F12) 打印调试日志。便于前端调试。 |
|
||||
| `show_token_usage_status` | `true` | 是否在对话结束时显示 Token 使用情况的状态通知。 |
|
||||
| `token_usage_status_threshold` | `80` | 触发显示上下文用量状态通知的最低百分比阈值 (0-100)。 |
|
||||
---
|
||||
|
||||
## 配置项
|
||||
|
||||
| 选项 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|---------|-------------|
|
||||
| `compression_threshold_tokens` | integer | `64000` | 超过该 token 数触发压缩 |
|
||||
| `max_context_tokens` | integer | `128000` | 上下文硬性上限 |
|
||||
| `keep_first` | integer | `1` | 始终保留的前 N 条消息 |
|
||||
| `keep_last` | integer | `6` | 始终保留的后 N 条消息 |
|
||||
| `summary_model` | string | `None` | 用于摘要的模型 |
|
||||
| `summary_model_max_context` | integer | `0` | 摘要模型的最大上下文 Token 数 |
|
||||
| `max_summary_tokens` | integer | `16384` | 摘要的最大 token 数 |
|
||||
| `enable_tool_output_trimming` | boolean | `false` | 启用长工具输出裁剪 |
|
||||
|
||||
---
|
||||
|
||||
## ⭐ 支持
|
||||
## 示例
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
### 压缩前
|
||||
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
```
|
||||
[Message 1] User: Tell me about Python...
|
||||
[Message 2] AI: Python is a programming language...
|
||||
[Message 3] User: What about its history?
|
||||
[Message 4] AI: Python was created by Guido...
|
||||
[Message 5] User: And its features?
|
||||
[Message 6] AI: Python has many features...
|
||||
... (many more messages)
|
||||
[Message 20] User: Current question
|
||||
```
|
||||
|
||||
- **初始系统提示丢失**:将 `keep_first` 设置为大于 0。
|
||||
- **压缩效果不明显**:提高 `compression_threshold_tokens`,或降低 `keep_first` / `keep_last` 以增强压缩力度。
|
||||
- **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[OpenWebUI Extensions Issues](https://github.com/Fu-Jie/openwebui-extensions/issues)
|
||||
### 压缩后
|
||||
|
||||
## 更新日志
|
||||
```
|
||||
[Summary] Previous conversation covered Python basics,
|
||||
history, features, and common use cases...
|
||||
|
||||
完整历史请查看 GitHub 项目: [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||
[Message 18] User: Recent question about decorators
|
||||
[Message 19] AI: Decorators in Python are...
|
||||
[Message 20] User: Current question
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 运行要求
|
||||
|
||||
!!! note "前置条件"
|
||||
- OpenWebUI v0.3.0 及以上
|
||||
- 需要可用的 LLM 用于摘要
|
||||
|
||||
!!! tip "最佳实践"
|
||||
- 根据模型上下文窗口设置合适的 token 阈值
|
||||
- 技术讨论可适当提高 `preserve_recent`
|
||||
- 先在非关键对话中测试压缩效果
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
??? question "没有触发压缩?"
|
||||
检查 token 数是否超过配置的阈值,并开启调试日志了解细节。
|
||||
|
||||
??? question "重要上下文丢失?"
|
||||
提高 `preserve_recent` 或降低压缩比例。
|
||||
|
||||
---
|
||||
|
||||
## 源码
|
||||
|
||||
[:fontawesome-brands-github: 在 GitHub 查看](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/filters/async-context-compression){ .md-button }
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
# GitHub Copilot SDK Files Filter (v0.1.3)
|
||||
# GitHub Copilot SDK Files Filter (v0.1.2)
|
||||
|
||||
This is a dedicated **companion filter plugin** designed specifically for the [GitHub Copilot SDK Pipe](../pipes/github-copilot-sdk.md).
|
||||
|
||||
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.**
|
||||
|
||||
## ✨ v0.1.3 Updates (What's New)
|
||||
|
||||
- **🔍 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)
|
||||
- **🐛 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)
|
||||
|
||||
## 🎯 Why is this needed?
|
||||
|
||||
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.
|
||||
@@ -53,6 +48,6 @@ Default settings work for most users unless you have specific needs:
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
- **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`).
|
||||
- **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.
|
||||
- **Physical File Path**: Ensure the `OPENWEBUI_UPLOAD_PATH` is correctly set in the Pipe plugin Valves for the actual file transport to work.
|
||||
* **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`).
|
||||
* **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.
|
||||
* **Physical File Path**: Ensure the `OPENWEBUI_UPLOAD_PATH` is correctly set in the Pipe plugin Valves for the actual file transport to work.
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
# GitHub Copilot SDK 文件过滤器 (v0.1.3)
|
||||
# GitHub Copilot SDK 文件过滤器 (v0.1.2)
|
||||
|
||||
这是一个专门为 [GitHub Copilot SDK Pipe](../pipes/github-copilot-sdk.zh.md) 设计的**伴侣过滤器插件**。
|
||||
|
||||
它的核心使命是:**保护用户上传的文件不被 OpenWebUI 核心系统“抢先处理”,确保 Copilot Agent 能够接收到原始文件并进行自主分析。**
|
||||
|
||||
## ✨ 0.1.3 更新内容 (What's New)
|
||||
|
||||
- **🔍 BYOK 模型 ID 匹配修复**: 新增前缀匹配(`github_copilot_official_sdk_pipe.xxx` 格式),修复 BYOK 模型无法被正确识别的问题,关键词兜底保持向后兼容。(v0.1.3)
|
||||
- **🐛 双通道调试日志**: 新增 `show_debug_log` 配置项,启用后同时向后端日志和浏览器控制台(`console.group`)输出调试信息。(v0.1.3)
|
||||
|
||||
## 🎯 为什么需要它?
|
||||
|
||||
在 OpenWebUI 的默认流程中,当你上传一个文件(如 PDF、Excel、Python 脚本)时,OpenWebUI 会自动启动 **RAG(检索增强生成)** 流程:解析文件、向量化、提取文本并注入到提示词中。
|
||||
@@ -53,6 +48,6 @@
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
- **必须配合 Copilot SDK Pipe 使用**:如果你没有安装主 Pipe 插件,本插件将导致上传的文件“凭空消失”(因为没有后续插件去 `copilot_files` 里找它们)。
|
||||
- **Gemini Filter 兼容性**:本插件已完美兼容 Gemini 多模态过滤器。只要优先级设置正确(本插件 < Gemini 插件),它们可以共存互不干扰。
|
||||
- **物理文件路径**: 确保在 Pipe 插件的 Valves 中正确设置了 `OPENWEBUI_UPLOAD_PATH`,以便文件自动搬运功能正常工作。
|
||||
* **必须配合 Copilot SDK Pipe 使用**:如果你没有安装主 Pipe 插件,本插件将导致上传的文件“凭空消失”(因为没有后续插件去 `copilot_files` 里找它们)。
|
||||
* **Gemini Filter 兼容性**:本插件已完美兼容 Gemini 多模态过滤器。只要优先级设置正确(本插件 < Gemini 插件),它们可以共存互不干扰。
|
||||
* **物理文件路径**: 确保在 Pipe 插件的 Valves 中正确设置了 `OPENWEBUI_UPLOAD_PATH`,以便文件自动搬运功能正常工作。
|
||||
|
||||
@@ -22,7 +22,7 @@ Filters act as middleware in the message pipeline:
|
||||
|
||||
Reduces token consumption in long conversations through intelligent summarization while maintaining coherence.
|
||||
|
||||
**Version:** 1.3.0
|
||||
**Version:** 1.2.2
|
||||
|
||||
[:octicons-arrow-right-24: Documentation](async-context-compression.md)
|
||||
|
||||
@@ -52,7 +52,7 @@ Filters act as middleware in the message pipeline:
|
||||
|
||||
Fixes common Markdown formatting issues in LLM outputs, including Mermaid syntax, code blocks, and LaTeX formulas.
|
||||
|
||||
**Version:** 1.2.7
|
||||
**Version:** 1.2.4
|
||||
|
||||
[:octicons-arrow-right-24: Documentation](markdown_normalizer.md)
|
||||
|
||||
@@ -82,7 +82,7 @@ Filters act as middleware in the message pipeline:
|
||||
|
||||
A specialized filter to bypass OpenWebUI's default RAG for GitHub Copilot SDK models. It ensures the Agent receives raw files for autonomous analysis.
|
||||
|
||||
**Version:** 0.1.3
|
||||
**Version:** 0.1.2
|
||||
|
||||
[:octicons-arrow-right-24: Documentation](github-copilot-sdk-files-filter.md)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Filter 充当消息管线中的中间件:
|
||||
|
||||
通过智能总结减少长对话的 token 消耗,同时保持连贯性。
|
||||
|
||||
**版本:** 1.3.0
|
||||
**版本:** 1.2.2
|
||||
|
||||
[:octicons-arrow-right-24: 查看文档](async-context-compression.md)
|
||||
|
||||
@@ -52,7 +52,7 @@ Filter 充当消息管线中的中间件:
|
||||
|
||||
修复 LLM 输出中常见的 Markdown 格式问题,包括 Mermaid 语法、代码块和 LaTeX 公式。
|
||||
|
||||
**版本:** 1.2.7
|
||||
**版本:** 1.2.4
|
||||
|
||||
[:octicons-arrow-right-24: 查看文档](markdown_normalizer.zh.md)
|
||||
|
||||
@@ -62,7 +62,7 @@ Filter 充当消息管线中的中间件:
|
||||
|
||||
专门用于绕过 OpenWebUI 默认 RAG 机制的过滤器,针对 GitHub Copilot SDK 模型。确保 Agent 能够接收到原始文件进行自主分析。
|
||||
|
||||
**版本:** 0.1.3
|
||||
**版本:** 0.1.2
|
||||
|
||||
[:octicons-arrow-right-24: 查看文档](github-copilot-sdk-files-filter.zh.md)
|
||||
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
# Markdown Normalizer Filter
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **Version:** 1.2.7 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
|
||||
A content normalizer filter for Open WebUI that fixes common Markdown formatting issues in LLM outputs. It ensures that code blocks, LaTeX formulas, Mermaid diagrams, and other Markdown elements are rendered correctly.
|
||||
|
||||
## 🔥 What's New in v1.2.7
|
||||
|
||||
* **LaTeX Formula Protection**: Enhanced escape character cleaning to protect LaTeX commands like `\times`, `\nu`, and `\theta` from being corrupted.
|
||||
* **Expanded i18n Support**: Now supports 12 languages with automatic detection and fallback.
|
||||
* **Valves Optimization**: Optimized configuration descriptions to be English-only for better consistency.
|
||||
* **Bug Fixes**:
|
||||
* Resolved [Issue #49](https://github.com/Fu-Jie/openwebui-extensions/issues/49): Fixed a bug where consecutive bold parts on the same line caused spaces between them to be removed.
|
||||
* Fixed a `NameError` in the plugin code that caused test collection failures.
|
||||
|
||||
## 🌐 Multilingual Support
|
||||
|
||||
Supports automatic interface and status switching for the following languages:
|
||||
`English`, `简体中文`, `繁體中文 (香港)`, `繁體中文 (台灣)`, `한국어`, `日本語`, `Français`, `Deutsch`, `Español`, `Italiano`, `Tiếng Việt`, `Bahasa Indonesia`.
|
||||
|
||||
## ✨ Core Features
|
||||
## Features
|
||||
|
||||
* **Details Tag Normalization**: Ensures proper spacing for `<details>` tags (used for thought chains). Adds a blank line after `</details>` and ensures a newline after self-closing `<details />` tags to prevent rendering issues.
|
||||
* **Emphasis Spacing Fix**: Fixes extra spaces inside emphasis markers (e.g., `** text **` -> `**text**`) which can cause rendering failures. Includes safeguards to protect math expressions (e.g., `2 * 3 * 4`) and list variables.
|
||||
@@ -33,7 +17,7 @@ Supports automatic interface and status switching for the following languages:
|
||||
* **Table Fix**: Adds missing closing pipes in tables.
|
||||
* **XML Cleanup**: Removes leftover XML artifacts.
|
||||
|
||||
## How to Use 🛠️
|
||||
## Usage
|
||||
|
||||
1. Install the plugin in Open WebUI.
|
||||
2. Enable the filter globally or for specific models.
|
||||
@@ -42,38 +26,73 @@ Supports automatic interface and status switching for the following languages:
|
||||
> [!WARNING]
|
||||
> As this is an initial version, some "negative fixes" might occur (e.g., breaking valid Markdown). If you encounter issues, please check the console logs, copy the "Original" vs "Normalized" content, and submit an issue.
|
||||
|
||||
## Configuration (Valves) ⚙️
|
||||
## Configuration (Valves)
|
||||
|
||||
| Parameter | Default | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `priority` | `50` | Filter priority. Higher runs later (recommended after other filters). |
|
||||
| `enable_escape_fix` | `True` | Fix excessive escape characters (`\n`, `\t`, etc.). |
|
||||
| `enable_escape_fix_in_code_blocks` | `False` | Apply escape fix inside code blocks (may affect valid code). |
|
||||
| `enable_thought_tag_fix` | `True` | Normalize thought tags (`</thought>`). |
|
||||
| `enable_details_tag_fix` | `True` | Normalize `<details>` tags and add safe spacing. |
|
||||
| `enable_code_block_fix` | `True` | Fix code block formatting (indentation/newlines). |
|
||||
| `enable_latex_fix` | `True` | Normalize LaTeX delimiters (`\[` -> `$$`, `\(` -> `$`). |
|
||||
| `enable_list_fix` | `False` | Fix list item newlines (experimental). |
|
||||
| `enable_unclosed_block_fix` | `True` | Auto-close unclosed code blocks. |
|
||||
| `enable_fullwidth_symbol_fix` | `False` | Fix full-width symbols in code blocks. |
|
||||
| `enable_mermaid_fix` | `True` | Fix common Mermaid syntax errors. |
|
||||
| `enable_heading_fix` | `True` | Fix missing space in headings. |
|
||||
| `enable_table_fix` | `True` | Fix missing closing pipe in tables. |
|
||||
| `enable_xml_tag_cleanup` | `True` | Cleanup leftover XML tags. |
|
||||
| `enable_emphasis_spacing_fix` | `False` | Fix extra spaces in emphasis. |
|
||||
| `show_status` | `True` | Show status notification when fixes are applied. |
|
||||
| `show_debug_log` | `True` | Print debug logs to browser console (F12). |
|
||||
* `priority`: Filter priority (default: 50).
|
||||
* `enable_escape_fix`: Fix excessive escape characters.
|
||||
* `enable_thought_tag_fix`: Normalize thought tags.
|
||||
* `enable_details_tag_fix`: Normalize details tags (default: True).
|
||||
* `enable_code_block_fix`: Fix code block formatting.
|
||||
* `enable_latex_fix`: Normalize LaTeX formulas.
|
||||
* `enable_list_fix`: Fix list item newlines (Experimental).
|
||||
* `enable_unclosed_block_fix`: Auto-close unclosed code blocks.
|
||||
* `enable_fullwidth_symbol_fix`: Fix full-width symbols in code blocks.
|
||||
* `enable_mermaid_fix`: Fix Mermaid syntax errors.
|
||||
* `enable_heading_fix`: Fix missing space in headings.
|
||||
* `enable_table_fix`: Fix missing closing pipe in tables.
|
||||
* `enable_xml_tag_cleanup`: Cleanup leftover XML tags.
|
||||
* `enable_emphasis_spacing_fix`: Fix extra spaces in emphasis (default: True).
|
||||
* `show_status`: Show status notification when fixes are applied.
|
||||
* `show_debug_log`: Print debug logs to browser console.
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
If this plugin has been useful, a star on [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) is a big motivation for me. Thank you for the support.
|
||||
|
||||
## 🧩 Others
|
||||
|
||||
### Troubleshooting ❓
|
||||
## Troubleshooting ❓
|
||||
|
||||
* **Submit an Issue**: If you encounter any problems, please submit an issue on GitHub: [OpenWebUI Extensions Issues](https://github.com/Fu-Jie/openwebui-extensions/issues)
|
||||
|
||||
### Changelog
|
||||
## Changelog
|
||||
|
||||
See the full history on GitHub: [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||
### v1.2.4
|
||||
|
||||
* **Documentation Updates**: Synchronized version numbers across all documentation and code files.
|
||||
|
||||
### v1.2.3
|
||||
|
||||
* **List Marker Protection Enhancement**: Fixed a bug where list markers (`*`) followed by plain text and emphasis were having their spaces incorrectly stripped (e.g., `* U16 forward` became `*U16 forward`).
|
||||
* **Placeholder Support**: Confirmed that 4 or more underscores (e.g., `____`) are correctly treated as placeholders and not modified by the emphasis fix.
|
||||
|
||||
### v1.2.2
|
||||
|
||||
* **Code Block Indentation Fix**: Fixed an issue where code blocks nested inside lists were having their indentation incorrectly stripped. Now preserves proper indentation for nested code blocks.
|
||||
* **Underscore Emphasis Support**: Extended emphasis spacing fix to support `__` (double underscore for bold) and `___` (triple underscore for bold+italic) syntax.
|
||||
* **List Marker Protection**: Fixed a bug where list markers (`*`) followed by emphasis markers (`**`) were incorrectly merged (e.g., `* **Yes**` became `***Yes**`). Added safeguard to prevent this.
|
||||
* **Test Suite**: Added comprehensive pytest test suite with 56 test cases covering all major features.
|
||||
|
||||
### v1.2.1
|
||||
|
||||
* **Emphasis Spacing Fix**: Added a new fix for extra spaces inside emphasis markers (e.g., `** text **` -> `**text**`).
|
||||
* Uses a recursive approach to handle nested emphasis (e.g., `**bold _italic _**`).
|
||||
* Includes safeguards to prevent modifying math expressions (e.g., `2 * 3 * 4`) or list variables.
|
||||
* Controlled by the `enable_emphasis_spacing_fix` valve (default: True).
|
||||
|
||||
### v1.2.0
|
||||
|
||||
* **Details Tag Support**: Added normalization for `<details>` tags.
|
||||
* Ensures a blank line is added after `</details>` closing tags to separate thought content from the main response.
|
||||
* Ensures a newline is added after self-closing `<details ... />` tags to prevent them from interfering with subsequent Markdown headings (e.g., fixing `<details/>#Heading`).
|
||||
* Includes safeguard to prevent modification of `<details>` tags inside code blocks.
|
||||
|
||||
### v1.1.2
|
||||
|
||||
* **Mermaid Edge Label Protection**: Implemented comprehensive protection for edge labels (text on connecting lines) to prevent them from being incorrectly modified. Now supports all Mermaid link types including solid (`--`), dotted (`-.`), and thick (`==`) lines with or without arrows.
|
||||
* **Bug Fixes**: Fixed an issue where lines without arrows (e.g., `A -- text --- B`) were not correctly protected.
|
||||
|
||||
### v1.1.0
|
||||
|
||||
* **Mermaid Fix Refinement**: Improved regex to handle nested parentheses in node labels (e.g., `ID("Label (text)")`) and avoided matching connection labels.
|
||||
* **HTML Safeguard Optimization**: Refined `_contains_html` to allow common tags like `<br/>`, `<b>`, `<i>`, etc., ensuring Mermaid diagrams with these tags are still normalized.
|
||||
* **Full-width Symbol Cleanup**: Fixed duplicate keys and incorrect quote mapping in `FULLWIDTH_MAP`.
|
||||
* **Bug Fixes**: Fixed missing `Dict` import in Python files.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
@@ -1,24 +1,8 @@
|
||||
# Markdown 格式化过滤器 (Markdown Normalizer)
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **Version:** 1.2.7 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
|
||||
|
||||
这是一个用于 Open WebUI 的内容格式化过滤器,旨在修复 LLM 输出中常见的 Markdown 格式问题。它能确保代码块、LaTeX 公式、Mermaid 图表和其他 Markdown 元素被正确渲染。
|
||||
|
||||
## 🔥 最新更新 v1.2.7
|
||||
|
||||
* **LaTeX 公式保护**: 增强了转义字符清理逻辑,自动保护 `$ $` 或 `$$ $$` 内的 LaTeX 命令(如 `\times`、`\nu`、`\theta`),防止渲染失效。
|
||||
* **扩展国际化 (i18n) 支持**: 现已支持 12 种语言,具备自动探测与回退机制。
|
||||
* **配置项优化**: 将 Valves 配置项的描述统一为英文,保持界面一致性。
|
||||
* **修复 Bug**:
|
||||
* 修复了 [Issue #49](https://github.com/Fu-Jie/openwebui-extensions/issues/49):解决了当同一行存在多个加粗部分时,由于正则匹配过于贪婪导致中间内容丢失空格的问题。
|
||||
* 修复了插件代码中的 `NameError` 错误,确保测试脚本能正常运行。
|
||||
|
||||
## 🌐 多语言支持 (i18n)
|
||||
|
||||
支持以下语言的界面与状态自动切换:
|
||||
`English`, `简体中文`, `繁體中文 (香港)`, `繁體中文 (台灣)`, `한국어`, `日本語`, `Français`, `Deutsch`, `Español`, `Italiano`, `Tiếng Việt`, `Bahasa Indonesia`
|
||||
|
||||
## ✨ 核心特性
|
||||
## 功能特性
|
||||
|
||||
* **Details 标签规范化**: 确保 `<details>` 标签(常用于思维链)有正确的间距。在 `</details>` 后添加空行,并在自闭合 `<details />` 标签后添加换行,防止渲染问题。
|
||||
* **强调空格修复**: 修复强调标记内部的多余空格(例如 `** 文本 **` -> `**文本**`),这会导致 Markdown 渲染失败。包含保护机制,防止误修改数学表达式(如 `2 * 3 * 4`)或列表变量。
|
||||
@@ -40,40 +24,75 @@
|
||||
3. 在 **Valves** 设置中配置需要启用的修复项。
|
||||
4. (可选) **显示调试日志 (Show Debug Log)** 在 Valves 中默认开启。这会将结构化的日志打印到浏览器控制台 (F12)。
|
||||
> [!WARNING]
|
||||
> 由于这是初版,可能会出现“负向修复”的情况(例如破坏了原本正确的格式)。如果您遇到问题,请务目查看控制台日志,复制“原始 (Original)”与“规范化 (Normalized)”的内容对比,并提交 Issue 反馈。
|
||||
> 由于这是初版,可能会出现“负向修复”的情况(例如破坏了原本正确的格式)。如果您遇到问题,请务必查看控制台日志,复制“原始 (Original)”与“规范化 (Normalized)”的内容对比,并提交 Issue 反馈。
|
||||
|
||||
## 配置参数 (Valves) ⚙️
|
||||
## 配置项 (Valves)
|
||||
|
||||
| 参数 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- |
|
||||
| `priority` | `50` | 过滤器优先级。数值越大越靠后(建议在其他过滤器之后运行)。 |
|
||||
| `enable_escape_fix` | `True` | 修复过度的转义字符(`\n`, `\t` 等)。 |
|
||||
| `enable_escape_fix_in_code_blocks` | `False` | 在代码块内应用转义修复(可能影响有效代码)。 |
|
||||
| `enable_thought_tag_fix` | `True` | 规范化思维标签(`</thought>`)。 |
|
||||
| `enable_details_tag_fix` | `True` | 规范化 `<details>` 标签并添加安全间距。 |
|
||||
| `enable_code_block_fix` | `True` | 修复代码块格式(缩进/换行)。 |
|
||||
| `enable_latex_fix` | `True` | 规范化 LaTeX 定界符(`\[` -> `$$`, `\(` -> `$`)。 |
|
||||
| `enable_list_fix` | `False` | 修复列表项换行(实验性)。 |
|
||||
| `enable_unclosed_block_fix` | `True` | 自动闭合未闭合的代码块。 |
|
||||
| `enable_fullwidth_symbol_fix` | `False` | 修复代码块中的全角符号。 |
|
||||
| `enable_mermaid_fix` | `True` | 修复常见 Mermaid 语法错误。 |
|
||||
| `enable_heading_fix` | `True` | 修复标题中缺失的空格。 |
|
||||
| `enable_table_fix` | `True` | 修复表格中缺失的闭合管道符。 |
|
||||
| `enable_xml_tag_cleanup` | `True` | 清理残留的 XML 标签。 |
|
||||
| `enable_emphasis_spacing_fix` | `False` | 修复强调语法中的多余空格。 |
|
||||
| `show_status` | `True` | 应用修复时显示状态通知。 |
|
||||
| `show_debug_log` | `True` | 在浏览器控制台打印调试日志。 |
|
||||
* `priority`: 过滤器优先级 (默认: 50)。
|
||||
* `enable_escape_fix`: 修复过度的转义字符。
|
||||
* `enable_thought_tag_fix`: 规范化思维标签。
|
||||
* `enable_details_tag_fix`: 规范化 Details 标签 (默认: True)。
|
||||
* `enable_code_block_fix`: 修复代码块格式。
|
||||
* `enable_latex_fix`: 规范化 LaTeX 公式。
|
||||
* `enable_list_fix`: 修复列表项换行 (实验性)。
|
||||
* `enable_unclosed_block_fix`: 自动闭合未闭合的代码块。
|
||||
* `enable_fullwidth_symbol_fix`: 修复代码块中的全角符号。
|
||||
* `enable_mermaid_fix`: 修复 Mermaid 语法错误。
|
||||
* `enable_heading_fix`: 修复标题中缺失的空格。
|
||||
* `enable_table_fix`: 修复表格中缺失的闭合管道符。
|
||||
* `enable_xml_tag_cleanup`: 清理残留的 XML 标签。
|
||||
* `enable_emphasis_spacing_fix`: 修复强调语法中的多余空格 (默认: True)。
|
||||
* `show_status`: 应用修复时显示状态通知。
|
||||
* `show_debug_log`: 在浏览器控制台打印调试日志。
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
如果这个插件对你有帮助,欢迎到 [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) 点个 Star,这将是我持续改进的动力,感谢支持。
|
||||
|
||||
## 其他
|
||||
|
||||
### 故障排除 (Troubleshooting) ❓
|
||||
## 故障排除 (Troubleshooting) ❓
|
||||
|
||||
* **提交 Issue**: 如果遇到任何问题,请在 GitHub 上提交 Issue:[OpenWebUI Extensions Issues](https://github.com/Fu-Jie/openwebui-extensions/issues)
|
||||
|
||||
### 更新日志
|
||||
## 更新日志
|
||||
|
||||
完整历史请查看 GitHub 项目: [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||
### v1.2.4
|
||||
|
||||
* **文档更新**: 同步了所有文档和代码文件的版本号。
|
||||
|
||||
### v1.2.3
|
||||
|
||||
* **列表标记保护增强**: 修复了列表标记 (`*`) 后跟普通文本和强调标记时,空格被错误剥离的问题(例如 `* U16 前锋` 变成 `*U16 前锋`)。
|
||||
* **占位符支持**: 确认 4 个或更多下划线(如 `____`)会被正确视为占位符,不会被强调修复逻辑修改。
|
||||
|
||||
### v1.2.2
|
||||
|
||||
* **代码块缩进修复**: 修复了列表中嵌套代码块的缩进被错误剥离的问题。现在会正确保留嵌套代码块的缩进。
|
||||
* **下划线强调语法支持**: 扩展强调空格修复以支持 `__` (双下划线加粗) 和 `___` (三下划线加粗斜体) 语法。
|
||||
* **列表标记保护**: 修复了列表标记 (`*`) 后跟强调标记 (`**`) 被错误合并的 Bug(例如 `* **是**` 变成 `***是**`)。添加了保护逻辑防止此问题。
|
||||
* **测试套件**: 新增完整的 pytest 测试套件,包含 56 个测试用例,覆盖所有主要功能。
|
||||
|
||||
### v1.2.1
|
||||
|
||||
* **强调空格修复**: 新增了对强调标记内部多余空格的修复(例如 `** 文本 **` -> `**文本**`)。
|
||||
* 采用递归方法处理嵌套强调(例如 `**加粗 _斜体 _**`)。
|
||||
* 包含保护机制,防止误修改数学表达式(如 `2 * 3 * 4`)或列表变量。
|
||||
* 通过 `enable_emphasis_spacing_fix` 开关控制(默认:开启)。
|
||||
|
||||
### v1.2.0
|
||||
|
||||
* **Details 标签支持**: 新增了对 `<details>` 标签的规范化支持。
|
||||
* 确保在 `</details>` 闭合标签后添加空行,将思维内容与正文分隔开。
|
||||
* 确保在自闭合 `<details ... />` 标签后添加换行,防止其干扰后续的 Markdown 标题(例如修复 `<details/>#标题`)。
|
||||
* 包含保护机制,防止修改代码块内部的 `<details>` 标签。
|
||||
|
||||
### v1.1.2
|
||||
|
||||
* **Mermaid 连线标签保护**: 实现了全面的连线标签保护机制,防止连接线上的文字被误修改。现在支持所有 Mermaid 连线类型,包括实线 (`--`)、虚线 (`-.`) 和粗线 (`==`),无论是否带有箭头。
|
||||
* **Bug 修复**: 修复了无箭头连线(如 `A -- text --- B`)未被正确保护的问题。
|
||||
|
||||
### v1.1.0
|
||||
|
||||
* **Mermaid 修复优化**: 改进了正则表达式以处理节点标签中的嵌套括号(如 `ID("标签 (文本)")`),并避免误匹配连接线上的文字。
|
||||
* **HTML 保护机制优化**: 优化了 `_contains_html` 检测,允许 `<br/>`, `<b>`, `<i>` 等常见标签,确保包含这些标签的 Mermaid 图表能被正常规范化。
|
||||
* **全角符号清理**: 修复了 `FULLWIDTH_MAP` 中的重复键名和错误的引号映射。
|
||||
* **Bug 修复**: 修复了 Python 文件中缺失的 `Dict` 类型导入。
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# GitHub Copilot SDK Pipe for OpenWebUI
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 0.8.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 0.6.2 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **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,23 +14,12 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
|
||||
|
||||
---
|
||||
|
||||
## ✨ v0.8.0 Updates (What's New)
|
||||
## ✨ v0.6.2 Updates (What's New)
|
||||
|
||||
- **🎛️ Conditional Tool Filtering (P1~P4)**: Four-priority tool permission system. **Default ON**: If no tools are selected in Chat UI (P4), all enabled tools are active. **Whitelist Mode**: Once specific tools are checked, the whitelist strictly filters both OpenWebUI tools and MCP servers. Admin-level `config.enable` (P2) allows global server disabling. (v0.8.0)
|
||||
- **🔧 File Publish Reliability**: Fixed `Error getting file content` across all storage backends (local/S3/GCS/Azure) by using `Storage.upload_file()` directly in the fallback path. HTML files are no longer blocked by `ALLOWED_FILE_EXTENSIONS` (`?process=false` always applied). (v0.8.0)
|
||||
- **🌐 HTML Direct Access Link**: When `publish_file_from_workspace` publishes an HTML file, the plugin also provides a directly accessible HTML link for instant in-chat preview/opening. (v0.8.0)
|
||||
- **🔒 Strict File URL Format**: Published file links must be relative paths starting with `/api/v1/files/` (e.g., `/api/v1/files/{id}/content/html`). Do not use `api/...` and do not prepend any domain. (v0.8.0)
|
||||
- **🛠️ CLI Built-in Tools Always Available**: `available_tools` is now always `None`, ensuring Copilot CLI built-ins (e.g. `bash`, `create_file`) are never silently blocked regardless of MCP configuration. (v0.8.0)
|
||||
- **📌 Publish Tool Always Injected**: `publish_file_from_workspace` is no longer lost when `ENABLE_OPENWEBUI_TOOLS` is disabled. (v0.8.0)
|
||||
- **⚠️ Code Interpreter Limitation**: The `code_interpreter` tool runs in a remote, ephemeral environment. A system prompt warning now clarifies that it cannot access local files or persist changes. (v0.8.0)
|
||||
|
||||
### 🐞 Bug Fixes in v0.8.0
|
||||
|
||||
- Fixed `{"detail":"[ERROR: Error getting file content]"}` when publishing files under object storage backends by replacing fallback manual copy/DB writes with `Storage.upload_file()`.
|
||||
- Fixed HTML artifact upload being rejected by `ALLOWED_FILE_EXTENSIONS` by always appending `?process=false` on file upload API calls.
|
||||
- Fixed invalid artifact links generated as `api/...` or domain-prefixed absolute URLs; links are now constrained to `/api/v1/files/...` relative paths.
|
||||
- Fixed Copilot CLI built-ins being silently unavailable when no server tools were configured/loaded (which resulted in `available_tools=[]`); now `available_tools` remains `None`.
|
||||
- Fixed `publish_file_from_workspace` disappearing when `ENABLE_OPENWEBUI_TOOLS` was disabled.
|
||||
- **🛠️ 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -42,24 +31,12 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
|
||||
- **♾️ Infinite Session Management**: Smart context window management with automatic compaction for indefinite conversation capability.
|
||||
- **🧠 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 (bypasses RAG for direct binary access).
|
||||
- **📤 Workspace Artifacts (`publish_file_from_workspace`)**: Agents can generate files (Excel, CSV, HTML reports, etc.) and provide **persistent download links** directly in the chat. For HTML files, a direct-access HTML link is also provided.
|
||||
- **🖼️ Intelligent Multimodal**: Vision capabilities and raw file analysis support.
|
||||
- **⚡ Full-Lifecycle File Agent**: Supports receiving uploaded files for raw bypass analysis and publishing results (Excel/reports) as downloadable links.
|
||||
- **🖼️ Interactive Artifacts**: Automatically renders HTML/JS apps generated by the agent directly in the chat interface.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 Companion Files Filter (Required for raw files)
|
||||
|
||||
`GitHub Copilot SDK Files Filter` is the companion plugin that prevents OpenWebUI's default RAG pre-processing from consuming uploaded files before the Pipe receives them.
|
||||
|
||||
- **What it does**: Moves uploaded files to `copilot_files` so the Pipe can access raw binaries directly.
|
||||
- **Why it matters**: Without it, uploaded files may be parsed/vectorized early and the Agent may lose direct raw-file access.
|
||||
- **v0.1.3 highlights**:
|
||||
- BYOK model-id matching fix (supports `github_copilot_official_sdk_pipe.xxx` prefixes).
|
||||
- Optional dual-channel debug log (`show_debug_log`) to backend logger + browser console.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Core Configuration (Valves)
|
||||
|
||||
### 1. Administrator Settings (Base)
|
||||
@@ -127,22 +104,13 @@ If this plugin has been useful, a **Star** on [OpenWebUI Extensions](https://git
|
||||
2. Create **Fine-grained token**, granting **Account permissions** -> **Copilot Requests** access.
|
||||
3. Paste the generated Token into the `GH_TOKEN` field in Valves.
|
||||
|
||||
### 3) Authentication Requirement (Mandatory)
|
||||
|
||||
You MUST configure **at least one** credential source:
|
||||
|
||||
- `GH_TOKEN` (GitHub Copilot subscription route), or
|
||||
- `BYOK_API_KEY` (OpenAI/Anthropic route).
|
||||
|
||||
If neither is configured, the model list will not appear.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Troubleshooting & Dependencies
|
||||
|
||||
- **Agent ignores files?**: Ensure the Files Filter is enabled, otherwise RAG will interfere with raw binaries.
|
||||
- **No progress bar?**: The bar only appears when the Agent uses the `update_todo` tool.
|
||||
- **Dependencies**: This Pipe automatically manages `github-copilot-sdk` (Python) and utilizes the bundled binary CLI. No manual install required.
|
||||
- **Dependencies**: This Pipe automatically installs `github-copilot-sdk` (Python) and `github-copilot-cli` (Binary).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# GitHub Copilot SDK 官方管道
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 0.8.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 0.6.2 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** 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,23 +14,12 @@
|
||||
|
||||
---
|
||||
|
||||
## ✨ 0.8.0 更新内容 (What's New)
|
||||
## ✨ 0.6.2 更新内容 (What's New)
|
||||
|
||||
- **🎛️ 条件工具过滤 (P1~P4)**: 四优先级工具权限体系。**默认全开**: 若未在 Chat UI (P4) 勾选任何工具,则默认启用所有工具;**白名单模式**: 一旦勾选特定工具,即刻进入严格过滤模式,且 MCP server 同步受控;管理员亦可通过 `config.enable` (P2) 全局禁用工具服务器。(v0.8.0)
|
||||
- **🔧 文件发布全面修复**: 通过在回退路径直接调用 `Storage.upload_file()`,彻底修复了所有存储后端(local/S3/GCS/Azure)下的 `Error getting file content` 问题;同时上传时自动携带 `?process=false`,HTML 文件不再被 `ALLOWED_FILE_EXTENSIONS` 拦截。(v0.8.0)
|
||||
- **🌐 HTML 直达链接**: 当 `publish_file_from_workspace` 发布的是 HTML 文件时,插件会额外提供可直接访问的 HTML 链接,便于在聊天中即时预览/打开。(v0.8.0)
|
||||
- **🔒 文件链接格式严格约束**: 发布链接必须是以 `/api/v1/files/` 开头的相对路径(例如 `/api/v1/files/{id}/content/html`)。禁止使用 `api/...`,也禁止拼接任何域名。(v0.8.0)
|
||||
- **🛠️ CLI 内置工具始终可用**: `available_tools` 统一设为 `None`,Copilot CLI 内置工具(如 `bash`、`create_file`)无论 MCP 配置如何都不会被静默屏蔽。(v0.8.0)
|
||||
- **📌 发布工具始终注入**: 即使 `ENABLE_OPENWEBUI_TOOLS` 关闭,`publish_file_from_workspace` 工具也不再丢失。(v0.8.0)
|
||||
- **⚠️ 代码解释器限制**: `code_interpreter` 工具运行在远程临时环境中。系统提示词现已包含警告,明确指出该工具无法访问本地文件或持久化更改。(v0.8.0)
|
||||
|
||||
### 🐞 v0.8.0 Bug 修复说明
|
||||
|
||||
- 修复了对象存储后端发布文件时出现的 `{"detail":"[ERROR: Error getting file content]"}`,回退路径从手动复制/写库改为 `Storage.upload_file()`。
|
||||
- 修复了 HTML 产物被 `ALLOWED_FILE_EXTENSIONS` 拦截的问题,上传接口统一追加 `?process=false`。
|
||||
- 修复了产物链接偶发被生成成 `api/...` 或带域名绝对 URL 的问题,现统一限制为 `/api/v1/files/...` 相对路径。
|
||||
- 修复了在未配置/未加载任何 server 工具时(最终出现 `available_tools=[]`)Copilot CLI 内置工具被静默禁用的问题,现统一保持 `available_tools=None`。
|
||||
- 修复了 `ENABLE_OPENWEBUI_TOOLS` 关闭时 `publish_file_from_workspace` 工具丢失的问题。
|
||||
- **🛠️ 新增工作区产物工具**: 引入 `publish_file_from_workspace`。Agent 现在可以生成物理文件(如使用 Python 生成的 Excel/CSV 报表),并直接在聊天界面提供点击下载链接。
|
||||
- **⚙️ 工作流优化**: 提升了内部 Agent 物理工作区管理的可靠性与原子性。
|
||||
- **🛡️ 安全增强**: 精细化了隔离环境下系统资源的访问控制策略。
|
||||
- **🔧 性能微调**: 针对大上下文窗口优化了流式数据处理性能。
|
||||
|
||||
---
|
||||
|
||||
@@ -42,24 +31,12 @@
|
||||
- **♾️ 无限会话管理**: 智能上下文窗口管理与自动压缩算法,支持无限时长的对话交互。
|
||||
- **🧠 深度数据库集成**: 实时持久化 TOD·O 列表到 UI 进度条。
|
||||
- **🌊 深度推理展示**: 完整支持模型思考过程 (Thinking Process) 的流式渲染。
|
||||
- **🖼️ 智能多模态**: 完整支持图像识别与附件上传分析(绕过 RAG 直接访问原始二进制内容)。
|
||||
- **📤 工作区产物工具 (`publish_file_from_workspace`)**: Agent 可生成文件(Excel、CSV、HTML 报告等)并直接提供**持久化下载链接**。管理员还可额外获得通过 `/content/html` 接口的**聊天内 HTML 预览**链接。
|
||||
- **🖼️ 智能多模态**: 完整支持图像识别与附件上传分析。
|
||||
- **⚡ 全生命周期文件 Agent**: 支持接收上传文件进行绕过 RAG 的深度分析,并将处理结果(如 Excel/报告)发布为下载链接实现闭环。
|
||||
- **🖼️ 交互式伪影 (Artifacts)**: 自动渲染 Agent 生成的 HTML/JS 应用程序,直接在聊天界面交互。
|
||||
|
||||
---
|
||||
|
||||
## 🧩 配套 Files Filter(原始文件必备)
|
||||
|
||||
`GitHub Copilot SDK Files Filter` 是本 Pipe 的配套插件,用于阻止 OpenWebUI 默认 RAG 在 Pipe 接手前抢先处理上传文件。
|
||||
|
||||
- **作用**: 将上传文件移动到 `copilot_files`,让 Pipe 能直接读取原始二进制。
|
||||
- **必要性**: 若未安装,文件可能被提前解析/向量化,Agent 难以拿到原始文件。
|
||||
- **v0.1.3 重点**:
|
||||
- 修复 BYOK 模型 ID 识别(支持 `github_copilot_official_sdk_pipe.xxx` 前缀匹配)。
|
||||
- 新增双通道调试日志(`show_debug_log`):后端 logger + 浏览器控制台。
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 核心配置参数 (Valves)
|
||||
|
||||
### 1. 管理员配置 (基础设置)
|
||||
@@ -118,7 +95,7 @@
|
||||
### 1) 导入函数
|
||||
|
||||
1. 打开 OpenWebUI,前往 **工作区** -> **函数**。
|
||||
2. 点击 **+** (创建函数),完整粘贴 `github_copilot_sdk.py` 的内容。
|
||||
2. 点击 **+** (创建函数),完整粘贴 `github_copilot_sdk_cn.py` 的内容。
|
||||
3. 点击保存并确保已启用。
|
||||
|
||||
### 2) 获取 Token (Get Token)
|
||||
@@ -127,22 +104,13 @@
|
||||
2. 创建 **Fine-grained token**,授予 **Account permissions** -> **Copilot Requests** 访问权限。
|
||||
3. 将生成的 Token 填入插件的 `GH_TOKEN` 配置项中。
|
||||
|
||||
### 3) 认证配置要求(必填)
|
||||
|
||||
你必须至少配置以下一种凭据:
|
||||
|
||||
- `GH_TOKEN`(GitHub Copilot 官方订阅路径),或
|
||||
- `BYOK_API_KEY`(OpenAI/Anthropic 自带 Key 路径)。
|
||||
|
||||
如果两者都未配置,模型列表将不会出现。
|
||||
|
||||
---
|
||||
|
||||
## 📋 常见问题与依赖 (Troubleshooting)
|
||||
|
||||
- **Agent 无法识别文件?**: 请确保已安装并启用了 Files Filter 插件,否则原始文件会被 RAG 干扰。
|
||||
- **看不到 TODO 进度条?**: 进度条仅在 Agent 使用 `update_todo` 工具(通常是处理复杂任务)时出现。
|
||||
- **依赖安装**: 本管道会自动管理 `github-copilot-sdk` (Python 包) 并优先直接使用内置的二进制 CLI,无需手动干预。
|
||||
- **依赖安装**: 本管道会自动尝试安装 `github-copilot-sdk` (Python 包) 和 `github-copilot-cli` (官方二进制)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Pipes allow you to:
|
||||
|
||||
## Available Pipe Plugins
|
||||
|
||||
- [GitHub Copilot SDK](github-copilot-sdk.md) (v0.8.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. [View Deep Dive](github-copilot-sdk-deep-dive.md) | [**View Advanced Tutorial**](github-copilot-sdk-tutorial.md).
|
||||
- [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 Deep Dive](github-copilot-sdk-deep-dive.md) | [**View Advanced Tutorial**](github-copilot-sdk-tutorial.md).
|
||||
- **[Case Study: GitHub 100 Star Growth Analysis](star-prediction-example.md)** - Learn how to use the GitHub Copilot SDK Pipe with Minimax 2.1 to automatically analyze CSV data and generate project growth reports.
|
||||
- **[Case Study: High-Quality Video to GIF Conversion](video-processing-example.md)** - See how the model uses system-level FFmpeg to accelerate, scale, and optimize colors for screen recordings.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Pipes 可以用于:
|
||||
|
||||
## 可用的 Pipe 插件
|
||||
|
||||
- [GitHub Copilot SDK](github-copilot-sdk.zh.md) (v0.8.0) - GitHub Copilot SDK 官方集成。具备**工作区安全隔离**、**数据库持久化**、**零配置工具桥接**与**BYOK (自带 Key) 支持**。支持流式输出、打字机思考过程及无限会话。[查看深度架构解析](github-copilot-sdk-deep-dive.zh.md) | [**查看进阶实战教程**](github-copilot-sdk-tutorial.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) | [**查看进阶实战教程**](github-copilot-sdk-tutorial.zh.md)。
|
||||
- **[实战案例:GitHub 100 Star 增长预测](star-prediction-example.zh.md)** - 展示如何使用 GitHub Copilot SDK Pipe 结合 Minimax 2.1 模型,自动编写脚本分析 CSV 数据并生成详细的项目增长报告。
|
||||
- **[实战案例:视频高质量 GIF 转换与加速](video-processing-example.zh.md)** - 演示模型如何通过底层 FFmpeg 工具对录屏进行加速、缩放及双阶段色彩优化处理。
|
||||
|
||||
|
||||
@@ -4,17 +4,15 @@
|
||||
|
||||
## 📚 目录
|
||||
|
||||
1. [插件开发快速入门](#1-插件开发快速入门)
|
||||
2. [核心概念与 SDK 详解](#2-核心概念与-sdk-详解)
|
||||
3. [插件类型深度解析](#3-插件类型深度解析)
|
||||
* [Action (动作)](#31-action-动作)
|
||||
* [Filter (过滤器)](#32-filter-过滤器)
|
||||
* [Pipe (管道)](#33-pipe-管道)
|
||||
4. [高级开发模式](#4-高级开发模式)
|
||||
5. [最佳实践与设计原则](#5-最佳实践与设计原则)
|
||||
6. [仓库规范(openwebui-extensions)](#6-仓库规范openwebui-extensions)
|
||||
7. [自定义 Agents 设计建议](#7-自定义-agents-设计建议)
|
||||
8. [故障排查](#8-故障排查)
|
||||
1. [插件开发快速入门](#1-插件开发快速入门)
|
||||
2. [核心概念与 SDK 详解](#2-核心概念与-sdk-详解)
|
||||
3. [插件类型深度解析](#3-插件类型深度解析)
|
||||
* [Action (动作)](#31-action-动作)
|
||||
* [Filter (过滤器)](#32-filter-过滤器)
|
||||
* [Pipe (管道)](#33-pipe-管道)
|
||||
4. [高级开发模式](#4-高级开发模式)
|
||||
5. [最佳实践与设计原则](#5-最佳实践与设计原则)
|
||||
6. [故障排查](#6-故障排查)
|
||||
|
||||
---
|
||||
|
||||
@@ -23,10 +21,9 @@
|
||||
### 1.1 什么是 OpenWebUI 插件?
|
||||
|
||||
OpenWebUI 插件(官方称为 "Functions")是扩展平台功能的主要方式。它们运行在后端 Python 环境中,允许你:
|
||||
|
||||
* 🔌 **集成新模型**:通过 Pipe 接入 Claude、Gemini 或自定义 RAG。
|
||||
* 🎨 **增强交互**:通过 Action 在消息旁添加按钮(如"导出"、"生成图表")。
|
||||
* 🔧 **干预流程**:通过 Filter 在请求前后修改数据(如注入上下文、敏感词过滤)。
|
||||
* 🔌 **集成新模型**:通过 Pipe 接入 Claude、Gemini 或自定义 RAG。
|
||||
* 🎨 **增强交互**:通过 Action 在消息旁添加按钮(如"导出"、"生成图表")。
|
||||
* 🔧 **干预流程**:通过 Filter 在请求前后修改数据(如注入上下文、敏感词过滤)。
|
||||
|
||||
### 1.2 你的第一个插件 (Hello World)
|
||||
|
||||
@@ -72,10 +69,9 @@ class Action:
|
||||
### 2.1 ⚠️ 重要:同步与异步
|
||||
|
||||
OpenWebUI 插件运行在 `asyncio` 事件循环中。
|
||||
|
||||
* **原则**:所有 I/O 操作(数据库、文件、网络)必须非阻塞。
|
||||
* **陷阱**:直接调用同步方法(如 `time.sleep`, `requests.get`)会卡死整个服务器。
|
||||
* **解决**:使用 `await asyncio.to_thread(sync_func, ...)` 包装同步调用。
|
||||
* **原则**:所有 I/O 操作(数据库、文件、网络)必须非阻塞。
|
||||
* **陷阱**:直接调用同步方法(如 `time.sleep`, `requests.get`)会卡死整个服务器。
|
||||
* **解决**:使用 `await asyncio.to_thread(sync_func, ...)` 包装同步调用。
|
||||
|
||||
### 2.2 核心参数详解
|
||||
|
||||
@@ -92,8 +88,8 @@ OpenWebUI 插件运行在 `asyncio` 事件循环中。
|
||||
|
||||
### 2.3 配置系统 (Valves)
|
||||
|
||||
* **`Valves`**: 管理员全局配置。
|
||||
* **`UserValves`**: 用户级配置(优先级更高,可覆盖全局)。
|
||||
* **`Valves`**: 管理员全局配置。
|
||||
* **`UserValves`**: 用户级配置(优先级更高,可覆盖全局)。
|
||||
|
||||
```python
|
||||
class Filter:
|
||||
@@ -117,7 +113,7 @@ class Filter:
|
||||
|
||||
**定位**:在消息下方添加按钮,用户点击触发。
|
||||
|
||||
#### 高级用法:前端执行 JavaScript (文件下载示例)
|
||||
**高级用法:前端执行 JavaScript (文件下载示例)**
|
||||
|
||||
```python
|
||||
import base64
|
||||
@@ -142,11 +138,11 @@ async def action(self, body, __event_call__):
|
||||
|
||||
**定位**:中间件,拦截并修改请求/响应。
|
||||
|
||||
* **`inlet`**: 请求前。用于注入上下文、修改模型参数。
|
||||
* **`outlet`**: 响应后。用于格式化输出、保存日志。
|
||||
* **`stream`**: 流式处理中。用于实时敏感词过滤。
|
||||
* **`inlet`**: 请求前。用于注入上下文、修改模型参数。
|
||||
* **`outlet`**: 响应后。用于格式化输出、保存日志。
|
||||
* **`stream`**: 流式处理中。用于实时敏感词过滤。
|
||||
|
||||
#### 示例:注入环境变量
|
||||
**示例:注入环境变量**
|
||||
|
||||
```python
|
||||
async def inlet(self, body, __metadata__):
|
||||
@@ -163,7 +159,7 @@ async def inlet(self, body, __metadata__):
|
||||
|
||||
**定位**:自定义模型/代理。
|
||||
|
||||
#### 示例:简单的 OpenAI 代理
|
||||
**示例:简单的 OpenAI 代理**
|
||||
|
||||
```python
|
||||
import requests
|
||||
@@ -184,14 +180,11 @@ class Pipe:
|
||||
## 4. 高级开发模式
|
||||
|
||||
### 4.1 Pipe 与 Filter 协同
|
||||
|
||||
利用 `__request__.app.state` 在不同插件间共享数据。
|
||||
|
||||
* **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
* **Filter (Outlet)**: 读取 `search_results` 并将其格式化为引用链接附加到回复末尾。
|
||||
* **Pipe**: `__request__.app.state.search_results = [...]`
|
||||
* **Filter (Outlet)**: 读取 `search_results` 并将其格式化为引用链接附加到回复末尾。
|
||||
|
||||
### 4.2 异步后台任务
|
||||
|
||||
不阻塞用户响应,在后台执行耗时操作(如生成总结、存库)。
|
||||
|
||||
```python
|
||||
@@ -211,18 +204,15 @@ async def background_job(self, chat_id):
|
||||
## 5. 最佳实践与设计原则
|
||||
|
||||
### 5.1 命名与定位
|
||||
|
||||
* **简短有力**:如 "闪记卡", "精读"。避免 "文本分析助手" 这种泛词。
|
||||
* **功能互补**:不要重复造轮子,明确你的插件解决了什么特定问题。
|
||||
* **简短有力**:如 "闪记卡", "精读"。避免 "文本分析助手" 这种泛词。
|
||||
* **功能互补**:不要重复造轮子,明确你的插件解决了什么特定问题。
|
||||
|
||||
### 5.2 用户体验 (UX)
|
||||
|
||||
* **反馈及时**:耗时操作前先发送 `notification` ("正在生成...")。
|
||||
* **视觉美观**:Action 输出 HTML 时,使用现代化的 CSS(圆角、阴影、渐变)。
|
||||
* **智能引导**:检测到文本过短时,提示用户"建议输入更多内容以获得更好结果"。
|
||||
* **反馈及时**:耗时操作前先发送 `notification` ("正在生成...")。
|
||||
* **视觉美观**:Action 输出 HTML 时,使用现代化的 CSS(圆角、阴影、渐变)。
|
||||
* **智能引导**:检测到文本过短时,提示用户"建议输入更多内容以获得更好结果"。
|
||||
|
||||
### 5.3 错误处理
|
||||
|
||||
永远不要让插件静默失败。捕获异常并通过 `__event_emitter__` 告知用户。
|
||||
|
||||
```python
|
||||
@@ -237,127 +227,8 @@ except Exception as e:
|
||||
|
||||
---
|
||||
|
||||
## 6. 仓库规范(openwebui-extensions)
|
||||
## 6. 故障排查
|
||||
|
||||
### 6.1 单文件 i18n 规范
|
||||
|
||||
本仓库要求每个插件采用**单文件源码 + 内置多语言**方案,禁止按语言拆分多个 `.py` 文件。
|
||||
|
||||
* 代码路径规范:`plugins/{type}/{name}/{name}.py`
|
||||
* 文档规范:必须同时提供 `README.md` 与 `README_CN.md`
|
||||
|
||||
### 6.2 上下文访问规范(必选)
|
||||
|
||||
优先通过 `_get_user_context` 与 `_get_chat_context` 提取上下文,避免直接硬编码读取 `__user__` 或 `body` 字段。
|
||||
|
||||
### 6.3 事件与日志规范
|
||||
|
||||
* 用状态/通知事件给用户反馈进度。
|
||||
* 前端调试优先使用 `execute` 注入的控制台日志。
|
||||
* 后端统一使用 Python `logging`,生产代码避免 `print()`。
|
||||
|
||||
### 6.4 前端语言探测防卡死
|
||||
|
||||
通过 `__event_call__` 获取前端语言时,必须同时满足:
|
||||
|
||||
* JS 端 `try...catch` 并保证返回值
|
||||
* 后端 `asyncio.wait_for(..., timeout=2.0)`
|
||||
|
||||
这样可以避免前端异常导致后端永久等待。
|
||||
|
||||
### 6.5 Copilot SDK 工具参数定义
|
||||
|
||||
开发 Copilot SDK 工具时,应使用 `pydantic.BaseModel` 显式声明参数,并在 `define_tool(...)` 中通过 `params_type` 传入。
|
||||
|
||||
### 6.6 Copilot SDK 流式输出格式
|
||||
|
||||
* 思考过程使用原生 `<think>...</think>`。
|
||||
* 正文或工具卡片输出前,必须先闭合 `</think>`。
|
||||
* 工具卡片使用 `<details type="tool_calls" ...>` 原生结构。
|
||||
* `arguments` 与 `result` 属性中的双引号必须转义为 `"`。
|
||||
|
||||
### 6.7 从源码提炼的实战模式(建议直接复用)
|
||||
|
||||
以下模式来自 `github_copilot_sdk.py` 与 `workspace_file_manager.py`:
|
||||
|
||||
* **工具参数防漂移**:工具定义使用 `params_type=BaseModel`,执行时用 `model_dump(exclude_unset=True)`,避免把未提供参数传成 `None` 覆盖函数默认值。
|
||||
* **工具名规范化**:将工具名限制为 `^[a-zA-Z0-9_-]+$`,若全中文等导致空名,使用 `md5` 后缀兜底,保证 SDK 可注册。
|
||||
* **工作区沙箱**:所有文件路径在解析后必须校验仍位于 workspace 根目录内,阻断目录穿越。
|
||||
* **文件发布三段式**:本地写入 -> `publish_file_from_workspace` -> 返回 `/api/v1/files/{id}/content`;并写入 `skip_rag=true` 元数据。
|
||||
* **S3/本地双通道上传**:优先走 API 上传(兼容对象存储),失败再回退 DB + 本地文件。
|
||||
* **流式渲染稳定性**:`assistant.message_delta` 前确保关闭 `<think>`,避免正文被吞进思考块。
|
||||
* **原生工具卡片输出**:`tool.execution_complete` 统一输出 `<details type="tool_calls">`,并对属性执行 HTML 转义(尤其 `"`、换行)。
|
||||
* **TODO 持久化联动**:`update_todo` 成功后同时回写 `TODO.md` 与数据库,保持会话可恢复。
|
||||
|
||||
### 6.8 从 `plugins/` 全量提炼的开发知识(Action / Filter / Pipe / Pipeline / Tool)
|
||||
|
||||
以下内容来自 `plugins/` 真实源码的横向归纳:
|
||||
|
||||
* **Action 输入治理**:统一抽取多模态文本内容,注入新 HTML 前清理旧插件块(`OPENWEBUI_PLUGIN_OUTPUT`),并在调用模型前做最小长度校验。
|
||||
* **Action i18n 工程化**:采用 `TRANSLATIONS + fallback_map + 基础语言回退`(如 `fr-CA -> fr-FR`、`en-GB -> en-US`),状态/UI/JS 文案统一走翻译键,并对 `format(**kwargs)` 做异常兜底。
|
||||
* **前端语言探测(生产可用)**:优先链路为 `document.lang -> localStorage(locale/language) -> navigator.language -> profile/request`,且 `__event_call__(execute)` 必须加超时保护。
|
||||
* **长任务体验模式**:开始即发送 `status + notification`,处理中分阶段更新,失败时对用户提示简洁并将详情写入后端日志。
|
||||
* **HTML 插件可组合模式**:通过样式/内容/脚本插入点支持多次累积,兼容覆盖模式(`CLEAR_PREVIOUS_HTML`)与合并模式。
|
||||
* **iframe 主题一致性**:从父页面 `meta[name=theme-color]`、父级 class/data-theme、系统主题逐级判定明暗,并在导出 SVG/PNG 时注入主题样式。
|
||||
* **前端渲染-导出-回写闭环**:离屏渲染图表/思维导图后导出 SVG/PNG 并上传 `/api/v1/files/`,再通过事件 API + 持久化 API 同步更新消息。
|
||||
* **DOCX 导出实战模式**:使用 `TITLE_SOURCE` 回退链(`chat_title -> markdown_title -> 用户名+日期`),导出前剔除 reasoning 块,公式走 `latex2mathml + mathml2omml` 并支持降级,引用可落地为参考文献与锚点。
|
||||
* **OpenWebUI 文件读取多级回退**:DB 内联字节/base64 -> S3 直连 -> 本地路径多变体 -> 公共 URL -> 内部 API `/api/v1/files/{id}/content` -> 原始对象字段,且每层都做字节上限控制。
|
||||
* **Filter 单例安全**:不在 `self` 保存请求级临时状态,请求内数据应基于 `body` 与上下文方法即时计算。
|
||||
* **异步上下文压缩模式**:采用 `inlet` 注入历史摘要 + `outlet` 异步生成新摘要,支持模型级阈值覆盖、快速估算与精算切换,并保护系统提示(`effective_keep_first`)。
|
||||
* **模型兼容性护栏**:对不兼容模型族(如 `copilot_sdk`)跳过特定处理,默认优先使用当前会话模型,避免硬编码。
|
||||
* **文件夹记忆(Folder Memory)模式**:每 N 条消息触发规则提炼,使用 `RULES_BLOCK_START/END` 做幂等替换,并可选上推至根文件夹。
|
||||
* **工作区工具加固**:`list/read/write/delete/publish` 全链路做路径越界校验,读写设置大小限制并区分文本/二进制,发布后返回可直接展示的 Markdown 下载链接。
|
||||
* **MoE 提示词精炼(Pipeline)模式**:通过触发前缀识别聚合请求,解析原问题与多模型回答后重写为综合分析主提示词,并支持聚合阶段模型切换。
|
||||
|
||||
### 6.9 Copilot 相关工程化配置
|
||||
|
||||
为了同时支持 **GitHub Copilot + Gemini CLI + 反重力开发**,建议采用以下工程化控制:
|
||||
|
||||
* **主辅双通道**:Copilot 负责主实现,Gemini CLI 负责草案与交叉校验。
|
||||
* **统一合入契约**:两条通道都必须遵守同一仓库规范(单文件 i18n、上下文方法、事件规范、发布规则)。
|
||||
* **工具参数治理**:Copilot SDK 工具必须使用 Pydantic `params_type` 显式建模。
|
||||
* **反重力安全机制**:小步可回滚、超时保护、回退链路、输出路径确定性。
|
||||
* **文件创建协议**:在 workspace 范围内创建,按发布流程输出,并返回 `/api/v1/files/{id}/content` 进行交付。
|
||||
|
||||
设计文档:
|
||||
|
||||
* `docs/development/copilot-engineering-plan.zh.md`
|
||||
|
||||
---
|
||||
|
||||
## 7. 自定义 Agents 设计建议
|
||||
|
||||
### 7.1 推荐架构(适合你的项目)
|
||||
|
||||
* **Orchestrator Pipe**:负责会话、模型路由、流式事件。
|
||||
* **Tool Adapter Layer**:统一接入 OpenWebUI Tools / OpenAPI / MCP,并做参数校验与名称规范化。
|
||||
* **Workspace I/O Layer**:统一文件读写、发布、沙箱校验。
|
||||
* **Render Layer**:统一处理 `<think>`、工具卡片、通知事件。
|
||||
|
||||
### 7.2 最小可用 Agent 清单(MVP)
|
||||
|
||||
1. `Valves + UserValves` 双层配置(用户优先覆盖)。
|
||||
2. `_get_user_context` / `_get_chat_context` 统一上下文入口。
|
||||
3. 至少 1 个可落地产物工具(如 `publish_file_from_workspace`)。
|
||||
4. 流式事件最小闭环:`reasoning_delta`、`message_delta`、`tool.execution_complete`。
|
||||
5. 错误统一走通知事件,不静默失败。
|
||||
|
||||
### 7.3 你现在就可以新增的 3 类 Agent
|
||||
|
||||
* **Repo Analyst Agent**:扫描仓库并输出“架构图 + 风险清单 + 重构建议”。
|
||||
* **Release Draft Agent**:自动生成 Conventional Commit、双语变更摘要、发布检查清单。
|
||||
* **Docs Sync Agent**:对比代码与文档版本差异,自动给出需同步文件列表。
|
||||
|
||||
### 7.4 实施优先级建议
|
||||
|
||||
* **P0**:先做 `Release Draft Agent`(收益最高、风险最低)。
|
||||
* **P1**:再做 `Docs Sync Agent`(减少文档漂移)。
|
||||
* **P2**:最后做 `Repo Analyst Agent`(用于中长期演进)。
|
||||
|
||||
---
|
||||
|
||||
## 8. 故障排查
|
||||
|
||||
* **HTML 不显示?** 确保包裹在 ` ```html ... ``` ` 代码块中。
|
||||
* **数据库报错?** 检查是否在 `async` 函数中直接调用了同步的 DB 方法,请使用 `asyncio.to_thread`。
|
||||
* **参数未生效?** 检查 `Valves` 定义是否正确,以及是否被 `UserValves` 覆盖。
|
||||
* **HTML 不显示?** 确保包裹在 ` ```html ... ``` ` 代码块中。
|
||||
* **数据库报错?** 检查是否在 `async` 函数中直接调用了同步的 DB 方法,请使用 `asyncio.to_thread`。
|
||||
* **参数未生效?** 检查 `Valves` 定义是否正确,以及是否被 `UserValves` 覆盖。
|
||||
|
||||
71
mkdocs.yml
71
mkdocs.yml
@@ -1,4 +1,3 @@
|
||||
# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json
|
||||
# MkDocs Configuration for OpenWebUI Extras
|
||||
# Site Information
|
||||
site_name: OpenWebUI Extensions
|
||||
@@ -18,12 +17,12 @@ copyright: Copyright © 2024 OpenWebUI Extensions Contributors
|
||||
theme:
|
||||
name: material
|
||||
language: en
|
||||
|
||||
|
||||
# Logo and Icons
|
||||
icon:
|
||||
logo: material/robot-happy-outline
|
||||
repo: fontawesome/brands/github
|
||||
|
||||
|
||||
# Color Palette with Light/Dark Toggle
|
||||
palette:
|
||||
# Light mode
|
||||
@@ -34,7 +33,7 @@ theme:
|
||||
toggle:
|
||||
icon: material/brightness-7
|
||||
name: Switch to dark mode
|
||||
|
||||
|
||||
# Dark mode
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
@@ -43,7 +42,7 @@ theme:
|
||||
toggle:
|
||||
icon: material/brightness-4
|
||||
name: Switch to light mode
|
||||
|
||||
|
||||
# Navigation Features
|
||||
features:
|
||||
- navigation.tabs
|
||||
@@ -60,7 +59,7 @@ theme:
|
||||
- content.code.annotate
|
||||
- content.tabs.link
|
||||
- toc.follow
|
||||
|
||||
|
||||
# Custom fonts
|
||||
font:
|
||||
text: Roboto
|
||||
@@ -95,7 +94,6 @@ plugins:
|
||||
Development: 开发指南
|
||||
Contributing: 贡献指南
|
||||
Plugin Development Guide: 插件开发指南
|
||||
Copilot Engineering Plan: Copilot 工程化配置
|
||||
Documentation Guide: 文档编写指南
|
||||
Smart Mind Map: 智能思维导图
|
||||
Smart Infographic: 智能信息图
|
||||
@@ -123,7 +121,7 @@ markdown_extensions:
|
||||
- toc:
|
||||
permalink: true
|
||||
toc_depth: 3
|
||||
|
||||
|
||||
# Python Markdown Extensions
|
||||
- pymdownx.arithmatex:
|
||||
generic: true
|
||||
@@ -165,9 +163,9 @@ extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/github
|
||||
link: https://github.com/Fu-Jie/openwebui-extensions
|
||||
|
||||
|
||||
generator: false
|
||||
|
||||
|
||||
# Analytics (optional - add your tracking ID)
|
||||
# analytics:
|
||||
# provider: google
|
||||
@@ -181,34 +179,33 @@ extra_css:
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Plugins:
|
||||
- plugins/index.md
|
||||
- Actions:
|
||||
- plugins/actions/index.md
|
||||
- Smart Mind Map: plugins/actions/smart-mind-map.md
|
||||
- Smart Infographic: plugins/actions/smart-infographic.md
|
||||
- Flash Card: plugins/actions/flash-card.md
|
||||
- Export to Excel: plugins/actions/export-to-excel.md
|
||||
- Export to Word: plugins/actions/export-to-word.md
|
||||
- Filters:
|
||||
- plugins/filters/index.md
|
||||
- Async Context Compression: plugins/filters/async-context-compression.md
|
||||
- Context Enhancement: plugins/filters/context-enhancement.md
|
||||
- Multi-Model Context Merger: plugins/filters/multi-model-context-merger.md
|
||||
- Web Gemini Multimodal Filter: plugins/filters/web-gemini-multimodel.md
|
||||
- Pipes:
|
||||
- plugins/pipes/index.md
|
||||
- Pipelines:
|
||||
- plugins/pipelines/index.md
|
||||
- MoE Prompt Refiner: plugins/pipelines/moe-prompt-refiner.md
|
||||
- plugins/index.md
|
||||
- Actions:
|
||||
- plugins/actions/index.md
|
||||
- Smart Mind Map: plugins/actions/smart-mind-map.md
|
||||
- Smart Infographic: plugins/actions/smart-infographic.md
|
||||
- Flash Card: plugins/actions/flash-card.md
|
||||
- Export to Excel: plugins/actions/export-to-excel.md
|
||||
- Export to Word: plugins/actions/export-to-word.md
|
||||
- Filters:
|
||||
- plugins/filters/index.md
|
||||
- Async Context Compression: plugins/filters/async-context-compression.md
|
||||
- Context Enhancement: plugins/filters/context-enhancement.md
|
||||
- Multi-Model Context Merger: plugins/filters/multi-model-context-merger.md
|
||||
- Web Gemini Multimodal Filter: plugins/filters/web-gemini-multimodel.md
|
||||
- Pipes:
|
||||
- plugins/pipes/index.md
|
||||
- Pipelines:
|
||||
- plugins/pipelines/index.md
|
||||
- MoE Prompt Refiner: plugins/pipelines/moe-prompt-refiner.md
|
||||
- Prompts:
|
||||
- prompts/index.md
|
||||
- prompts/library.md
|
||||
- prompts/index.md
|
||||
- prompts/library.md
|
||||
- Enhancements:
|
||||
- enhancements/index.md
|
||||
- enhancements/guide.md
|
||||
- enhancements/index.md
|
||||
- enhancements/guide.md
|
||||
- Development:
|
||||
- development/index.md
|
||||
- Plugin Development Guide: development/plugin-guide.md
|
||||
- Copilot Engineering Plan: development/copilot-engineering-plan.md
|
||||
- Documentation Guide: development/documentation-guide.md
|
||||
- development/index.md
|
||||
- Plugin Development Guide: development/plugin-guide.md
|
||||
- Documentation Guide: development/documentation-guide.md
|
||||
- Contributing: contributing.md
|
||||
|
||||
@@ -2,26 +2,21 @@
|
||||
|
||||
Smart Mind Map is a powerful OpenWebUI action plugin that intelligently analyzes long-form text content and automatically generates interactive mind maps, helping users structure and visualize knowledge.
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 1.0.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **Version:** 0.9.2 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
|
||||
## What's New in v1.0.0
|
||||
## What's New in v0.9.2
|
||||
|
||||
### Direct Embed & UI Refinements
|
||||
**Language Rule Alignment**
|
||||
|
||||
- **Native Multi-language UI (i18n)**: The plugin interface (buttons, settings, status) now automatically adapts to your browser's language setting for a seamless global experience.
|
||||
- **Direct Embed Mode**: Introduced a native-like inline display mode for Open WebUI 0.8.0+, enabling a seamless full-width canvas.
|
||||
- **Adaptive Auto-Sizing**: Mind map now dynamically scales its height and perfectly refits to the window to eliminate scrollbar artifacts.
|
||||
- **Subdued & Compact UI**: Completely redesigned the header tooling bar to a slender, single-line configuration to maximize visual rendering space.
|
||||
- **Configurable Experience**: Added `ENABLE_DIRECT_EMBED_MODE` valve to explicitly toggle the new inline rendering behavior.
|
||||
- **Input Language First**: Mind map output now strictly matches the input text language.
|
||||
- **Consistent Behavior**: Matches the infographic language rule for predictable multilingual output.
|
||||
|
||||
## Key Features 🔑
|
||||
|
||||
- ✅ **Intelligent Text Analysis**: Automatically identifies core themes, key concepts, and hierarchical structures.
|
||||
- ✅ **Native Multi-language UI**: Automatic interface translation (i18n) based on system language for a native feel.
|
||||
- ✅ **Interactive Visualization**: Generates beautiful interactive mind maps based on Markmap.js.
|
||||
- ✅ **Direct Embed Mode**: (Optional) For Open WebUI 0.8.0+, render natively inline to fill entire UI width.
|
||||
- ✅ **High-Resolution PNG Export**: Export mind maps as high-quality PNG images (9x scale).
|
||||
- ✅ **Complete Control Panel**: Zoom controls, expand level selection, and fullscreen mode within a compact toolbar.
|
||||
- ✅ **Complete Control Panel**: Zoom controls, expand level selection, and fullscreen mode.
|
||||
- ✅ **Theme Switching**: Manual theme toggle button with automatic theme detection.
|
||||
- ✅ **Image Output Mode**: Generate static SVG images embedded directly in Markdown for cleaner history.
|
||||
|
||||
@@ -42,7 +37,6 @@ Smart Mind Map is a powerful OpenWebUI action plugin that intelligently analyzes
|
||||
| `CLEAR_PREVIOUS_HTML` | `false` | Whether to clear previous plugin-generated HTML content. |
|
||||
| `MESSAGE_COUNT` | `1` | Number of recent messages to use for generation (1-5). |
|
||||
| `OUTPUT_MODE` | `html` | Output mode: `html` (interactive) or `image` (static). |
|
||||
| `ENABLE_DIRECT_EMBED_MODE` | `false` | Enable Direct Embed Mode (Open WebUI 0.8.0+ native layout) instead of Legacy Mode. |
|
||||
|
||||
## ⭐ Support
|
||||
|
||||
|
||||
@@ -2,26 +2,21 @@
|
||||
|
||||
思维导图是一个强大的 OpenWebUI 动作插件,能够智能分析长篇文本内容,自动生成交互式思维导图,帮助用户结构化和可视化知识。
|
||||
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie) | **版本:** 1.0.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
|
||||
**作者:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **版本:** 0.9.2 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
|
||||
|
||||
## v1.0.0 最新更新
|
||||
## v0.9.2 更新亮点
|
||||
|
||||
### 嵌入式直出与 UI 细节全线重构
|
||||
**语言规则对齐**
|
||||
|
||||
- **原生多语言界面 (Native i18n)**:插件界面(按钮、设置说明、状态提示)现在会根据您浏览器的语言设置自动适配系统语言。
|
||||
- **原生态嵌入模式 (Direct Embed)**:针对 Open WebUI 0.8.0+ 的前端架构支持了纯正的内容内联(Inline)直出模式,不再受气泡和 Markdown 隔离,真正撑满屏幕宽度。
|
||||
- **自动响应边界 (Auto-Sizing)**:突破以前高度僵死的问题。思维导图现在可以根据您的当前屏幕大小弹性伸缩(动态 `clamp()` 高度),彻底消灭丑陋的局部滚动条与白边。
|
||||
- **极简专业 UI (Compact UI)**:推倒重做了头部的菜单栏,统一使用了一套干净、单行的极简全透明微拟物 Toolbar 设计,为导图画布省下极大的垂直空间。
|
||||
- **模式配置自由**:为了照顾阅读流连贯的习惯,新增了 `ENABLE_DIRECT_EMBED_MODE` 配置开关。您必须在设置中显式开启才能体验宽广内联全屏模式。
|
||||
- **输入语言优先**:导图输出严格与输入文本语言一致。
|
||||
- **一致性提升**:与信息图语言规则保持一致,多语言输出更可预期。
|
||||
|
||||
## 核心特性 🔑
|
||||
|
||||
- ✅ **智能文本分析**:自动识别文本的核心主题、关键概念和层次结构。
|
||||
- ✅ **原生多语言界面**:根据系统语言自动切换界面语言 (i18n),提供原生交互体验。
|
||||
- ✅ **交互式可视化**:基于 Markmap.js 生成美观的交互式思维导图。
|
||||
- ✅ **直出全景内嵌 (Direct Embed)**:(可选开关) 对于 Open WebUI 0.8.0+,直接填补整个前端宽度,去除气泡剥离感。
|
||||
- ✅ **高分辨率 PNG 导出**:导出高质量的 PNG 图片(9 倍分辨率)。
|
||||
- ✅ **完整控制面板**:极简清爽的单行大屏缩放控制、展开层级选择、全局全屏等核心操作。
|
||||
- ✅ **完整控制面板**:缩放控制、展开层级选择、全屏模式。
|
||||
- ✅ **主题切换**:手动主题切换按钮与自动主题检测。
|
||||
- ✅ **图片输出模式**:生成静态 SVG 图片直接嵌入 Markdown,聊天记录更简洁。
|
||||
|
||||
@@ -42,7 +37,6 @@
|
||||
| `CLEAR_PREVIOUS_HTML` | `false` | 在生成新的思维导图时,是否清除之前的 HTML 内容。 |
|
||||
| `MESSAGE_COUNT` | `1` | 用于生成思维导图的最近消息数量(1-5)。 |
|
||||
| `OUTPUT_MODE` | `html` | 输出模式:`html`(交互式)或 `image`(静态图片)。 |
|
||||
| `ENABLE_DIRECT_EMBED_MODE` | `false` | 是否开启沉浸式直出嵌入模式(需要 Open WebUI v0.8.0+ 环境)。如果保持 `false` 将会维持旧版的对话流 Markdown 渲染模式。 |
|
||||
|
||||
## ⭐ 支持
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 752 KiB |
File diff suppressed because it is too large
Load Diff
BIN
plugins/actions/smart-mind-map/smart_mind_map_cn.png
Normal file
BIN
plugins/actions/smart-mind-map/smart_mind_map_cn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 216 KiB |
1617
plugins/actions/smart-mind-map/smart_mind_map_cn.py
Normal file
1617
plugins/actions/smart-mind-map/smart_mind_map_cn.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
import re
|
||||
|
||||
def reproduce_bug():
|
||||
# 模拟 Issue #49 中提到的受损逻辑
|
||||
# 核心问题在于正则表达式过于贪婪,或者在多次迭代中错误地将两个加粗块中间的部分当作了“带空格的加粗内容”
|
||||
text = "I **prefer** tea **to** coffee."
|
||||
|
||||
# 模拟一个不严谨的、容易跨块匹配的正则
|
||||
# 它会匹配 ** 开始,中间任意字符,** 结束
|
||||
buggy_pattern = re.compile(r"(\*\*)(.*?)(\*\*)")
|
||||
|
||||
def buggy_fix(content):
|
||||
# 模拟插件中的 strip 逻辑:它想去掉加粗符号内部的空格
|
||||
# 但由于正则匹配了 "**prefer** tea **", 这里的 m.group(2) 变成了 "prefer** tea "
|
||||
return buggy_pattern.sub(lambda m: f"{m.group(1)}{m.group(2).strip()}{m.group(1)}", content)
|
||||
|
||||
# 第一次执行:处理了 "**prefer**" -> "**prefer**"
|
||||
result_1 = buggy_fix(text)
|
||||
|
||||
# 第二次执行(模拟 while 循环或重复运行):
|
||||
# 此时如果正则引擎从第一个加粗的结束符开始匹配到第二个加粗的起始符
|
||||
# 指针位置: I **prefer**[匹配开始] tea [匹配结束]**to** coffee.
|
||||
# 就会把 " tea " 两侧的 ** 当作一对,然后 strip() 掉空格
|
||||
result_2 = buggy_fix(result_1)
|
||||
|
||||
print(f"Original: {text}")
|
||||
print(f"Step 1: {result_1}")
|
||||
print(f"Step 2: {result_2} (Bug Reproduced!)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
reproduce_bug()
|
||||
@@ -1,28 +0,0 @@
|
||||
import re
|
||||
|
||||
def reproduce_bug_v2():
|
||||
# 模拟更接近旧版实际代码的情况
|
||||
# 旧版代码中循环多次处理,且正则可能在处理嵌套或连续块时出现偏移
|
||||
text = "I **prefer** tea **to** coffee."
|
||||
|
||||
# 这是一个贪婪且不具备前瞻断言的正则
|
||||
buggy_pattern = re.compile(r"(\*\*)( +)(.*?)( +)(\*\*)")
|
||||
|
||||
# 模拟那种“只要看到 ** 且中间有空格就想修”的逻辑
|
||||
# 如果文本是 "I **prefer** tea **to**"
|
||||
# 这里的空格出现在 "prefer**" 和 "**to" 之间
|
||||
content = "I **prefer** tea **to** coffee."
|
||||
|
||||
# 错误的匹配尝试:将第一个块的结尾和第二个块的开头误认为是一对
|
||||
# I **prefer** tea **to**
|
||||
# ^^ ^^
|
||||
# A B
|
||||
# 正则误以为 A 是开始,B 是结束
|
||||
|
||||
bug_result = re.sub(r"\*\*( +)(.*?)( +)\*\*", r"**\2**", content)
|
||||
|
||||
print(f"Input: {content}")
|
||||
print(f"Output: {bug_result}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
reproduce_bug_v2()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user