Compare commits
124 Commits
v2026.02.2
...
github-cop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f2e7a9658 | ||
|
|
c87e80379b | ||
|
|
4c9b5d1c7c | ||
|
|
afac25c14c | ||
|
|
a8581119fe | ||
|
|
2508eec590 | ||
|
|
121b1db732 | ||
|
|
ad04a3e50e | ||
|
|
a5b968676d | ||
|
|
894584330c | ||
|
|
6f8c871658 | ||
|
|
bf3ba97b9a | ||
|
|
31496a191e | ||
|
|
c6171be0d1 | ||
|
|
6b8cb9630a | ||
|
|
8573a0d7b0 | ||
|
|
f142b32486 | ||
|
|
04a05ac47c | ||
|
|
e992b8a3bd | ||
|
|
6dbbca8e55 | ||
|
|
06735d3c7f | ||
|
|
5119add50c | ||
|
|
1df328a304 | ||
|
|
e92ad60e3f | ||
|
|
93a6c41c05 | ||
|
|
64af4276a7 | ||
|
|
4feb1bdd80 | ||
|
|
44debbab04 | ||
|
|
de10ba87ae | ||
|
|
c818a2ac8d | ||
|
|
cea31fed38 | ||
|
|
8f8147828b | ||
|
|
158792d82f | ||
|
|
858d048d81 | ||
|
|
2f518d4c7a | ||
|
|
baae09a223 | ||
|
|
903bd7b372 | ||
|
|
8c998ecc73 | ||
|
|
f11cf27404 | ||
|
|
41f271d2d8 | ||
|
|
984d3061c7 | ||
|
|
ba11cdd157 | ||
|
|
b1482b6083 | ||
|
|
0cc46e0188 | ||
|
|
93a42cbe03 | ||
|
|
fdf95a2825 | ||
|
|
5fe66a5803 | ||
|
|
cd95b5ff69 | ||
|
|
3210262296 | ||
|
|
37a130993a | ||
|
|
b75fd96e4a | ||
|
|
5dd9d6cc56 | ||
|
|
d569dc3ec9 | ||
|
|
e2426c74e1 | ||
|
|
ae0fa1d39a | ||
|
|
62e78ace5c | ||
|
|
7efb64b16b | ||
|
|
2eee7c5d35 | ||
|
|
9bf31488ae | ||
|
|
ef86a2c3c4 | ||
|
|
b4c6d23dfb | ||
|
|
6102851e55 | ||
|
|
79c1fde217 | ||
|
|
d29c24ba4a | ||
|
|
55a9c6ffb5 | ||
|
|
f11affd3e6 | ||
|
|
d57f9affd5 | ||
|
|
f4f7b65792 | ||
|
|
a777112417 | ||
|
|
530a6f9459 | ||
|
|
935fa0ccaa | ||
|
|
f5a983fb4a | ||
|
|
35dec491de | ||
|
|
67de7f1cfc | ||
|
|
b954fbca1d | ||
|
|
c1411e731d | ||
|
|
df78f0454b | ||
|
|
d5931fbc5e | ||
|
|
af59959ade | ||
|
|
56a6ddd422 | ||
|
|
eda495e55f | ||
|
|
3642058292 | ||
|
|
5b0464dcdd | ||
|
|
2aff7f1bf4 | ||
|
|
ba0d63930e | ||
|
|
a1568de67b | ||
|
|
f4a38a7906 | ||
|
|
2e6c61737f | ||
|
|
c1e9aca5dc | ||
|
|
6f700fe610 | ||
|
|
3927e384cc | ||
|
|
e1dac2219e | ||
|
|
9436364b9a | ||
|
|
e7b1ff4c54 | ||
|
|
c4ff4fea7e | ||
|
|
32afc3286e | ||
|
|
3e8b15af46 | ||
|
|
658f37baa6 | ||
|
|
c65ba57553 | ||
|
|
7c17dbbe23 | ||
|
|
c6279240b9 | ||
|
|
a8a324500a | ||
|
|
369e8c900c | ||
|
|
83e317a335 | ||
|
|
c28c3c837b | ||
|
|
701ea0b18f | ||
|
|
eb79bc9633 | ||
|
|
0c7d427b93 | ||
|
|
07bc5f027e | ||
|
|
701fc3e906 | ||
|
|
d392af66c9 | ||
|
|
67cf86fb26 | ||
|
|
fe98b0e007 | ||
|
|
3236d19e28 | ||
|
|
354c1eee6b | ||
|
|
6b3eb8064b | ||
|
|
f32e90e182 | ||
|
|
8001ab18ee | ||
|
|
dcfde9c0dc | ||
|
|
dbcf7421ea | ||
|
|
1705baf976 | ||
|
|
8e8d478ece | ||
|
|
acc9cd7ff2 | ||
|
|
e4582c3197 |
49
.agent/learnings/README.md
Normal file
49
.agent/learnings/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# `.agent/learnings/` — Engineering Learnings & Reusable Patterns
|
||||
|
||||
This directory stores **hard-won engineering insights** discovered during development.
|
||||
Each file is a standalone Markdown note covering a specific topic, pattern, or gotcha.
|
||||
|
||||
The goal is to avoid re-investigating the same issue twice.
|
||||
|
||||
---
|
||||
|
||||
## Conventions
|
||||
|
||||
- **File naming**: `{topic}.md`, e.g., `openwebui-tool-injection.md`
|
||||
- **Scope**: One clear topic per file. Keep files focused and concise.
|
||||
- **Format**: Use the template below.
|
||||
|
||||
---
|
||||
|
||||
## Template
|
||||
|
||||
```markdown
|
||||
# [Topic Title]
|
||||
|
||||
> Discovered: YYYY-MM-DD
|
||||
|
||||
## Context
|
||||
Where / when does this apply?
|
||||
|
||||
## Finding
|
||||
What exactly did we learn?
|
||||
|
||||
## Solution / Pattern
|
||||
The code or approach that works.
|
||||
|
||||
## Gotchas
|
||||
Edge cases or caveats to watch out for.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Index
|
||||
|
||||
| File | Topic |
|
||||
|------|-------|
|
||||
| [openwebui-tool-injection.md](./openwebui-tool-injection.md) | How OpenWebUI injects parameters into Tool functions, and what the Pipe must provide |
|
||||
| [openwebui-mock-request.md](./openwebui-mock-request.md) | How to build a valid Mock Request for calling OpenWebUI-internal APIs from a Pipe |
|
||||
| [copilot-plan-mode-prompt-parity.md](./copilot-plan-mode-prompt-parity.md) | Why Plan Mode prompt logic must be shared between fresh-session and resume-session injection |
|
||||
| [richui-default-actions-optout.md](./richui-default-actions-optout.md) | How static RichUI widgets opt out of fallback prompt/link action injection |
|
||||
| [richui-declarative-priority.md](./richui-declarative-priority.md) | How RichUI resolves priority between declarative actions and inline click handlers |
|
||||
| [richui-interaction-api.md](./richui-interaction-api.md) | Recommended 4-action RichUI interaction contract for chat continuation, prefill, submit, and links |
|
||||
@@ -0,0 +1,27 @@
|
||||
# Async Context Compression Progress Mapping
|
||||
|
||||
> Discovered: 2026-03-10
|
||||
|
||||
## Context
|
||||
Applies to `plugins/filters/async-context-compression/async_context_compression.py` once the inlet has already replaced early history with a synthetic summary message.
|
||||
|
||||
## Finding
|
||||
`compressed_message_count` cannot be recalculated from the visible message list length after compression. Once a summary marker is present, the visible list mixes:
|
||||
- preserved head messages that are still before the saved boundary
|
||||
- one synthetic summary message
|
||||
- tail messages that map to original history starting at the saved boundary
|
||||
|
||||
## Solution / Pattern
|
||||
Store the original-history boundary on the injected summary message metadata, then recover future progress using:
|
||||
- `original_count = covered_until + len(messages_after_summary_marker)`
|
||||
- `target_progress = max(covered_until, original_count - keep_last)`
|
||||
|
||||
When the summary-model window is too small, trim newest atomic groups from the summary input so the saved boundary still matches what the summary actually covers.
|
||||
|
||||
## Gotchas
|
||||
- If you trim from the head of the summary input, the saved progress can overstate coverage and hide messages that were never summarized.
|
||||
- Status previews for the next context must convert the saved original-history boundary back into the current visible view before rebuilding head/summary/tail.
|
||||
- `inlet(body["messages"])` and `outlet(body["messages"])` can both represent the full conversation while using different serializations:
|
||||
- inlet may receive expanded native tool-call chains (`assistant(tool_calls) -> tool -> assistant`)
|
||||
- outlet may receive a compact top-level transcript where tool calls are folded into assistant `<details type="tool_calls">` blocks
|
||||
- These two views do not share a safe `compressed_message_count` coordinate system. If outlet is in the compact assistant/details view, do not persist summary progress derived from its top-level message count.
|
||||
40
.agent/learnings/copilot-plan-mode-prompt-parity.md
Normal file
40
.agent/learnings/copilot-plan-mode-prompt-parity.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copilot Plan Mode Prompt Parity
|
||||
|
||||
> Discovered: 2026-03-06
|
||||
|
||||
## Context
|
||||
|
||||
The GitHub Copilot SDK pipe builds system prompts in two paths:
|
||||
|
||||
- fresh session creation via `_build_session_config(...)`
|
||||
- resumed session injection via the `system_parts` rebuild branch
|
||||
|
||||
Plan Mode guidance was duplicated across those branches.
|
||||
|
||||
## Finding
|
||||
|
||||
If Plan Mode instructions are edited in only one branch, resumed sessions silently lose planning behavior or capability hints that fresh sessions still have.
|
||||
|
||||
This is especially easy to miss because both branches still work, but resumed chats receive a weaker or stale prompt.
|
||||
|
||||
Session mode switching alone is also not enough. Even when `session.rpc.mode.set(Mode.PLAN)` succeeds, the SDK may still skip creating the expected `plan.md` if the runtime system prompt does not explicitly include the original Plan Mode persistence contract.
|
||||
|
||||
## Solution / Pattern
|
||||
|
||||
Extract the Plan Mode prompt into one shared helper and call it from both branches:
|
||||
|
||||
```python
|
||||
def _build_plan_mode_context(plan_path: str) -> str:
|
||||
...
|
||||
```
|
||||
|
||||
Then inject it in both places with the chat-specific `plan.md` path.
|
||||
|
||||
For extra safety, when the pipe later reads `session.rpc.plan.read()`, mirror the returned content into the chat-specific `COPILOTSDK_CONFIG_DIR/session-state/<chat_id>/plan.md` path. This keeps the UI-visible file in sync even if the SDK persists plan state internally but does not materialize the file where the chat integration expects it.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Keep the helper dynamic: the `plan.md` path must still be resolved per chat/session.
|
||||
- Do not only update debug prompt artifacts; the effective runtime prompt lives in `plugins/pipes/github-copilot-sdk/github_copilot_sdk.py`.
|
||||
- Resume-session parity matters for capability guidance just as much as for session context.
|
||||
- If users report that Plan Mode is active but `plan.md` is missing, check both halves: prompt parity and the final `rpc.plan.read()` -> `plan.md` sync path.
|
||||
171
.agent/learnings/filter-async-context-compression-design.md
Normal file
171
.agent/learnings/filter-async-context-compression-design.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Filter: async-context-compression 设计模式与工程实践
|
||||
|
||||
**日期**: 2026-03-12
|
||||
**模块**: `plugins/filters/async-context-compression/async_context_compression.py`
|
||||
**关键特性**: 上下文压缩、异步摘要生成、状态管理、LLM 工程优化
|
||||
|
||||
---
|
||||
|
||||
## 核心工程洞察
|
||||
|
||||
### 1. Request 对象的 Filter-to-LLM 传导链
|
||||
|
||||
**问题**:Filter 的 `outlet` 阶段启动背景异步任务(`asyncio.create_task`)调用 `generate_chat_completion`(内部 API),但无法直接访问原始 HTTP `request`。早期代码用最小化合成 Request(仅 `{"type": "http", "app": webui_app}`),暴露兼容性风险。
|
||||
|
||||
**解决方案**:
|
||||
|
||||
- OpenWebUI 对 `outlet` 同样支持 `__request__` 参数注入(即 `inlet` + `outlet` 都支持)
|
||||
- 透传 `__request__` 通过整个异步调用链:`outlet → _locked_summary_task → _check_and_generate_summary_async → _generate_summary_async → _call_summary_llm`
|
||||
- 在最终调用处:`request = __request__ or Request(...)`(兜底降级)
|
||||
|
||||
**收获**:LLM 调用路径应始终倾向于使用真实请求上下文,而非人工合成。即使后台任务中,`request.app` 的应用级状态仍持续有效。
|
||||
|
||||
---
|
||||
|
||||
### 2. 异步摘要生成中的上下文完整性
|
||||
|
||||
**关键场景分化**:
|
||||
|
||||
| 情况 | `summary_index` 值 | 旧摘要位置 | 需要 `previous_summary` |
|
||||
|------|--------|----------|---------|
|
||||
| Inlet 已注入旧摘要 | Not None | `messages[0]`(middle_messages 首项) | ❌ 否,已在 conversation_text 中 |
|
||||
| Outlet 收原始消息(未注入) | None | DB 存档 | ✅ **是**,必须显式读取并透传 |
|
||||
|
||||
**问题根源**:`outlet` 收到的消息来自原始数据库查询,未经过 `inlet` 的摘要注入。当 LLM 看不到历史摘要时,已压缩的知识(旧对话、已解决的问题、先前的发现)会被重新处理或遗忘。
|
||||
|
||||
**实现要点**:
|
||||
|
||||
```python
|
||||
# 仅当 summary_index is None 时异步加载旧摘要
|
||||
if summary_index is None:
|
||||
previous_summary = await asyncio.to_thread(
|
||||
self._load_summary, chat_id, body
|
||||
)
|
||||
else:
|
||||
previous_summary = None
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 上下文压缩的 LLM Prompt 设计
|
||||
|
||||
**工程原则**:
|
||||
|
||||
1. **Clear Input Boundaries**:用 XML 风格标签(`<previous_working_memory>`, `<new_conversation>`)明确分界,避免 LLM 混淆"指令示例"与"待处理数据"
|
||||
2. **State-Aware Merging**:不是"保留所有旧事实",而是**更新状态**——`"bug X exists" → "bug X fixed"` 或彻底移除已解决项
|
||||
3. **Goal Evolution**:Current Goal 反映**最新**意图;旧目标迁移到 Working Memory 作为上下文
|
||||
4. **Error Verbatim**:Stack trace、异常类型、错误码必须逐字引用(是调试的一等公民)
|
||||
5. **Format Strictness**:结构变为 **REQUIRED**(而非 Suggested),允许零内容项省略,但布局一致
|
||||
|
||||
**新 Prompt 结构**:
|
||||
|
||||
```
|
||||
[Rules] → [Output Constraints] → [Required Structure Header] → [Boundaries] → <previous_working_memory> → <new_conversation>
|
||||
```
|
||||
|
||||
关键改进:
|
||||
|
||||
- 规则 3(Ruthless Denoising) → 新增规则 4(Error Verbatim) + 规则 5(Causal Chain)
|
||||
- "Suggested" Structure → "Required" Structure with Optional Sections
|
||||
- 新增 `## Causal Log` 专项,强制单行因果链格式:`[MSG_ID?] action → result`
|
||||
- Token 预算策略明确:按近期性和紧迫性优先裁剪(RRF)
|
||||
|
||||
---
|
||||
|
||||
### 4. 异步任务中的错误边界与恢复
|
||||
|
||||
**现象**:背景摘要生成任务(`asyncio.create_task`)的异常不会阻塞用户响应,但需要:
|
||||
|
||||
- 完整的日志链路(`_log` 调用 + `event_emitter` 通知)
|
||||
- 数据库事务的原子性(摘要和压缩状态同时保存)
|
||||
- 前端 UI 反馈(status event: "generating..." → "complete" 或 "error")
|
||||
|
||||
**最佳实践**:
|
||||
|
||||
- 用 `asyncio.Lock` 按 chat_id 防止并发摘要任务
|
||||
- 后台执行繁重操作(tokenize、LLM call)用 `asyncio.to_thread`
|
||||
- 所有 I/O(DB reads/writes)需包裹异步线程池
|
||||
- 异常捕获限制在 try-except,日志不要吞掉堆栈信息
|
||||
|
||||
---
|
||||
|
||||
### 5. Filter 单例与状态设计陷阱
|
||||
|
||||
**约束**:Filter 实例是全局单例,所有会话共享同一个 `self`。
|
||||
|
||||
**禁忌**:
|
||||
|
||||
```python
|
||||
# ❌ 错误:self.temp_buffer = ... (会被其他并发会话污染)
|
||||
self.temp_state = body # 危险!
|
||||
|
||||
# ✅ 正确:无状态或使用锁/chat_id 隔离
|
||||
self._chat_locks[chat_id] = asyncio.Lock() # 每个 chat 一个锁
|
||||
```
|
||||
|
||||
**设计**:
|
||||
|
||||
- Valves(Pydantic BaseModel)保存全局配置 ✅
|
||||
- 使用 dict 按 `chat_id` 键维护临时状态(lock、计数器)✅
|
||||
- 传参而非全局变量保存请求级数据 ✅
|
||||
|
||||
---
|
||||
|
||||
## 集成场景:Filter + Pipe 的配合
|
||||
|
||||
**当 Pipe 模型调用 Filter 时**:
|
||||
|
||||
1. `inlet` 注入摘要,削减上下文会话消息数
|
||||
2. Pipe 模型(通常为 Copilot SDK 或自定义内核)处理精简消息
|
||||
3. `outlet` 触发背景摘要,无阻塞用户响应
|
||||
4. 下一轮对话时,`inlet` 再次注入最新摘要
|
||||
|
||||
**关键约束**:
|
||||
|
||||
- `_should_skip_compression` 检测 `__model__.get("pipe")` 或 `copilot_sdk`,必要时跳过注入
|
||||
- Pipe 模型若有自己的上下文管理(如 Copilot 的 native tool calling),过度压缩会失去工具调用链
|
||||
- 摘要模型选择(`summary_model` Valve)应兼容当前 Pipe 环境的 API(推荐用通用模型如 gemini-flash)
|
||||
|
||||
---
|
||||
|
||||
## 内部 API 契约速记
|
||||
|
||||
### `generate_chat_completion(request, payload, user)`
|
||||
|
||||
- **request**: FastAPI Request;可来自真实 HTTP 或 `__request__` 注入
|
||||
- **payload**: `{"model": id, "messages": [...], "stream": false, "max_tokens": N, "temperature": T}`
|
||||
- **user**: UserModel;从 DB 查询或 `__user__` 转换(需 `Users.get_user_by_id()`)
|
||||
- **返回**: dict 或 JSONResponse;若是后者需 `response.body.decode()` + JSON parse
|
||||
|
||||
### Filter 生命周期
|
||||
|
||||
```
|
||||
New Message → inlet (User input) → [Plugins wait] → LLM → outlet (Response) → Summary Task (Background)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调试清单
|
||||
|
||||
- [ ] `__request__` 在 `outlet` 签名中声明且被 OpenWebUI 注入(非 None)
|
||||
- [ ] 异步调用链中每层都透传 `__request__`,最底层兜底合成
|
||||
- [ ] `summary_index is None` 时从 DB 异步读取 `previous_summary`
|
||||
- [ ] LLM Prompt 中 `<previous_working_memory>` 和 `<new_conversation>` 有明确边界
|
||||
- [ ] 错误处理不吞堆栈:`logger.exception()` 或 `exc_info=True`
|
||||
- [ ] `asyncio.Lock` 按 chat_id 避免并发工作冲突
|
||||
- [ ] Copilot SDK / Pipe 模型需 `_should_skip_compression()` 检查
|
||||
- [ ] Token budget 在 max_summary_tokens 下规划,优先保留近期事件
|
||||
|
||||
---
|
||||
|
||||
## 相关文件
|
||||
|
||||
- 核心实现:`plugins/filters/async-context-compression/async_context_compression.py`
|
||||
- README:`plugins/filters/async-context-compression/README.md` + `README_CN.md`
|
||||
- OpenWebUI 内部:`open_webui/utils/chat.py` → `generate_chat_completion()`
|
||||
|
||||
---
|
||||
|
||||
**版本**: 1.0
|
||||
**维护者**: Fu-Jie
|
||||
**最后更新**: 2026-03-12
|
||||
72
.agent/learnings/github-copilot-sdk-hang-analysis.md
Normal file
72
.agent/learnings/github-copilot-sdk-hang-analysis.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# GitHub Copilot SDK 卡顿/悬停问题深度源码分析报告
|
||||
|
||||
## 📌 问题现象
|
||||
|
||||
用户反馈在 agent 处理过程中(工具调用、思考、内容输出),`github_copilot_sdk.py` 管道偶尔会卡住(界面转圈不停)。
|
||||
|
||||
## 🔍 事件流架构(SDK 源码分析)
|
||||
|
||||
通过阅读 `copilot-sdk` 源码 (`jsonrpc.py`, `client.py`, `session.py`),事件流路径如下:
|
||||
|
||||
```
|
||||
Copilot CLI (subprocess)
|
||||
└─ stdout (JSON-RPC over stdio)
|
||||
└─ JsonRpcClient._read_loop() [daemon thread]
|
||||
└─ _handle_message()
|
||||
└─ notification_handler("session.event", params) [线程安全调度到 event loop]
|
||||
└─ CopilotSession._dispatch_event(event)
|
||||
└─ plugin handler(event) → queue.put_nowait(chunk)
|
||||
└─ main loop: await queue.get() → yield chunk
|
||||
```
|
||||
|
||||
## 🚨 已确认的三个卡顿根因
|
||||
|
||||
### 根因 1: Stall 检测豁免盲区
|
||||
|
||||
原始代码的防卡死检测仅在 `content_sent=False` 且 `thinking_started=False` 且 `running_tool_calls` 为空时才触发。一旦 agent 开始处理(输出内容/调用工具),所有豁免条件为真,防卡死机制永久失效。
|
||||
|
||||
### 根因 2: 工具调用状态泄漏
|
||||
|
||||
`running_tool_calls.add(tool_call_id)` 在 `tool.execution_start` 时添加,但如果 SDK 连接断开导致 `tool.execution_complete` 事件丢失,集合永远不为空,直接阻塞 Stall 检测。
|
||||
|
||||
### 根因 3: `session.abort()` 自身可能卡住(SDK 源码确认)
|
||||
|
||||
**SDK 源码关键证据** (`jsonrpc.py:107-148`):
|
||||
|
||||
```python
|
||||
async def request(self, method, params=None, timeout=None):
|
||||
...
|
||||
if timeout is not None:
|
||||
return await asyncio.wait_for(future, timeout=timeout)
|
||||
return await future # ← 无 timeout,永久等待!
|
||||
```
|
||||
|
||||
`session.abort()` 底层调用 `self._client.request("session.abort", ...)` **没有传 timeout**。
|
||||
当 CLI 进程挂死但 `_read_loop` 尚未检测到断流(例如 TCP 半开连接),`abort()` RPC 自身会无限等待响应,造成**修复代码自身也卡住**。
|
||||
|
||||
## ✅ 修复记录 (2026-03-18)
|
||||
|
||||
### 修复 1: `assistant.turn_end` / `session.error` 兜底清理
|
||||
|
||||
`running_tool_calls.clear()` — 即时清除孤儿工具状态。
|
||||
|
||||
### 修复 2: 绝对不活跃保护 (Absolute Inactivity Guard)
|
||||
|
||||
当距最后一个事件超过 `min(TIMEOUT, 90) × 2 = 180s` 且无任何新事件时,**无条件**推送错误并结束流。不受 `content_sent` / `thinking_started` / `running_tool_calls` 任何豁免条件限制。
|
||||
|
||||
### 修复 3: `session.abort()` 超时保护
|
||||
|
||||
所有 `session.abort()` 调用使用 `asyncio.wait_for(..., timeout=5.0)` 包裹。即使 abort RPC 自身卡住也不会阻塞主循环。
|
||||
|
||||
## 📊 修复后超时时间线
|
||||
|
||||
| 场景 | 保护机制 | 触发时间 |
|
||||
|------|----------|----------|
|
||||
| Turn 开始后完全无事件 | Primary Stall Detection | 90 秒 |
|
||||
| Agent 处理中突然断流 | Absolute Inactivity Guard | 180 秒 |
|
||||
| abort() 调用本身卡住 | asyncio.wait_for timeout | 5 秒 |
|
||||
| Turn 结束/Session 错误 | 兜底 running_tool_calls.clear() | 即时 |
|
||||
|
||||
---
|
||||
|
||||
*Created by Antigravity using Source-Code-Analyzer skill on 2026-03-18.*
|
||||
25
.agent/learnings/github-copilot-sdk-stream-finalization.md
Normal file
25
.agent/learnings/github-copilot-sdk-stream-finalization.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# GitHub Copilot SDK Stream Finalization
|
||||
|
||||
> Discovered: 2026-03-20
|
||||
|
||||
## Context
|
||||
Applies to `plugins/pipes/github-copilot-sdk/github_copilot_sdk.py` when streaming assistant output, handling `pending_embeds`, and waiting for `session.idle`.
|
||||
|
||||
## Finding
|
||||
Two non-obvious issues can make the pipe feel permanently stuck even when useful work already finished:
|
||||
|
||||
1. If the main `queue.get()` wait uses the full user-configured `TIMEOUT` (for example 300s), watchdog logic, "still working" status updates, and synthetic finalization checks only wake up at that same coarse interval.
|
||||
2. If `pending_embeds` are flushed only in the `session.idle` branch, any timeout/error/missing-idle path can lose already-prepared embeds even though file publishing itself succeeded.
|
||||
|
||||
## Solution / Pattern
|
||||
- Keep the *inactivity limit* controlled by `TIMEOUT`, but poll the local stream queue on a short fixed cadence (for example max 5s) so watchdogs and fallback finalization stay responsive.
|
||||
- Track `assistant.turn_end`; if `session.idle` does not arrive shortly afterward, synthesize finalization instead of waiting for the full inactivity timeout.
|
||||
- Flush `pending_embeds` exactly once via a shared helper that can run from both normal idle finalization and error/timeout finalization paths.
|
||||
- For streamed text/reasoning, use conservative overlap trimming: only strip an overlapping prefix when the incoming chunk still contains new suffix content. Do not drop fully repeated chunks blindly, or legitimate repeated text can be corrupted.
|
||||
|
||||
## Gotchas
|
||||
- RichUI embed success and streamed-text success are separate paths; a file can be published correctly while chat output still hangs or duplicates.
|
||||
- If `assistant.reasoning_delta` is streamed, the later complete `assistant.reasoning` event must be suppressed just like `assistant.message`, or the thinking block can duplicate.
|
||||
|
||||
## 🛠️ Update 2026-03-21
|
||||
- **Fixed Stream Duplication**: Fixed text stream overlays (e.g., `🎉 删 🎉 删除成功`) when resuming conversation session. Strictly applied `_dedupe_stream_chunk(delta, "message_stream_tail")` inside `assistant.message_delta` event handler to prevent concurrent history re-play or multiple stream delivery bug overlays, solving previous gaps in the deployment pipeline.
|
||||
45
.agent/learnings/openwebui-community-api.md
Normal file
45
.agent/learnings/openwebui-community-api.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# OpenWebUI Community API Patterns
|
||||
|
||||
## Post Data Structure Variations
|
||||
|
||||
When fetching posts from the OpenWebUI Community API (`https://api.openwebui.com/api/v1/posts/...`), the structure of the `data` field varies significantly depending on the `type` of the post.
|
||||
|
||||
### Observed Mappings
|
||||
|
||||
| Post Type | Data Key (under `data`) | Usual Content |
|
||||
|-----------|-------------------------|---------------|
|
||||
| `action` | `function` | Plugin code and metadata |
|
||||
| `filter` | `function` | Filter logic and metadata |
|
||||
| `pipe` | `function` | Pipe logic and metadata |
|
||||
| `tool` | `tool` | Tool definition and logic |
|
||||
| `prompt` | `prompt` | Prompt template strings |
|
||||
| `model` | `model` | Model configuration |
|
||||
|
||||
### Implementation Workaround
|
||||
|
||||
To robustly extract metadata (like `version` or `description`) regardless of the post type, the following heuristic logic is recommended:
|
||||
|
||||
```python
|
||||
def _get_plugin_obj(post: dict) -> dict:
|
||||
data = post.get("data", {}) or {}
|
||||
post_type = post.get("type")
|
||||
|
||||
# Priority 1: Use specific type key
|
||||
if post_type in data:
|
||||
return data[post_type]
|
||||
|
||||
# Priority 2: Fallback to common keys
|
||||
for k in ["function", "tool", "pipe"]:
|
||||
if k in data:
|
||||
return data[k]
|
||||
|
||||
# Priority 3: First available key
|
||||
if data:
|
||||
return list(data.values())[0]
|
||||
|
||||
return {}
|
||||
```
|
||||
|
||||
### Gotchas
|
||||
- Some older posts or different categories might not have a `version` field in `manifest`, leading to empty strings or `N/A` in reports.
|
||||
- `slug` should be used as the unique identifier rather than `title` when tracking stats across history.
|
||||
131
.agent/learnings/openwebui-mock-request.md
Normal file
131
.agent/learnings/openwebui-mock-request.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Building a Valid Mock Request for OpenWebUI Pipes
|
||||
|
||||
> Discovered: 2026-03-05
|
||||
|
||||
## Context
|
||||
|
||||
OpenWebUI Pipes run as a Pipe plugin, not as a real HTTP request handler. When the Pipe
|
||||
needs to call OpenWebUI-internal APIs (like `generate_chat_completion`, `get_tools`, etc.)
|
||||
or load Tools that do the same, it must provide a **fake-but-complete Request object**.
|
||||
|
||||
## Finding
|
||||
|
||||
OpenWebUI's internal functions expect `request` to satisfy several contracts:
|
||||
|
||||
```
|
||||
request.app.state.MODELS → dict { model_id: ModelModel } — MUST be populated!
|
||||
request.app.state.config → config object with all env variables
|
||||
request.app.state.TOOLS → dict (can start empty)
|
||||
request.app.state.FUNCTIONS → dict (can start empty)
|
||||
request.app.state.redis → None is fine
|
||||
request.app.state.TOOL_SERVERS → [] is fine
|
||||
request.app.url_path_for(name, **path_params) → str
|
||||
request.headers → dict with Authorization, host, user-agent
|
||||
request.state.user → user dict
|
||||
request.state.token.credentials → str (the Bearer token, without "Bearer " prefix)
|
||||
await request.json() → dict (the raw request body)
|
||||
await request.body() → bytes (the raw request body as JSON bytes)
|
||||
```
|
||||
|
||||
## Solution / Pattern
|
||||
|
||||
```python
|
||||
from types import SimpleNamespace
|
||||
import json as _json_mod
|
||||
|
||||
def _build_openwebui_request(user: dict, token: str, body: dict = None):
|
||||
from open_webui.config import PERSISTENT_CONFIG_REGISTRY
|
||||
from open_webui.models.models import Models as _Models
|
||||
|
||||
# 1. Build config from registry
|
||||
config = SimpleNamespace()
|
||||
for item in PERSISTENT_CONFIG_REGISTRY:
|
||||
val = item.value
|
||||
if hasattr(val, "value"):
|
||||
val = val.value
|
||||
setattr(config, item.env_name, val)
|
||||
|
||||
# 2. Populate MODELS from DB — critical for model validation
|
||||
system_models = {}
|
||||
try:
|
||||
for m in _Models.get_all_models():
|
||||
system_models[m.id] = m
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 3. Build app_state
|
||||
app_state = SimpleNamespace(
|
||||
config=config,
|
||||
TOOLS={},
|
||||
TOOL_CONTENTS={},
|
||||
FUNCTIONS={},
|
||||
FUNCTION_CONTENTS={},
|
||||
MODELS=system_models, # <-- KEY: must not be empty!
|
||||
redis=None,
|
||||
TOOL_SERVERS=[],
|
||||
)
|
||||
|
||||
# 4. url_path_for helper
|
||||
def url_path_for(name: str, **params):
|
||||
if name == "get_file_content_by_id":
|
||||
return f"/api/v1/files/{params.get('id')}/content"
|
||||
return f"/mock/{name}"
|
||||
|
||||
app = SimpleNamespace(state=app_state, url_path_for=url_path_for)
|
||||
|
||||
# 5. Async body helpers
|
||||
async def _json():
|
||||
return body or {}
|
||||
|
||||
async def _body_fn():
|
||||
return _json_mod.dumps(body or {}).encode("utf-8")
|
||||
|
||||
# 6. Headers
|
||||
headers = {
|
||||
"user-agent": "Mozilla/5.0",
|
||||
"host": "localhost:8080",
|
||||
"accept": "*/*",
|
||||
}
|
||||
if token:
|
||||
headers["Authorization"] = token if token.startswith("Bearer ") else f"Bearer {token}"
|
||||
|
||||
return SimpleNamespace(
|
||||
app=app,
|
||||
headers=headers,
|
||||
method="POST",
|
||||
cookies={},
|
||||
base_url="http://localhost:8080",
|
||||
url=SimpleNamespace(path="/api/chat/completions", base_url="http://localhost:8080"),
|
||||
state=SimpleNamespace(
|
||||
token=SimpleNamespace(credentials=token or ""),
|
||||
user=user or {},
|
||||
),
|
||||
json=_json,
|
||||
body=_body_fn,
|
||||
)
|
||||
```
|
||||
|
||||
## Token Extraction
|
||||
|
||||
Tokens can be found in multiple places. Check in order:
|
||||
|
||||
```python
|
||||
# 1. Direct in body (some SDK requests embed it)
|
||||
token = body.get("token")
|
||||
|
||||
# 2. In metadata
|
||||
token = token or (metadata or {}).get("token")
|
||||
|
||||
# 3. In the original __request__ Authorization header
|
||||
if not token and __request__ is not None:
|
||||
auth = getattr(__request__, "headers", {}).get("Authorization", "")
|
||||
if auth.startswith("Bearer "):
|
||||
token = auth.split(" ", 1)[1]
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`app.state.MODELS` empty = "Model not found"** for *any* model ID, even correct ones.
|
||||
- `TOOL_SERVER_CONNECTIONS` must be synced from DB, not from in-memory cache (stale in multi-worker).
|
||||
- `request.state.token.credentials` should be the **raw token** (no "Bearer " prefix).
|
||||
- Tools may call `await request.json()` — must be an async method, not a regular attribute.
|
||||
26
.agent/learnings/openwebui-tool-call-context-inflation.md
Normal file
26
.agent/learnings/openwebui-tool-call-context-inflation.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# OpenWebUI Tool Call Context Inflation
|
||||
|
||||
> Discovered: 2026-03-11
|
||||
|
||||
## Context
|
||||
When analyzing why the `async_context_compression` plugin sees different array lengths of `messages` between the `inlet` (e.g. 27 items) and `outlet` (e.g. 8 items) phases, especially when native tool calling (Function Calling) is involved in OpenWebUI.
|
||||
|
||||
## Finding
|
||||
There is a fundamental disparity in how OpenWebUI serializes conversational history at different stages of the request lifecycle:
|
||||
|
||||
1. **Outlet (UI Rendering View)**:
|
||||
After the LLM completes generation and tools have been executed, OpenWebUI's `middleware.py` (and streaming builders) bundles intermediate tool calls and their raw results. It hides them inside an HTML `<details type="tool_calls">...</details>` block within a single `role: assistant` message's `content`.
|
||||
Concurrently, the actual native API tool-calling data is saved in a hidden `output` dict field attached to that message. At this stage, the `messages` array looks short (e.g., 8 items) because tool interactions are visually folded.
|
||||
|
||||
2. **Inlet (LLM Native View)**:
|
||||
When the user sends the *next* message, the request enters `main.py` -> `process_chat_payload` -> `middleware.py:process_messages_with_output()`.
|
||||
Here, OpenWebUI scans historical `assistant` messages for that hidden `output` field. If found, it completely **inflates (unfolds)** the raw data back into an exact sequence of OpenAI-compliant `tool_call` and `tool_result` messages (using `utils/misc.py:convert_output_to_messages`).
|
||||
The HTML `<details>` string is entirely discarded before being sent to the LLM.
|
||||
|
||||
**Conclusion on Token Consumption**:
|
||||
In the next turn, tool context is **NOT** compressed at all. It is fully re-expanded to its original verbose state (e.g., back to 27 items) and consumes the maximum amount of tokens required by the raw JSON arguments and results.
|
||||
|
||||
## Gotchas
|
||||
- Any logic operating in the `outlet` phase (like background tasks) that relies on the `messages` array index will be completely misaligned with the array seen in the `inlet` phase.
|
||||
- Attempting to slice or trim history based on `outlet` array lengths will cause index out-of-bounds errors or destructive cropping of recent messages.
|
||||
- The only safe way to bridge these two views is either to translate the folded view back into the expanded view using `convert_output_to_messages`, or to rely on unique `id` fields (if available) rather than array indices.
|
||||
83
.agent/learnings/openwebui-tool-injection.md
Normal file
83
.agent/learnings/openwebui-tool-injection.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# OpenWebUI Tool Parameter Injection
|
||||
|
||||
> Discovered: 2026-03-05
|
||||
|
||||
## Context
|
||||
|
||||
When OpenWebUI loads a Python Tool and calls one of its functions (e.g. `generate_mind_map`),
|
||||
it automatically matches parameters from an `extra_params` dict against the function's
|
||||
signature **by name**. This is done in:
|
||||
|
||||
```
|
||||
open_webui/utils/tools.py → get_async_tool_function_and_apply_extra_params()
|
||||
```
|
||||
|
||||
The lookup is: `extra_params = {k: v for k, v in extra_params.items() if k in sig.parameters}`
|
||||
|
||||
## Finding
|
||||
|
||||
A Tool function declares its dependencies via its parameter names. Common injected names:
|
||||
|
||||
| Parameter Name | What it contains |
|
||||
|-----------------------|---------------------------------------------------|
|
||||
| `__user__` | User context dict (id, email, role, name) |
|
||||
| `__event_emitter__` | Async callable to emit status/notification events |
|
||||
| `__event_call__` | Async callable for JS `__event_call__` roundtrips |
|
||||
| `__request__` | Request-like object (must have `.app.state.MODELS`) |
|
||||
| `__metadata__` | Dict: `{model, base_model_id, chat_id, ...}` |
|
||||
| `__messages__` | Full conversation history list |
|
||||
| `__chat_id__` | Current chat UUID |
|
||||
| `__message_id__` | Current message UUID |
|
||||
| `__session_id__` | Current session UUID |
|
||||
| `__files__` | Files attached to the current message |
|
||||
| `__task__` | Task type string (e.g. `title_generation`) |
|
||||
| `body` | Raw request body dict (non-dunder variant) |
|
||||
| `request` | Request object (non-dunder variant) |
|
||||
|
||||
## Key Rule
|
||||
|
||||
**`extra_params` must contain ALL keys a Tool's function signature declares.**
|
||||
If a key is missing from `extra_params`, the parameter silently receives its default
|
||||
value (e.g. `{}` for `__metadata__`). This means the Tool appears to work but
|
||||
gets empty/wrong context.
|
||||
|
||||
## Solution / Pattern
|
||||
|
||||
When a Pipe calls an OpenWebUI Tool, it must populate `extra_params` with **all** the above:
|
||||
|
||||
```python
|
||||
extra_params = {
|
||||
"__request__": request, # Must have app.state.MODELS populated!
|
||||
"request": request, # Non-dunder alias
|
||||
"__user__": user_data,
|
||||
"__event_emitter__": __event_emitter__,
|
||||
"__event_call__": __event_call__,
|
||||
"__messages__": messages,
|
||||
"__metadata__": __metadata__ or {},
|
||||
"__chat_id__": chat_id,
|
||||
"__message_id__": message_id,
|
||||
"__session_id__": session_id,
|
||||
"__files__": files,
|
||||
"__task__": task,
|
||||
"__task_body__": task_body,
|
||||
"body": body, # Non-dunder alias
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Model Resolution
|
||||
|
||||
Tools that call `generate_chat_completion` internally need a **valid model ID**.
|
||||
When the conversation is running under a Pipe/Manifold model (e.g. `github_copilot.gpt-4o`),
|
||||
the Tool's `valves.MODEL_ID` must be a *real* model known to the system.
|
||||
|
||||
`generate_chat_completion` validates model IDs against `request.app.state.MODELS`.
|
||||
➡️ That dict **must be populated** from the database (see `openwebui-mock-request.md`).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Tools call `generate_chat_completion` with a `request` arg that must be the full Mock Request.
|
||||
- If `app.state.MODELS` is empty, even a correctly-spelled model ID will cause "Model not found".
|
||||
- `__metadata__['model']` can be a **dict** (from DB) **or a string** (manifold ID). Tools must
|
||||
handle both types.
|
||||
- For manifold models not in the DB, strip the prefix: `github_copilot.gpt-4o` → `gpt-4o`.
|
||||
27
.agent/learnings/richui-declarative-priority.md
Normal file
27
.agent/learnings/richui-declarative-priority.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# RichUI Declarative Priority
|
||||
|
||||
> Discovered: 2026-03-16
|
||||
|
||||
## Context
|
||||
This applies to the RichUI bridge embedded by `plugins/pipes/github-copilot-sdk/github_copilot_sdk.py` when HTML pages mix declarative `data-openwebui-prompt` / `data-prompt` actions with inline `onclick` handlers.
|
||||
|
||||
## Finding
|
||||
Mixing declarative prompt/link attributes with inline click handlers can cause duplicate prompt submission paths, especially when both the page and the bridge react to the same click.
|
||||
|
||||
## Solution / Pattern
|
||||
The bridge now treats inline `onclick` as the default owner of click behavior. Declarative prompt/link dispatch is skipped when an element already has inline click logic.
|
||||
|
||||
If a page intentionally wants declarative bridge handling even with inline handlers present, mark the element explicitly:
|
||||
|
||||
```html
|
||||
<button
|
||||
onclick="trackClick()"
|
||||
data-openwebui-prompt="Explain this chart"
|
||||
data-openwebui-force-declarative="1"
|
||||
>
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
Without the explicit override, keyboard/click dispatch for declarative actions will yield to inline `onclick`.
|
||||
|
||||
The bridge also keeps a short same-prompt dedupe window in `sendPrompt()` as a safety net, but the preferred fix is still to avoid mixed ownership unless you opt in deliberately.
|
||||
23
.agent/learnings/richui-default-actions-optout.md
Normal file
23
.agent/learnings/richui-default-actions-optout.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# RichUI Default Action Opt-Out
|
||||
|
||||
> Discovered: 2026-03-16
|
||||
|
||||
## Context
|
||||
This applies to RichUI embeds generated by `plugins/pipes/github-copilot-sdk/github_copilot_sdk.py`, especially when a specific embed should render state without fallback prompt or link actions.
|
||||
|
||||
## Finding
|
||||
The RichUI bridge can add fallback action buttons based on declarative prompt/link metadata. Static embeds can explicitly opt out when their HTML includes `data-openwebui-no-default-actions="1"` or `data-openwebui-static-widget="1"`.
|
||||
|
||||
## Solution / Pattern
|
||||
Mark the embed root with both attributes and keep the embed wrapped through `_prepare_richui_embed_html(...)` when you explicitly want to suppress fallback actions.
|
||||
|
||||
Example:
|
||||
|
||||
```html
|
||||
<div class="w" data-openwebui-no-default-actions="1" data-openwebui-static-widget="1">
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
If the opt-out markers are missing, RichUI fallback actions can reappear even after interactive row handlers have been removed from the widget itself.
|
||||
|
||||
This opt-out only suppresses fallback prompt/link injection. It does not affect the SQL-driven TODO refresh path, which still re-emits the widget through `type: embeds` after `todos` or `todo_deps` updates.
|
||||
89
.agent/learnings/richui-interaction-api.md
Normal file
89
.agent/learnings/richui-interaction-api.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# RichUI Interaction API
|
||||
|
||||
> Discovered: 2026-03-16
|
||||
|
||||
## Context
|
||||
This applies to RichUI HTML embeds generated by `plugins/pipes/github-copilot-sdk/github_copilot_sdk.py` when the page needs to talk back to the OpenWebUI chat UI.
|
||||
|
||||
## Finding
|
||||
The most reliable design is a small recommended interaction surface with only four primary actions:
|
||||
|
||||
1. continue chat now
|
||||
2. prefill chat input without sending
|
||||
3. submit the current chat input
|
||||
4. open an external link
|
||||
|
||||
Keeping the recommended API this small reduces LLM choice overload and makes multilingual HTML generation more consistent.
|
||||
|
||||
Advanced capabilities still exist, but they are intentionally treated as opt-in patterns rather than the default contract:
|
||||
|
||||
- copy text to clipboard
|
||||
- structured selection state
|
||||
- template-based prompt/copy actions driven by current selections
|
||||
|
||||
## Solution / Pattern
|
||||
Prefer declarative attributes first:
|
||||
|
||||
```html
|
||||
<!-- 1. Continue chat immediately -->
|
||||
<button data-openwebui-prompt="Explain this workflow step by step">Explain</button>
|
||||
|
||||
<!-- 2. Prefill the chat input only -->
|
||||
<button
|
||||
data-openwebui-prompt="Draft a rollout checklist for this design"
|
||||
data-openwebui-action="fill"
|
||||
>
|
||||
Draft in input
|
||||
</button>
|
||||
|
||||
<!-- 3. Submit the current chat input -->
|
||||
<button data-openwebui-action="submit">Send current draft</button>
|
||||
|
||||
<!-- 4. Open a real URL -->
|
||||
<a data-openwebui-link="https://docs.example.com">Docs</a>
|
||||
```
|
||||
|
||||
When JavaScript is genuinely needed, prefer the object methods:
|
||||
|
||||
```javascript
|
||||
window.OpenWebUIBridge.prompt(text);
|
||||
window.OpenWebUIBridge.fill(text);
|
||||
window.OpenWebUIBridge.submit();
|
||||
window.OpenWebUIBridge.openLink(url);
|
||||
window.OpenWebUIBridge.reportHeight();
|
||||
```
|
||||
|
||||
Use advanced patterns only when the page genuinely needs them:
|
||||
|
||||
```html
|
||||
<!-- Copy -->
|
||||
<button data-openwebui-copy="npm run build && npm test">Copy command</button>
|
||||
|
||||
<!-- Pick a structured selection -->
|
||||
<button data-openwebui-select="role" data-openwebui-value="reviewer">
|
||||
Reviewer
|
||||
</button>
|
||||
|
||||
<!-- Use the current selection in a follow-up action -->
|
||||
<button data-openwebui-prompt-template="Explain the responsibilities of {{role}}">
|
||||
Explain selected role
|
||||
</button>
|
||||
```
|
||||
|
||||
### Quick decision guide
|
||||
|
||||
- Need an immediate answer now → `data-openwebui-prompt`
|
||||
- Need the user to review/edit first → `data-openwebui-action="fill"`
|
||||
- Need to send what is already in chat input → `data-openwebui-action="submit"`
|
||||
- Need to open an external resource → `data-openwebui-link`
|
||||
- Need copy UX → `data-openwebui-copy`
|
||||
- Need pick-then-act UX → `data-openwebui-select` + template placeholder
|
||||
|
||||
For most pages, keep to one dominant interaction style and only 2-4 visible actions.
|
||||
|
||||
## Gotchas
|
||||
Inline `onclick` owns click behavior by default. If an element mixes inline click code with declarative prompt/link attributes, declarative handling is skipped unless `data-openwebui-force-declarative="1"` is present.
|
||||
|
||||
Legacy aliases such as `sendPrompt(...)` still work for compatibility, but new generated pages should prefer the smaller object-method API or the declarative contract above.
|
||||
|
||||
The bridge still keeps a short same-prompt dedupe window as a safety net, but the preferred design is to avoid mixed ownership in the first place.
|
||||
30
.agent/learnings/richui-theme-source-separation.md
Normal file
30
.agent/learnings/richui-theme-source-separation.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# RichUI Theme Source Separation
|
||||
|
||||
> Discovered: 2026-03-20
|
||||
|
||||
## Context
|
||||
Applies to the RichUI bridge in `plugins/pipes/github-copilot-sdk/github_copilot_sdk.py` when syncing iframe or standalone HTML theme with OpenWebUI.
|
||||
|
||||
## Finding
|
||||
Theme detection must not read back bridge-applied local theme markers as if they were the upstream source of truth.
|
||||
|
||||
If the bridge writes `html[data-theme]` or `html.dark` in standalone/current-document mode and then also reads those same markers during detection, the theme can self-latch and stop following real source changes such as `meta[name="theme-color"]` updates or `prefers-color-scheme` changes.
|
||||
|
||||
## Solution / Pattern
|
||||
Keep theme **detection** and theme **application** separate.
|
||||
|
||||
When embedded in OpenWebUI, follow the same stable detection order used by `smart-mind-map`:
|
||||
|
||||
1. `parent document` `meta[name="theme-color"]`
|
||||
2. `parent document` `html/body` class or `html[data-theme]`
|
||||
3. `prefers-color-scheme`
|
||||
|
||||
Only if there is no accessible parent document should the bridge fall back to the current document's `meta[name="theme-color"]` and `html/body` theme signals.
|
||||
|
||||
- Always write the resolved theme to a dedicated bridge marker such as `data-openwebui-applied-theme`.
|
||||
- Only mirror generic `html[data-theme]` / `html.dark` markers when a real parent document exists, so standalone fallback does not pollute its own detection source.
|
||||
- If internal widget CSS needs dark-mode styling in standalone mode, target the dedicated marker too (for example `html[data-openwebui-applied-theme="dark"]`).
|
||||
|
||||
## Gotchas
|
||||
- Watching `style` mutations is unnecessary once detection no longer reads computed style or inline color-scheme.
|
||||
- If standalone mode needs to honor page-owned `html.dark` or `html[data-theme]`, do not overwrite those markers just to style the bridge itself; use the dedicated bridge marker instead.
|
||||
@@ -138,6 +138,18 @@ Before completing an antigravity operation, confirm:
|
||||
- [ ] 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
|
||||
- [ ] Non-obvious findings / gotchas are saved to `.agent/learnings/{topic}.md`
|
||||
|
||||
---
|
||||
|
||||
## Mandatory: Knowledge Capture
|
||||
|
||||
Any non-obvious pattern, internal API contract, or workaround discovered during an
|
||||
antigravity session **MUST** be saved to `.agent/learnings/{topic}.md` before the
|
||||
session ends. This ensures hard-won insights are not lost between sessions.
|
||||
|
||||
**Format**: See `.agent/learnings/README.md`
|
||||
**Existing entries**: Browse `.agent/learnings/` for prior knowledge to reuse.
|
||||
|
||||
---
|
||||
|
||||
@@ -145,3 +157,4 @@ Before completing an antigravity operation, confirm:
|
||||
|
||||
- Full engineering spec: `.github/copilot-instructions.md` → Section: **Antigravity Development Mode**
|
||||
- Design document: `docs/development/copilot-engineering-plan.md` → Section 5
|
||||
- Knowledge base: `.agent/learnings/` — reusable engineering patterns and gotchas
|
||||
|
||||
@@ -18,16 +18,18 @@ All plugins MUST follow the standard README template.
|
||||
|
||||
### Metadata Requirements
|
||||
|
||||
The metadata line must follow this format:
|
||||
`**Author:** [Name](Link) | **Version:** [X.Y.Z] | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT`
|
||||
Follow the header table used in the template:
|
||||
`| By [Fu-Jie](https://github.com/Fu-Jie) · vX.Y.Z | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |`
|
||||
|
||||
### Structure Checklist
|
||||
|
||||
1. **Title & Description**
|
||||
2. **Metadata Line** (Author, Version, Project, License)
|
||||
3. **Preview** (Screenshots/GIFs)
|
||||
4. **What's New** (Keep last 3 versions)
|
||||
5. **Key Features**
|
||||
6. **How to Use**
|
||||
7. **Configuration (Valves)**
|
||||
8. **Troubleshooting** (Must include link to GitHub Issues)
|
||||
2. **Header Metadata Table** (Author, version, repo star link)
|
||||
3. **Preview** (Screenshot, GIF, or a short note if preview is not ready)
|
||||
4. **Install with Batch Install Plugins** (Include the fixed prompt block)
|
||||
Use the generic prompt `Install plugin from Fu-Jie/openwebui-extensions` instead of hard-coding the plugin name.
|
||||
5. **What's New** (Keep last 1-3 versions)
|
||||
6. **Key Features**
|
||||
7. **How to Use**
|
||||
8. **Configuration (Valves)**
|
||||
9. **Troubleshooting** (Must include link to GitHub Issues and mention official-version conflict if relevant)
|
||||
|
||||
71
.agent/skills/README.md
Normal file
71
.agent/skills/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# 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`
|
||||
|
||||
---
|
||||
|
||||
## Release Pipeline Skills
|
||||
|
||||
These four skills form a complete release pipeline and are designed to be used in sequence:
|
||||
|
||||
```
|
||||
release-prep → pr-submitter → pr-reviewer → release-finalizer
|
||||
(prepare) (push & PR) (respond to review) (merge & close issue)
|
||||
```
|
||||
|
||||
- **release-prep**
|
||||
- Purpose: Full release preparation — version sync across 7+ files, bilingual release notes creation, consistency check, and commit.
|
||||
- Entry: `release-prep/SKILL.md`
|
||||
|
||||
- **pr-submitter**
|
||||
- Purpose: Shell-escape-safe PR submission — writes body to temp file, validates sections, pushes branch, creates PR via `gh pr create --body-file`.
|
||||
- Entry: `pr-submitter/SKILL.md`
|
||||
|
||||
- **pr-reviewer**
|
||||
- Purpose: Fetch PR review comments, categorize feedback, implement fixes, commit and push, reply to reviewers.
|
||||
- Entry: `pr-reviewer/SKILL.md`
|
||||
|
||||
- **release-finalizer**
|
||||
- Purpose: Merge release PR to main with proper commit message, auto-link and close related issues, post closing messages.
|
||||
- Entry: `release-finalizer/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
.agent/skills/community-announcer/SKILL.md
Normal file
23
.agent/skills/community-announcer/SKILL.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
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.
|
||||
50
.agent/skills/doc-mirror-sync/SKILL.md
Normal file
50
.agent/skills/doc-mirror-sync/SKILL.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
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`.
|
||||
|
||||
## Docs-Only Mode (No Release Changes)
|
||||
Use this mode when the request is "only sync docs".
|
||||
|
||||
- Only update documentation mirror files under `docs/plugins/**`.
|
||||
- Do **not** bump plugin version.
|
||||
- Do **not** modify plugin code (`plugins/**.py`) unless explicitly requested.
|
||||
- Do **not** update root badges/dates for release.
|
||||
- Do **not** run release preparation steps.
|
||||
|
||||
## Workflow
|
||||
1. Identify changed READMEs.
|
||||
2. Copy content to corresponding mirror paths.
|
||||
3. Update version badges in `docs/plugins/{type}/index.md`.
|
||||
|
||||
## Commands
|
||||
|
||||
### Sync all mirrors (EN + ZH)
|
||||
|
||||
```bash
|
||||
python .github/skills/doc-mirror-sync/scripts/sync.py
|
||||
```
|
||||
|
||||
### Sync only one plugin (EN only)
|
||||
|
||||
```bash
|
||||
cp plugins/<type>/<name>/README.md docs/plugins/<type>/<name>.md
|
||||
```
|
||||
|
||||
### Sync only one plugin (EN + ZH)
|
||||
|
||||
```bash
|
||||
cp plugins/<type>/<name>/README.md docs/plugins/<type>/<name>.md
|
||||
cp plugins/<type>/<name>/README_CN.md docs/plugins/<type>/<name>.zh.md
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- If asked for English-only update, sync only `README.md` -> `.md` mirror.
|
||||
- If both languages are requested, sync both `README.md` and `README_CN.md`.
|
||||
- After syncing, verify git diff only contains docs file changes.
|
||||
38
.agent/skills/doc-mirror-sync/scripts/sync.py
Normal file
38
.agent/skills/doc-mirror-sync/scripts/sync.py
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/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
.agent/skills/gh-issue-replier/SKILL.md
Normal file
51
.agent/skills/gh-issue-replier/SKILL.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
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>`.
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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
|
||||
45
.agent/skills/gh-issue-replier/references/templates.md
Normal file
45
.agent/skills/gh-issue-replier/references/templates.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# 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!"
|
||||
31
.agent/skills/gh-issue-replier/scripts/check_star.sh
Executable file
31
.agent/skills/gh-issue-replier/scripts/check_star.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/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
.agent/skills/gh-issue-scheduler/SKILL.md
Normal file
42
.agent/skills/gh-issue-scheduler/SKILL.md
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
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)
|
||||
42
.agent/skills/gh-issue-scheduler/scripts/find_unanswered.sh
Executable file
42
.agent/skills/gh-issue-scheduler/scripts/find_unanswered.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/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
.agent/skills/i18n-validator/SKILL.md
Normal file
14
.agent/skills/i18n-validator/SKILL.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
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.
|
||||
54
.agent/skills/i18n-validator/scripts/validate_i18n.py
Normal file
54
.agent/skills/i18n-validator/scripts/validate_i18n.py
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/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
.agent/skills/plugin-scaffolder/SKILL.md
Normal file
19
.agent/skills/plugin-scaffolder/SKILL.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
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
|
||||
34
.agent/skills/plugin-scaffolder/assets/README_template.md
Normal file
34
.agent/skills/plugin-scaffolder/assets/README_template.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# {{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.
|
||||
80
.agent/skills/plugin-scaffolder/assets/template.py
Normal file
80
.agent/skills/plugin-scaffolder/assets/template.py
Normal file
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
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
|
||||
80
.agent/skills/plugin-scaffolder/assets/template.py.j2
Normal file
80
.agent/skills/plugin-scaffolder/assets/template.py.j2
Normal file
@@ -0,0 +1,80 @@
|
||||
"""
|
||||
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
|
||||
66
.agent/skills/plugin-scaffolder/scripts/scaffold.py
Normal file
66
.agent/skills/plugin-scaffolder/scripts/scaffold.py
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/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])
|
||||
180
.agent/skills/pr-reviewer/SKILL.md
Normal file
180
.agent/skills/pr-reviewer/SKILL.md
Normal file
@@ -0,0 +1,180 @@
|
||||
---
|
||||
name: pr-reviewer
|
||||
description: Fetches PR review comments, analyzes requested changes, implements fixes, commits and pushes the resolution. Use after a reviewer has left comments on an open PR to close the feedback loop efficiently.
|
||||
---
|
||||
|
||||
# PR Reviewer
|
||||
|
||||
## Overview
|
||||
|
||||
This skill automates the response cycle for code review. When a reviewer leaves comments on a Pull Request, this skill fetches all pending feedback, categorizes issues by severity, implements fixes, and submits a follow-up commit with appropriate review response comments.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An open PR exists with pending review comments
|
||||
- The local branch matches the PR's head branch
|
||||
- `gh` CLI is authenticated
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1 — Fetch Review State
|
||||
|
||||
Retrieve all review comments and overall review status:
|
||||
|
||||
```bash
|
||||
# Get overall review decisions
|
||||
PAGER=cat GH_PAGER=cat gh pr view <PR-NUMBER> --json reviews,reviewDecision,headRefName \
|
||||
--jq '{decision: .reviewDecision, reviews: [.reviews[] | {author: .author.login, state: .state, body: .body}]}'
|
||||
|
||||
# Get inline code comments (specific line comments)
|
||||
PAGER=cat GH_PAGER=cat gh api repos/Fu-Jie/openwebui-extensions/pulls/<PR-NUMBER>/comments \
|
||||
--jq '[.[] | {path: .path, line: .line, body: .body, author: .user.login, id: .id}]'
|
||||
|
||||
# Get general issue comments
|
||||
PAGER=cat GH_PAGER=cat gh issue view <PR-NUMBER> --comments --json comments \
|
||||
--jq '[.comments[] | {author: .author.login, body: .body}]'
|
||||
```
|
||||
|
||||
Confirm the current local branch matches the PR head:
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
If mismatched, checkout the correct branch first.
|
||||
|
||||
### Step 2 — Categorize Review Feedback
|
||||
|
||||
Group feedback into categories:
|
||||
|
||||
| Category | Examples | Action |
|
||||
|----------|---------|--------|
|
||||
| **Code Bug** | Logic error, incorrect variable, broken condition | Fix code immediately |
|
||||
| **Style / Formatting** | Indentation, naming convention, missing blank line | Fix code |
|
||||
| **Documentation** | Missing i18n key, wrong version in README, typo | Fix docs |
|
||||
| **Design Question** | Suggestion to restructure, alternative approach | Discuss with user before implementing |
|
||||
| **Nitpick / Optional** | Minor style preferences reviewer marked as optional | Fix if quick; document if skipped |
|
||||
| **Blocking** | Reviewer explicitly blocks merge | Must fix before proceeding |
|
||||
|
||||
Present the full categorized list to the user and confirm the resolution plan.
|
||||
|
||||
### Step 3 — Implement Fixes
|
||||
|
||||
For each accepted fix:
|
||||
|
||||
1. Read the affected file at the commented line for context:
|
||||
```bash
|
||||
sed -n '<line-5>,<line+10>p' <file-path>
|
||||
```
|
||||
2. Apply the fix using appropriate file edit tools
|
||||
3. After editing, verify the specific area looks correct
|
||||
|
||||
**For code changes that might affect behavior:**
|
||||
- Check if tests exist: `ls tests/test_*.py`
|
||||
- If tests exist, run them: `python -m pytest tests/ -v`
|
||||
|
||||
**For documentation fixes:**
|
||||
- If modifying README.md, check if `docs/` mirror needs the same fix
|
||||
- Apply the same fix to both locations
|
||||
|
||||
### Step 4 — Run Consistency Checks
|
||||
|
||||
After all fixes are applied:
|
||||
|
||||
```bash
|
||||
# Version consistency (if any version files were touched)
|
||||
python3 scripts/check_version_consistency.py
|
||||
|
||||
# Quick syntax check for Python files
|
||||
python3 -m py_compile plugins/{type}/{name}/{name}.py && echo "✅ Syntax OK"
|
||||
```
|
||||
|
||||
### Step 5 — Stage and Commit
|
||||
|
||||
Create a new commit (do NOT amend if the branch has already been pushed, to avoid force-push):
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git status
|
||||
```
|
||||
|
||||
Draft a Conventional Commits message for the fixup:
|
||||
|
||||
Format: `fix(scope): address review feedback`
|
||||
|
||||
Body should list what was fixed, referencing reviewer concerns:
|
||||
```
|
||||
fix(github-copilot-sdk): address review feedback from @reviewer
|
||||
|
||||
- Fix X per review comment on line Y of file Z
|
||||
- Update README to clarify auth requirement
|
||||
- Correct edge case in _parse_mcp_servers logic
|
||||
```
|
||||
|
||||
```bash
|
||||
git commit -m "<fixup commit message>"
|
||||
```
|
||||
|
||||
### Step 6 — Push the Fix Commit
|
||||
|
||||
```bash
|
||||
git push origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
**Force-push policy:**
|
||||
- Use `git push` (non-force) by default
|
||||
- Only use `git push --force-with-lease` if:
|
||||
1. The user explicitly requests it, AND
|
||||
2. The only change is an amended commit squash (cosmetic, no logic change)
|
||||
3. Never use `--force` (without `--lease`)
|
||||
|
||||
### Step 7 — Respond to Reviewers
|
||||
|
||||
For each addressed review comment, post a reply:
|
||||
|
||||
```bash
|
||||
# Reply to inline comment
|
||||
gh api repos/Fu-Jie/openwebui-extensions/pulls/<PR-NUMBER>/comments/<COMMENT-ID>/replies \
|
||||
-X POST -f body="Fixed in commit <SHORT-SHA>. <Brief explanation of what was changed.>"
|
||||
|
||||
# General comment to summarize all fixes
|
||||
gh issue comment <PR-NUMBER> --body "All review feedback addressed in commit <SHORT-SHA>:
|
||||
- Fixed: <item 1>
|
||||
- Fixed: <item 2>
|
||||
Ready for re-review. 🙏"
|
||||
```
|
||||
|
||||
### Step 8 — Re-Request Review (Optional)
|
||||
|
||||
If the reviewer had submitted a `CHANGES_REQUESTED` review, request a new review after fixes:
|
||||
|
||||
```bash
|
||||
PAGER=cat GH_PAGER=cat gh api repos/Fu-Jie/openwebui-extensions/pulls/<PR-NUMBER>/requested_reviewers \
|
||||
-X POST -f reviewers[]='<reviewer-login>'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Decision Guide
|
||||
|
||||
### When NOT to implement a suggestion immediately
|
||||
|
||||
- **Design questions**: "Should this be a separate class?" — Present to user for decision
|
||||
- **Optional nitpicks**: Reviewer marked as `nit:` — Ask user if they want to include it
|
||||
- **Large refactors**: If fix would require changing >50 lines, propose a separate follow-up issue instead
|
||||
|
||||
### When to ask the user before proceeding
|
||||
|
||||
- Any fix involving behavioral changes to plugin logic
|
||||
- Renaming Valve keys (breaking change — requires migration notes)
|
||||
- Changes that affect the bilingual release notes already committed
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- ❌ Do NOT `git commit --amend` on a pushed commit without user approval for force-push
|
||||
- ❌ Do NOT silently skip a reviewer's comment; always acknowledge it (implement or explain why not)
|
||||
- ❌ Do NOT use `--force` (only `--force-with-lease` when absolutely necessary)
|
||||
- ❌ Do NOT make unrelated changes in the fixup commit; keep scope focused on review feedback
|
||||
- ❌ Do NOT respond to reviewer comments in Chinese if the PR language context is English
|
||||
194
.agent/skills/pr-submitter/SKILL.md
Normal file
194
.agent/skills/pr-submitter/SKILL.md
Normal file
@@ -0,0 +1,194 @@
|
||||
---
|
||||
name: pr-submitter
|
||||
description: Submits a feature branch as a Pull Request with a validated, properly formatted bilingual PR body. Handles shell-escape-safe body writing via temp files. Use after release-prep has committed all changes.
|
||||
---
|
||||
|
||||
# PR Submitter
|
||||
|
||||
## Overview
|
||||
|
||||
This skill handles the final step of pushing a feature branch and creating a validated Pull Request on GitHub. Its primary purpose is to avoid the shell-escaping pitfalls (backticks, special characters in `gh pr create --body`) by always writing the PR body to a **temp file** first.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- All changes are committed (use `release-prep` skill first)
|
||||
- The `gh` CLI is authenticated (`gh auth status`)
|
||||
- Current branch is NOT `main` or `master`
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 0 — Initialize Temp Directory (Project-Based)
|
||||
|
||||
For all temporary files, use the project's `.temp/` directory instead of system `/tmp`:
|
||||
|
||||
```bash
|
||||
# Create temp directory if it doesn't exist
|
||||
mkdir -p .temp
|
||||
```
|
||||
|
||||
**Why**: All temporary files stay within the project workspace, avoiding system `/tmp` pollution and better aligning with OpenWebUI workspace isolation principles.
|
||||
|
||||
### Step 1 — Pre-Flight Checks
|
||||
|
||||
Run these checks before any push:
|
||||
|
||||
```bash
|
||||
# 1. Confirm not on protected branch
|
||||
git branch --show-current
|
||||
|
||||
# 2. Verify there are commits to push
|
||||
git log origin/$(git branch --show-current)..HEAD --oneline 2>/dev/null || echo "No remote tracking branch yet"
|
||||
|
||||
# 3. Check gh CLI auth
|
||||
gh auth status
|
||||
```
|
||||
|
||||
If any check fails, stop and report clearly.
|
||||
|
||||
### Step 2 — Collect PR Metadata
|
||||
|
||||
Gather:
|
||||
- **PR Title**: Must follow Conventional Commits format, English only (e.g., `feat(github-copilot-sdk): release v0.8.0 with conditional tool filtering`)
|
||||
- **Target base branch**: Default is `main`
|
||||
- **Plugin name + version** (to build body sections)
|
||||
- **Key changes** (reuse from release-prep or the latest What's New section)
|
||||
|
||||
### Step 3 — Build PR Body File (Shell-Escape-Safe)
|
||||
|
||||
**Always write the body to a temp file in `.temp/` directory.** Never embed multi-line markdown with special characters directly in a shell command.
|
||||
|
||||
```bash
|
||||
cat > .temp/pr_body.md << 'HEREDOC'
|
||||
## Summary
|
||||
|
||||
Brief one-sentence description of what this PR accomplishes.
|
||||
|
||||
## Changes
|
||||
|
||||
### New Features
|
||||
- Feature 1 description
|
||||
- Feature 2 description
|
||||
|
||||
### Bug Fixes
|
||||
- Fix 1 description
|
||||
|
||||
## Plugin Version
|
||||
- `PluginName` bumped to `vX.X.X`
|
||||
|
||||
## Documentation
|
||||
- README.md / README_CN.md updated
|
||||
- docs/ mirrors synced
|
||||
|
||||
## Testing
|
||||
- [ ] Tested locally in OpenWebUI
|
||||
- [ ] i18n validated (all language keys present)
|
||||
- [ ] Version consistency check passed (`python3 scripts/check_version_consistency.py`)
|
||||
|
||||
---
|
||||
|
||||
## 变更摘要(中文)
|
||||
|
||||
简要描述本次 PR 的改动内容。
|
||||
|
||||
### 新功能
|
||||
- 功能1描述
|
||||
- 功能2描述
|
||||
|
||||
### 问题修复
|
||||
- 修复1描述
|
||||
HEREDOC
|
||||
```
|
||||
|
||||
**Critical rules for the body file:**
|
||||
- Use `<< 'HEREDOC'` (quoted heredoc) to prevent variable expansion
|
||||
- Keep all backticks literal — they are safe inside a heredoc
|
||||
- Paths like `/api/v1/files/` are safe too since heredoc doesn't interpret them as commands
|
||||
|
||||
### Step 4 — Validate PR Body
|
||||
|
||||
Before submitting, verify the body file contains expected sections:
|
||||
|
||||
```bash
|
||||
# Check key sections exist
|
||||
grep -q "## Summary" .temp/pr_body.md && echo "✅ Summary" || echo "❌ Summary missing"
|
||||
grep -q "## Changes" .temp/pr_body.md && echo "✅ Changes" || echo "❌ Changes missing"
|
||||
grep -q "## 变更摘要" .temp/pr_body.md && echo "✅ CN Section" || echo "❌ CN Section missing"
|
||||
|
||||
# Preview the body
|
||||
cat .temp/pr_body.md
|
||||
```
|
||||
|
||||
Ask the user to confirm the body content before proceeding.
|
||||
|
||||
### Step 5 — Push Branch
|
||||
|
||||
```bash
|
||||
git push -u origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
If push is rejected (non-fast-forward), report to user and ask whether to force-push. **Do NOT force-push without explicit confirmation.**
|
||||
|
||||
### Step 6 — Create Pull Request
|
||||
|
||||
```bash
|
||||
gh pr create \
|
||||
--base main \
|
||||
--head $(git branch --show-current) \
|
||||
--title "<PR title from Step 2>" \
|
||||
--body-file .temp/pr_body.md
|
||||
```
|
||||
|
||||
Always use `--body-file`, never `--body` with inline markdown.
|
||||
|
||||
### Step 7 — Verify PR Creation
|
||||
|
||||
```bash
|
||||
PAGER=cat GH_PAGER=cat gh pr view --json number,url,title,body --jq '{number: .number, url: .url, title: .title, body_preview: .body[:200]}'
|
||||
```
|
||||
|
||||
Confirm:
|
||||
- PR number and URL
|
||||
- Title matches intended Conventional Commits format
|
||||
- Body preview includes key sections (not truncated/corrupted)
|
||||
|
||||
If the body appears corrupted (empty sections, missing backtick content), use edit:
|
||||
|
||||
```bash
|
||||
gh pr edit <PR-NUMBER> --body-file /tmp/pr_body.md
|
||||
```
|
||||
|
||||
### Step 8 — Cleanup
|
||||
|
||||
```bash
|
||||
rm -f .temp/pr_body.md
|
||||
```
|
||||
|
||||
**Note**: The `.temp/` directory itself is preserved for reuse; only the individual PR body file is deleted. To fully clean up: `rm -rf .temp/`
|
||||
|
||||
Report final PR URL to the user.
|
||||
|
||||
---
|
||||
|
||||
## Shell-Escape Safety Rules
|
||||
|
||||
| Risk | Safe Approach |
|
||||
|------|--------------|
|
||||
| Backticks in `--body` | Write to file, use `--body-file` |
|
||||
| Paths like `/api/...` | Safe in heredoc; risky in inline `--body` |
|
||||
| Newlines in `--body` | File-based only |
|
||||
| `$variable` expansion | Use `<< 'HEREDOC'` (quoted) |
|
||||
| Double quotes in body | Safe in heredoc file |
|
||||
| Temp file storage | Use `.temp/` dir, not `/tmp` |
|
||||
| Cleanup after use | Always delete temp file (keep dir) |
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- ❌ Never use `--body "..."` with multi-line content directly in shell command
|
||||
- ❌ Never interpolate variables directly into heredoc without quoting the delimiter
|
||||
- ❌ Never force-push (`--force`) without explicit user confirmation
|
||||
- ❌ Never target `main` as the source branch (only as base)
|
||||
- ❌ Never skip the body validation step — a PR with empty body is worse than a delayed PR
|
||||
208
.agent/skills/release-finalizer/SKILL.md
Normal file
208
.agent/skills/release-finalizer/SKILL.md
Normal file
@@ -0,0 +1,208 @@
|
||||
---
|
||||
name: release-finalizer
|
||||
description: Merges a release PR, associates it with resolved issues, replies to issue reporters, and closes issues. Use after PR review is complete and ready for merge. Closes the release cycle.
|
||||
---
|
||||
|
||||
# Release Finalizer
|
||||
|
||||
## Overview
|
||||
|
||||
This skill completes the final step of the release cycle: merging the release PR to `main`, replying to all related issues with solutions, and automatically closing them using GitHub's issue linking mechanism.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The PR is in `OPEN` state and ready to merge
|
||||
- All status checks have passed (CI green)
|
||||
- All review feedback has been addressed
|
||||
- The PR relates to one or more GitHub issues (either in PR description or through commits)
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1 — Pre-Merge Verification
|
||||
|
||||
Verify that the PR is ready:
|
||||
|
||||
```bash
|
||||
PAGER=cat GH_PAGER=cat gh pr view <PR-NUMBER> --json state,statusCheckRollup,reviewDecision
|
||||
```
|
||||
|
||||
Checklist:
|
||||
- ✅ `state` is `OPEN`
|
||||
- ✅ `statusCheckRollup` all have `conclusion: SUCCESS`
|
||||
- ✅ `reviewDecision` is `APPROVED` or empty (no blocking reviews)
|
||||
|
||||
If any check fails, **do NOT merge**. Report the issue to the user.
|
||||
|
||||
### Step 2 — Identify Related Issues
|
||||
|
||||
Issues can be linked to a PR in multiple ways. Check the PR description and commit messages for keywords:
|
||||
|
||||
```bash
|
||||
PAGER=cat GH_PAGER=cat gh pr view <PR-NUMBER> --json body,commits
|
||||
```
|
||||
|
||||
Look for patterns like:
|
||||
- `Closes #XX`, `Fixes #XX`, `Resolves #XX` (in description or commit bodies)
|
||||
- `#XX` mentioned as "related to" or "addresses"
|
||||
|
||||
**Manual input**: If issue links are not in the PR, ask the user which issue(s) this PR resolves.
|
||||
|
||||
Extract all issue numbers into a list: `[#48, #52, ...]`
|
||||
|
||||
### Step 3 — Select Merge Strategy
|
||||
|
||||
Offer the user three options:
|
||||
|
||||
| Strategy | Git Behavior | Use Case |
|
||||
|----------|-------------|----------|
|
||||
| **Squash** | All commits squashed into one commit on main | Clean history, recommended for release PRs |
|
||||
| **Rebase** | Linear history, no merge commit | Preserve commit granularity |
|
||||
| **Merge** | Merge commit created | Preserve full PR context |
|
||||
|
||||
**Recommendation for release PRs**: Use `--squash` to create a single clean commit.
|
||||
|
||||
If user doesn't specify, default to `--squash`.
|
||||
|
||||
### Step 4 — Prepare Merge Commit Message
|
||||
|
||||
If using `--squash`, craft a single comprehensive commit message:
|
||||
|
||||
**Format** (Conventional Commits + Github linking):
|
||||
```
|
||||
type(scope): description
|
||||
|
||||
- Bullet point 1
|
||||
- Bullet point 2
|
||||
|
||||
Closes #48
|
||||
Closes #52
|
||||
```
|
||||
|
||||
The `Closes #XX` keyword tells GitHub to automatically close those issues when the commit lands on `main`.
|
||||
|
||||
Example:
|
||||
```
|
||||
feat(pipes,filters): release Copilot SDK Pipe v0.8.0 and Files Filter v0.1.3
|
||||
|
||||
- Implement P1~P4 conditional tool filtering system
|
||||
- Fix file publishing reliability across all storage backends
|
||||
- Add strict file URL validation
|
||||
- Update bilingual documentation
|
||||
|
||||
Closes #48
|
||||
```
|
||||
|
||||
### Step 5 — Execute Merge
|
||||
|
||||
```bash
|
||||
gh pr merge <PR-NUMBER> \
|
||||
--squash \
|
||||
--delete-branch \
|
||||
-m "type(scope): description" \
|
||||
-b "- Bullet 1\n- Bullet 2\n\nCloses #48"
|
||||
```
|
||||
|
||||
**Key flags:**
|
||||
- `--squash`: Squash commits (recommended for releases)
|
||||
- `--delete-branch`: Delete the feature branch after merge
|
||||
- `-m`: Commit subject
|
||||
- `-b`: Commit body (supports `\n` for newlines)
|
||||
|
||||
Confirm the merge is successful; GitHub will automatically close related issues with `Closes #XX` keyword.
|
||||
|
||||
### Step 6 — Verify Auto-Close
|
||||
|
||||
GitHub automatically closes issues when a commit with `Closes #XX` lands on the default branch (`main`).
|
||||
|
||||
To verify:
|
||||
```bash
|
||||
PAGER=cat GH_PAGER=cat gh issue view <ISSUE-NUMBER> --json state
|
||||
```
|
||||
|
||||
Should show `state: CLOSED`.
|
||||
|
||||
### Step 7 — Post Closing Message (Optional but Recommended)
|
||||
|
||||
For better UX, manually post a summary comment to **each issue** before it auto-closes (since auto-close happens silently):
|
||||
|
||||
```bash
|
||||
gh issue comment <ISSUE-NUMBER> --body "
|
||||
This has been fixed in PR #<PR-NUMBER>, which is now merged to main.
|
||||
|
||||
**Solution Summary:**
|
||||
- <Key fix 1>
|
||||
- <Key fix 2>
|
||||
|
||||
The fix will be available in the next plugin release. Thank you for reporting! ⭐
|
||||
"
|
||||
```
|
||||
|
||||
### Step 8 — (Optional) Regenerate Release Notes
|
||||
|
||||
If the merge revealed any final tweaks to release notes:
|
||||
|
||||
```bash
|
||||
# Re-export release notes from merged commit
|
||||
git log --oneline -1 <merged-commit-sha>
|
||||
```
|
||||
|
||||
If needed, create a follow-up PR with doc polish (do NOT force-push the merged commit).
|
||||
|
||||
---
|
||||
|
||||
## Merge Strategy Decision Tree
|
||||
|
||||
```
|
||||
Is this a patch/hotfix release?
|
||||
├─ YES → Use --squash
|
||||
└─ NO → Multi-feature release?
|
||||
├─ YES → Use --squash (cleaner history)
|
||||
└─ NO → Preserve detail?
|
||||
├─ YES → Use --rebase
|
||||
└─ NO → Use --merge (preserve PR context)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Issue Auto-Close Keywords
|
||||
|
||||
These keywords in commit/PR messages will auto-close issues when merged to `main`:
|
||||
|
||||
- `Closes #XX`
|
||||
- `Fixes #XX`
|
||||
- `Resolves #XX`
|
||||
- `close #XX` (case-insensitive)
|
||||
- `fix #XX`
|
||||
- `resolve #XX`
|
||||
|
||||
**Important**: The keyword must be on the **final commit that lands on** `main`. For squash merges, it must be in the squash commit message body.
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- ❌ Do NOT merge if any status checks are PENDING or FAILED
|
||||
- ❌ Do NOT merge if there are blocking reviews (reviewDecision: `CHANGES_REQUESTED`)
|
||||
- ❌ Do NOT merge without verifying the Conventional Commits format in the merge message
|
||||
- ❌ Do NOT merge without including `Closes #XX` keywords for all related issues
|
||||
- ❌ Do NOT assume issues will auto-close silently — post a courtesy comment first
|
||||
- ❌ Do NOT delete the branch if it might be needed for cherry-pick or hotfixes later
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue did not auto-close after merge
|
||||
- Verify the `Closes #XX` keyword is in the **final commit message** (use `git log` to check)
|
||||
- Ensure the commit is on the `main` branch
|
||||
- GitHub sometimes takes a few seconds to process; refresh the issue page
|
||||
|
||||
### Multiple issues to close
|
||||
- List all in separate `Closes #XX` lines in the commit body
|
||||
- Each one will be independently auto-closed
|
||||
|
||||
### Want to close issue without merge?
|
||||
- Use `gh issue close <ISSUE-NUMBER>` manually
|
||||
- Only recommended if the PR was manually reverted or deemed invalid
|
||||
157
.agent/skills/release-prep/SKILL.md
Normal file
157
.agent/skills/release-prep/SKILL.md
Normal file
@@ -0,0 +1,157 @@
|
||||
---
|
||||
name: release-prep
|
||||
description: Orchestrates the full release preparation flow for a plugin — version sync across 7+ files, bilingual release notes creation, and commit message drafting. Use before submitting a PR. Does NOT push or create a PR; that is handled by pr-submitter.
|
||||
---
|
||||
|
||||
# Release Prep
|
||||
|
||||
## Overview
|
||||
|
||||
This skill drives the complete pre-PR release pipeline. It enforces the repository rule that every release must synchronize the version number and changelog across **at least 7 locations** before a commit is created.
|
||||
|
||||
## Scope
|
||||
|
||||
This skill covers:
|
||||
1. Version sync (delegates detail to `version-bumper` if needed)
|
||||
2. Bilingual release notes file creation
|
||||
3. 7-location consistency verification
|
||||
4. Conventional Commits message drafting
|
||||
5. `git add -A && git commit` execution
|
||||
|
||||
It **stops before** `git push` or `gh pr create`. Use the `pr-submitter` skill for those steps.
|
||||
|
||||
### Temporary File Convention
|
||||
|
||||
Any temporary files created during release prep (e.g., draft changelogs) must:
|
||||
- Be written to the project's `.temp/` directory, **NOT** system `/tmp`
|
||||
- Be cleaned up before commit using `rm -f .temp/file_name`
|
||||
- Never be committed to git (add `.temp/` to `.gitignore`)
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1 — Collect Release Info
|
||||
|
||||
Ask the user (or infer from current state) the following:
|
||||
- **Plugin name** and **type** (actions / filters / pipes / tools)
|
||||
- **New version number** (e.g., `0.8.0`)
|
||||
- **Key changes** in English and Chinese (1-5 bullet points each)
|
||||
|
||||
If a `What's New` section already exists in README.md, extract it as the source of truth.
|
||||
|
||||
### Step 2 — Sync Version Across 7 Locations
|
||||
|
||||
Verify AND update the version string in all of the following. Mark each as ✅ or ❌:
|
||||
|
||||
| # | File | Location |
|
||||
|---|------|----------|
|
||||
| 1 | `plugins/{type}/{name}/{name}.py` | `version:` in docstring |
|
||||
| 2 | `plugins/{type}/{name}/README.md` | `**Version:** x.x.x` metadata line |
|
||||
| 3 | `plugins/{type}/{name}/README_CN.md` | `**Version:** x.x.x` metadata line |
|
||||
| 4 | `docs/plugins/{type}/{name}.md` | `**Version:** x.x.x` metadata line |
|
||||
| 5 | `docs/plugins/{type}/{name}.zh.md` | `**Version:** x.x.x` metadata line |
|
||||
| 6 | `docs/plugins/{type}/index.md` | version badge for this plugin |
|
||||
| 7 | `docs/plugins/{type}/index.zh.md` | version badge for this plugin |
|
||||
|
||||
Additionally update the root-level **updated date badge** in:
|
||||
- `README.md` — ``
|
||||
- `README_CN.md` — same badge format
|
||||
|
||||
Use today's date (`YYYY-MM-DD`) for the badge.
|
||||
|
||||
### Step 3 — Update What's New (All 4 Doc Files)
|
||||
|
||||
The `What's New` / `最新更新` section must contain **only the most recent release's changes**. Previous entries should be removed from this section (they live in CHANGELOG or release notes files).
|
||||
|
||||
Update these 4 files' `What's New` / `最新更新` block consistently:
|
||||
- `plugins/{type}/{name}/README.md`
|
||||
- `plugins/{type}/{name}/README_CN.md`
|
||||
- `docs/plugins/{type}/{name}.md`
|
||||
- `docs/plugins/{type}/{name}.zh.md`
|
||||
|
||||
### Step 4 — Create Bilingual Release Notes Files
|
||||
|
||||
Create two versioned release notes files:
|
||||
|
||||
**Path**: `plugins/{type}/{name}/v{version}.md`
|
||||
**Path**: `plugins/{type}/{name}/v{version}_CN.md`
|
||||
|
||||
#### Required Sections
|
||||
|
||||
Each file must include:
|
||||
1. **Title**: `# v{version} Release Notes` (EN) / `# v{version} 版本发布说明` (CN)
|
||||
2. **Overview**: One paragraph summarizing this release
|
||||
3. **New Features** / **新功能**: Bulleted list of features
|
||||
4. **Bug Fixes** / **问题修复**: Bulleted list of fixes
|
||||
5. **Migration Notes** / **迁移说明**: Breaking changes or Valve key renames (omit section if none)
|
||||
6. **Companion Plugins** / **配套插件** (optional): If a companion plugin was updated
|
||||
|
||||
If a release notes file already exists for this version, update it rather than creating a new one.
|
||||
|
||||
#### Full Coverage Rule (Mandatory)
|
||||
|
||||
Release notes must cover **all updates in the current release scope** and not only headline features.
|
||||
|
||||
Minimum required coverage in both EN/CN files:
|
||||
- New features and capability enhancements
|
||||
- Bug fixes and reliability fixes
|
||||
- Documentation/README/doc-mirror updates that affect user understanding or usage
|
||||
- Terminology/i18n/wording fixes that change visible behavior or messaging
|
||||
|
||||
Before commit, cross-check release notes against `git diff` and ensure no meaningful update is omitted.
|
||||
|
||||
### Step 5 — Verify Consistency (Pre-Commit Check)
|
||||
|
||||
Run the consistency check script:
|
||||
|
||||
```bash
|
||||
python3 scripts/check_version_consistency.py
|
||||
```
|
||||
|
||||
If issues are found, fix them before proceeding. Do not commit with inconsistencies.
|
||||
|
||||
### Step 6 — Draft Conventional Commits Message
|
||||
|
||||
Generate the commit message following `commit-message.instructions.md` rules:
|
||||
- **Language**: English ONLY
|
||||
- **Format**: `type(scope): subject` + blank line + body bullets
|
||||
- **Scope**: use plugin folder name (e.g., `github-copilot-sdk`)
|
||||
- **Body**: 1-3 bullets summarizing key changes
|
||||
- Explicitly mention "READMEs and docs synced" if version was bumped
|
||||
|
||||
Present the full commit message to the user for review before executing.
|
||||
|
||||
### Step 7 — Stage and Commit
|
||||
|
||||
After user approval (or if user says "commit it"):
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "<approved commit message>"
|
||||
```
|
||||
|
||||
Confirm the commit hash and list the number of files changed.
|
||||
|
||||
---
|
||||
|
||||
## Checklist (Auto-Verify Before Commit)
|
||||
|
||||
- [ ] `version:` in `.py` docstring matches target version
|
||||
- [ ] `**Version:**` in all 4 README/docs files matches
|
||||
- [ ] Both `index.md` version badges updated
|
||||
- [ ] Root `README.md` and `README_CN.md` date badges updated to today
|
||||
- [ ] `What's New` / `最新更新` contains ONLY the latest release
|
||||
- [ ] Release notes include all meaningful updates from the current diff (feature + fix + docs/i18n)
|
||||
- [ ] `v{version}.md` and `v{version}_CN.md` created or updated
|
||||
- [ ] `python3 scripts/check_version_consistency.py` returns no errors
|
||||
- [ ] Commit message is English-only Conventional Commits format
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- ❌ Do NOT add extra features or refactor code during release prep — only version/doc updates
|
||||
- ❌ Do NOT push or create PR in this skill — use `pr-submitter`
|
||||
- ❌ Do NOT use today's date in commit messages; only in badge URLs
|
||||
- ❌ Do NOT leave stale What's New content from prior versions
|
||||
31
.agent/skills/source-code-analyzer/SKILL.md
Normal file
31
.agent/skills/source-code-analyzer/SKILL.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
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)
|
||||
- **Open Terminal**: `../open-terminal/` (Terminal integration service)
|
||||
|
||||
### 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.
|
||||
@@ -18,7 +18,7 @@ This is a **universal testing framework** for publishing the latest `github_copi
|
||||
|
||||
| Attribute | Fixed Value |
|
||||
|------|--------|
|
||||
| **Deployment Script** | `/Users/fujie/app/python/oui/openwebui-extensions/scripts/update_pipe.py` |
|
||||
| **Deployment Script** | `/Users/fujie/app/python/oui/openwebui-extensions/scripts/deploy_pipe.py` |
|
||||
| **Python Path** | `/opt/homebrew/Caskroom/miniconda/base/envs/ai/bin/python3` |
|
||||
| **Test URL** | `http://localhost:3003/?model=github_copilot_official_sdk_pipe.github_copilot_sdk-gpt-4.1` |
|
||||
|
||||
@@ -36,11 +36,11 @@ Example: *Modified tool calling logic -> Test prompt should trigger a specific t
|
||||
Use the `run_command` tool to execute the fixed update task:
|
||||
|
||||
```bash
|
||||
/opt/homebrew/Caskroom/miniconda/base/envs/ai/bin/python3 /Users/fujie/app/python/oui/openwebui-extensions/scripts/update_pipe.py
|
||||
/opt/homebrew/Caskroom/miniconda/base/envs/ai/bin/python3 /Users/fujie/app/python/oui/openwebui-extensions/scripts/deploy_pipe.py
|
||||
```
|
||||
|
||||
> **Mechanism**: `update_pipe.py` automatically loads the API Key from `scripts/.env` in the same directory.
|
||||
> **Verification**: Look for `✅ Successfully updated... version X.X.X`. If a 401 error occurs, remind the user to generate a new API Key in OpenWebUI and update `.env`.
|
||||
> **Mechanism**: `deploy_pipe.py` automatically loads the API Key from `scripts/.env` in the same directory.
|
||||
> **Verification**: Look for `✅ Successfully updated... version X.X.X` or `✅ Successfully created...`. If a 401 error occurs, remind the user to generate a new API Key in OpenWebUI and update `.env`.
|
||||
|
||||
### Step 3: Verify via Browser Subagent (Verify)
|
||||
|
||||
|
||||
26
.agent/skills/version-bumper/SKILL.md
Normal file
26
.agent/skills/version-bumper/SKILL.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
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
.agent/skills/version-bumper/scripts/bump.py
Normal file
70
.agent/skills/version-bumper/scripts/bump.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/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])
|
||||
@@ -140,6 +140,7 @@ Before committing:
|
||||
- [ ] `docs/` index and detail pages are updated?
|
||||
- [ ] Root `README.md` is updated?
|
||||
- [ ] All version numbers match exactly?
|
||||
- [ ] Any non-obvious findings saved to `.agent/learnings/{topic}.md`?
|
||||
|
||||
## 5. Git Operations (Agent Rules)
|
||||
|
||||
@@ -147,3 +148,12 @@ Before committing:
|
||||
2. **No Auto-Commit**: Never `git commit`, `git push`, or `create_pull_request` automatically after file updates unless the user explicitly says "commit this" or "release now".
|
||||
3. **Draft Mode**: If available, use PRs as drafts first.
|
||||
4. **Reference**: Strictly follow the rules defined in `.github/copilot-instructions.md` → **Git Operations (Agent Rules)** section.
|
||||
|
||||
## 6. Knowledge Capture (Mandatory)
|
||||
|
||||
Whenever you discover a non-obvious behaviour, internal API contract, or workaround
|
||||
during plugin development, **document it in `.agent/learnings/{topic}.md`** before
|
||||
ending the session.
|
||||
|
||||
- Browse `.agent/learnings/` **first** at the start of a session to reuse existing knowledge.
|
||||
- Format: see `.agent/learnings/README.md`.
|
||||
|
||||
173
.continues-handoff.md
Normal file
173
.continues-handoff.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Session Handoff Context
|
||||
|
||||
|
||||
## Session Overview
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Source** | GitHub Copilot CLI |
|
||||
| **Session ID** | `231b2651-f3bf-4a24-8680-5ad9d2cdcd22` |
|
||||
| **Working Directory** | `/Users/fujie/app/python/oui/openwebui-extensions` |
|
||||
| **Session File** | `~/.copilot/session-state/231b2651-f3bf-4a24-8680-5ad9d2cdcd22` |
|
||||
| **Repository** | Fu-Jie/openwebui-extensions @ `main` |
|
||||
| **Last Active** | 2026-03-16 14:08 |
|
||||
| **Files Modified** | 0 |
|
||||
| **Messages** | 1 |
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
> Implement RichUI Embed Bridge
|
||||
|
||||
|
||||
## Tool Activity
|
||||
|
||||
### Shell (17 calls)
|
||||
|
||||
> `$ cd /Users/fujie/app/python/oui/openwebui-extensions && git status --short && echo "---" && git log --oneline -3`
|
||||
|
||||
> `$ q`
|
||||
|
||||
> `$ cd /Users/fujie/app/python/oui/openwebui-extensions && git --no-pager status --short --branch`
|
||||
|
||||
> `$ cd /Users/fujie/app/python/oui/openwebui-extensions && diff -u --label main/plugins/pipes/github-copilot-sdk/github_copilot_sdk.py plugins/pipes/github-copilot-sdk/github_copilot_sdk.py --label worktree/.git-worktrees/github-copilot-sdk-richui/plugins/pipes/github-copilot-sdk/github_copilot_sdk.py .git-worktrees/github-copilot-sdk-richui/plugins/pipes/github-copilot-sdk/github_copilot_sdk.py | sed -n '1,260p'`
|
||||
|
||||
> `$ python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
src = Path('/Users/fujie/app/python/oui/openwebui-extensions/.git-worktrees/github-copilot-sdk-richui/plugins/pipes/github-copilot-sdk/github_copilot_sdk.py')
|
||||
dst = Path('/Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/github_copilot_sdk.py')
|
||||
dst.write_text(src.read_text(encoding='utf-8'), encoding='utf-8')
|
||||
print(f'copied {src} -> {dst}')
|
||||
PY
|
||||
cd /Users/fujie/app/python/oui/openwebui-extensions && git --no-pager diff --stat -- plugins/pipes/github-copilot-sdk/github_copilot_sdk.py`
|
||||
|
||||
*...and 12 more shell calls (all exit 0)*
|
||||
|
||||
|
||||
### Edit (10 calls)
|
||||
|
||||
> **``**
|
||||
|
||||
> **``**
|
||||
|
||||
> **``**
|
||||
|
||||
> **``**
|
||||
|
||||
> **``**
|
||||
|
||||
*...and 5 more edits*
|
||||
|
||||
|
||||
### Glob (7 calls)
|
||||
|
||||
- `plan.md`
|
||||
- `**/example.py`
|
||||
- `**/test*github*copilot*sdk*.py`
|
||||
- `**/*github*copilot*sdk*.py`
|
||||
- `plugins/pipes/github-copilot-sdk/tests/**/*.py`
|
||||
- *...and 2 more glob calls*
|
||||
|
||||
|
||||
### MCP (51 calls)
|
||||
|
||||
- `view({"path":"/Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk"})`
|
||||
- `view({"path":"/Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/github_co)`
|
||||
- `view({"path":"/Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/example.p)`
|
||||
- `view({"path":"/Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/github_co)`
|
||||
- `view({"path":"/Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/github_co)`
|
||||
- *...and 46 more*
|
||||
|
||||
|
||||
### MCP (20 calls)
|
||||
|
||||
- `report_intent({"intent":"Reviewing RichUI fix"})`
|
||||
- `report_intent({"intent":"Syncing RichUI changes"})`
|
||||
- `report_intent({"intent":"Planning sync work"})`
|
||||
- `report_intent({"intent":"Syncing SDK file"})`
|
||||
- `report_intent({"intent":"Verifying SDK sync"})`
|
||||
- *...and 15 more*
|
||||
|
||||
|
||||
### MCP (1 calls)
|
||||
|
||||
- `stop_bash({"shellId":"0"})`
|
||||
|
||||
|
||||
### MCP (40 calls)
|
||||
|
||||
- `rg({"pattern":"_build_todo_widget_html|_prepare_richui_embed_html|input:prompt:submit|data-prompt|ready)`
|
||||
- `rg({"pattern":"def _prepare_richui_embed_html|def _build_todo_widget_html|def _emit_todo_widget_if_chan)`
|
||||
- `rg({"pattern":"def _prepare_richui_embed_html|RICHUI_BRIDGE_MARKER|RICHUI_BRIDGE_STYLE|RICHUI_BRIDGE_SC)`
|
||||
- `rg({"pattern":"pending_embeds|type\": \"embeds\"|Content-Disposition|inline|richui|_write_todo_widget_h)`
|
||||
- `rg({"pattern":"_emit_todo_widget_if_changed\\(","path":"/Users/fujie/app/python/oui/openwebui-extension)`
|
||||
- *...and 35 more*
|
||||
|
||||
|
||||
### MCP (18 calls)
|
||||
|
||||
- `sql({"description":"Create sync todos","query":"INSERT OR REPLACE INTO todos (id, title, description, st)`
|
||||
- `sql({"description":"Keep compare todo active","query":"UPDATE todos SET status = 'in_progress' WHERE id )`
|
||||
- `sql({"description":"Advance sync todos","query":"UPDATE todos SET status = 'done' WHERE id = 'compare-wo)`
|
||||
- `sql({"description":"Advance verify todo","query":"UPDATE todos SET status = 'done' WHERE id = 'apply-ric)`
|
||||
- `sql({"description":"Complete verification todo","query":"UPDATE todos SET status = 'done' WHERE id = 've)`
|
||||
- *...and 13 more*
|
||||
|
||||
|
||||
### MCP (4 calls)
|
||||
|
||||
- `store_memory({"subject":"richui widgets","fact":"Static RichUI widgets should set data-openwebui-no-default-actio)`
|
||||
- `store_memory({"subject":"richui widgets","fact":"github_copilot_sdk RichUI opt-out markers are optional; fallback)`
|
||||
- `store_memory({"subject":"richui interactions","fact":"RichUI bridge now lets inline onclick own click behavior by)`
|
||||
- `store_memory({"subject":"richui api","fact":"Recommended RichUI interaction contract is 4 actions: data-openwebui)`
|
||||
|
||||
|
||||
### MCP (6 calls)
|
||||
|
||||
- `ide-get_diagnostics({"uri":"file:///Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/git)`
|
||||
- `ide-get_diagnostics({"uri":"file:///Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/git)`
|
||||
- `ide-get_diagnostics({"uri":"file:///Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/git)`
|
||||
- `ide-get_diagnostics({"uri":"file:///Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/git)`
|
||||
- `ide-get_diagnostics({"uri":"file:///Users/fujie/app/python/oui/openwebui-extensions/plugins/pipes/github-copilot-sdk/git)`
|
||||
- *...and 1 more*
|
||||
|
||||
|
||||
|
||||
## Recent Conversation
|
||||
|
||||
### Assistant
|
||||
|
||||
已优化,而且我把交互协议收敛成了 **4 个推荐动作**,专门减少大模型选择困难。
|
||||
|
||||
推荐写法现在是:
|
||||
|
||||
- `data-openwebui-prompt="..."`:立即继续对话
|
||||
- `data-openwebui-prompt="..." data-openwebui-action="fill"`:只填输入框,不发送
|
||||
- `data-openwebui-action="submit"`:提交当前输入框
|
||||
- `data-openwebui-link="https://..."`:打开链接
|
||||
|
||||
JS 推荐也同步收敛为:
|
||||
|
||||
- `window.OpenWebUIBridge.prompt(text)`
|
||||
- `window.OpenWebUIBridge.fill(text)`
|
||||
- `window.OpenWebUIBridge.submit()`
|
||||
- `window.OpenWebUIBridge.openLink(url)`
|
||||
- `window.OpenWebUIBridge.reportHeight()`
|
||||
|
||||
另外我做了两点稳定性优化:
|
||||
|
||||
- `onclick` 默认优先,避免和 de…
|
||||
|
||||
|
||||
## Session Origin
|
||||
|
||||
This session was extracted from **GitHub Copilot CLI** session data.
|
||||
- **Session file**: `~/.copilot/session-state/231b2651-f3bf-4a24-8680-5ad9d2cdcd22`
|
||||
- **Session ID**: `231b2651-f3bf-4a24-8680-5ad9d2cdcd22`
|
||||
- **Project directory**: `/Users/fujie/app/python/oui/openwebui-extensions`
|
||||
|
||||
> To access the raw session data, inspect the file path above.
|
||||
|
||||
---
|
||||
|
||||
**You are continuing this session. Pick up exactly where it left off — review the conversation above, check pending tasks, and keep going.**
|
||||
8
.cursorrules
Normal file
8
.cursorrules
Normal file
@@ -0,0 +1,8 @@
|
||||
# 🤖 Cursor/Gemini Multi-Agent Protocol
|
||||
|
||||
1. **STATUS CHECK**: Always run `python3 scripts/agent_sync.py status` first.
|
||||
2. **REGISTRATION**: Run `python3 scripts/agent_sync.py register gemini-id "Gemini" "Current task"`.
|
||||
3. **LOCKING**: Never edit without `python3 scripts/agent_sync.py lock gemini-id <path>`.
|
||||
4. **STANDARDS**: Refer to `.agent/rules/plugin_standards.md` for coding guidelines.
|
||||
|
||||
Full details in `COOPERATION.md`.
|
||||
@@ -8,7 +8,43 @@ description: Automatically synchronizes plugin READMEs to the official documenta
|
||||
## Overview
|
||||
Automates the mirroring of `plugins/{type}/{name}/README.md` to `docs/plugins/{type}/{name}.md`.
|
||||
|
||||
## Docs-Only Mode (No Release Changes)
|
||||
Use this mode when the request is "only sync docs".
|
||||
|
||||
- Only update documentation mirror files under `docs/plugins/**`.
|
||||
- Do **not** bump plugin version.
|
||||
- Do **not** modify plugin code (`plugins/**.py`) unless explicitly requested.
|
||||
- Do **not** update root badges/dates for release.
|
||||
- Do **not** run release preparation steps.
|
||||
|
||||
## Workflow
|
||||
1. Identify changed READMEs.
|
||||
2. Copy content to corresponding mirror paths.
|
||||
3. Update version badges in `docs/plugins/{type}/index.md`.
|
||||
|
||||
## Commands
|
||||
|
||||
### Sync all mirrors (EN + ZH)
|
||||
|
||||
```bash
|
||||
python .github/skills/doc-mirror-sync/scripts/sync.py
|
||||
```
|
||||
|
||||
### Sync only one plugin (EN only)
|
||||
|
||||
```bash
|
||||
cp plugins/<type>/<name>/README.md docs/plugins/<type>/<name>.md
|
||||
```
|
||||
|
||||
### Sync only one plugin (EN + ZH)
|
||||
|
||||
```bash
|
||||
cp plugins/<type>/<name>/README.md docs/plugins/<type>/<name>.md
|
||||
cp plugins/<type>/<name>/README_CN.md docs/plugins/<type>/<name>.zh.md
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- If asked for English-only update, sync only `README.md` -> `.md` mirror.
|
||||
- If both languages are requested, sync both `README.md` and `README_CN.md`.
|
||||
- After syncing, verify git diff only contains docs file changes.
|
||||
|
||||
@@ -73,11 +73,21 @@ Create two versioned release notes files:
|
||||
#### Required Sections
|
||||
|
||||
Each file must include:
|
||||
1. **Title**: `# v{version} Release Notes` (EN) / `# v{version} 版本发布说明` (CN)
|
||||
2. **Overview**: One paragraph summarizing this release
|
||||
3. **New Features** / **新功能**: Bulleted list of features
|
||||
4. **Bug Fixes** / **问题修复**: Bulleted list of fixes
|
||||
5. **Migration Notes** / **迁移说明**: Breaking changes or Valve key renames (omit section if none)
|
||||
0. **Marketplace Badge**: A prominent button linking to the plugin on openwebui.com using shields.io (e.g., `[](URL)`).
|
||||
1. **Overview Header**: Use `## Overview` as the first header.
|
||||
2. **Summary Paragraph**: A paragraph summarizing the release. **NEVER** include the version number as a title.
|
||||
3. **README Link**: Direct link to the plugin's README file on GitHub.
|
||||
4. **New Features** / **新功能**: Bulleted list of features
|
||||
5. **Bug Fixes** / **问题修复**: Bulleted list of fixes
|
||||
6. **Related Issues** / **相关 Issue**: Link to GitHub Issues. **ONLY** include if a specific issue is resolved. **NEVER use placeholders.**
|
||||
7. **Related PRs** / **相关 PR**: Link to the Pull Request. **ONLY** include if the PR is already created and the ID is known. **NEVER use placeholders.**
|
||||
8. **Migration Notes**: Breaking changes or Valve key renames (omit section if none)
|
||||
|
||||
---
|
||||
|
||||
## Language Standard
|
||||
|
||||
- **Release Notes Files**: Use **English ONLY** for the final `.md` files to maintain professional consistency on GitHub. Avoid bilingual content in the release description.
|
||||
6. **Companion Plugins** / **配套插件** (optional): If a companion plugin was updated
|
||||
|
||||
If a release notes file already exists for this version, update it rather than creating a new one.
|
||||
@@ -98,8 +108,10 @@ Generate the commit message following `commit-message.instructions.md` rules:
|
||||
- **Language**: English ONLY
|
||||
- **Format**: `type(scope): subject` + blank line + body bullets
|
||||
- **Scope**: use plugin folder name (e.g., `github-copilot-sdk`)
|
||||
- **Body**: 1-3 bullets summarizing key changes
|
||||
- Explicitly mention "READMEs and docs synced" if version was bumped
|
||||
- **Body**:
|
||||
- 1-3 bullets summarizing key changes
|
||||
- Explicitly mention "READMEs and docs synced" if version was bumped
|
||||
- **MUST** end with `Closes #XX` or `Fixes #XX` if an issue is being resolved.
|
||||
|
||||
Present the full commit message to the user for review before executing.
|
||||
|
||||
|
||||
165
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
165
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
name: 🐛 Bug Report
|
||||
description: Report a bug or issue with OpenWebUI plugins
|
||||
title: "[BUG] "
|
||||
labels: ["bug"]
|
||||
assignees: []
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for reporting a bug! Please provide clear information to help us reproduce and fix the issue.
|
||||
|
||||
- type: dropdown
|
||||
id: plugin-type
|
||||
attributes:
|
||||
label: Plugin Type
|
||||
description: Which type of plugin is affected?
|
||||
options:
|
||||
- Action
|
||||
- Filter
|
||||
- Pipe
|
||||
- Pipeline
|
||||
- Tool
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: plugin-name
|
||||
attributes:
|
||||
label: Plugin Name
|
||||
description: Which plugin has the issue?
|
||||
options:
|
||||
- "Select a plugin..."
|
||||
- "Action - Deep Dive"
|
||||
- "Action - Export to Word Enhanced"
|
||||
- "Action - Export to Excel"
|
||||
- "Action - Flash Card"
|
||||
- "Action - Smart Infographic"
|
||||
- "Action - Smart Mind Map"
|
||||
- "Filter - Async Context Compression"
|
||||
- "Filter - Context & Model Enhancement Filter"
|
||||
- "Filter - Folder Memory"
|
||||
- "Filter - GitHub Copilot SDK Files Filter"
|
||||
- "Filter - Markdown Normalizer"
|
||||
- "Filter - Gemini Multimodel Filter"
|
||||
- "Pipeline - MOE Prompt Refiner"
|
||||
- "Pipe - GitHub Copilot SDK"
|
||||
- "Pipe - iFlow SDK"
|
||||
- "Tool - OpenWebUI Skills Manager"
|
||||
- "Tool - Smart Infographic Tool"
|
||||
- "Tool - Smart Mind Map Tool"
|
||||
- "Other / Not Listed"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: plugin-name-other
|
||||
attributes:
|
||||
label: Plugin Name (if not in list)
|
||||
description: If you selected 'Other / Not Listed', please specify the plugin name
|
||||
placeholder: "Plugin name"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Clearly describe the bug. What went wrong? What did you expect?
|
||||
placeholder: |
|
||||
I tried to use [feature], but instead of [expected behavior], it [actual behavior].
|
||||
|
||||
Error message (if any):
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: How can we reproduce this issue?
|
||||
placeholder: |
|
||||
1. Click on...
|
||||
2. Enter...
|
||||
3. See error...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: openwebui-version
|
||||
attributes:
|
||||
label: OpenWebUI Version
|
||||
description: What version of OpenWebUI are you using?
|
||||
placeholder: "e.g., 0.3.0 or main"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Operating System & Container
|
||||
description: "Your operating system and deployment method"
|
||||
placeholder: |
|
||||
Example 1:
|
||||
OS: macOS 14.3
|
||||
Container: Docker (version 24.0.x)
|
||||
|
||||
Example 2:
|
||||
OS: Ubuntu 22.04 LTS
|
||||
Deployment: Docker Compose
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## 📋 Debug Information (Optional)
|
||||
|
||||
To help diagnose the issue faster, please provide relevant logs:
|
||||
|
||||
**Frontend Console Logs** (Recommended):
|
||||
1. Enable: Click avatar → Settings → General → Enable Plugin Debug Output
|
||||
2. Open DevTools: Press `F12` (or `Cmd+Option+I` on Mac)
|
||||
3. Go to Console tab and copy any error messages or `🛠️ Debug` output
|
||||
|
||||
**Server-Side Logs**:
|
||||
- Docker: `docker logs <container-id>`
|
||||
- Local: Check terminal output or log files
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Error Logs (Optional)
|
||||
description: "Paste frontend console or server logs that show the error"
|
||||
placeholder: |
|
||||
Error message from console:
|
||||
[Your logs here]
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Information (Optional)
|
||||
description: "Screenshots, related issues, or other helpful details"
|
||||
placeholder: |
|
||||
- Screenshots (if applicable)
|
||||
- Related issues or discussions
|
||||
- Steps you've already tried to fix it
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: I have searched for duplicate issues
|
||||
required: true
|
||||
- label: I have provided clear reproduction steps
|
||||
required: true
|
||||
- label: I have mentioned OpenWebUI version and OS/container info
|
||||
required: true
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Documentation
|
||||
url: https://docs.openwebui.com/
|
||||
about: Official OpenWebUI documentation
|
||||
- name: Discussions
|
||||
url: https://github.com/Fu-Jie/openwebui-extensions/discussions
|
||||
about: Ask questions and discuss with the community
|
||||
- name: OpenWebUI Repository
|
||||
url: https://github.com/open-webui/open-webui
|
||||
about: Main OpenWebUI project
|
||||
104
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
104
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
name: ✨ Feature Request
|
||||
description: Suggest a new feature or improvement
|
||||
title: "[FEATURE] "
|
||||
labels: ["enhancement"]
|
||||
assignees: []
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your suggestion! Please describe the feature you'd like to see.
|
||||
|
||||
- type: dropdown
|
||||
id: plugin-type
|
||||
attributes:
|
||||
label: Plugin Type (Optional)
|
||||
description: Is this for a specific plugin type?
|
||||
options:
|
||||
- Action
|
||||
- Filter
|
||||
- Pipe
|
||||
- Pipeline
|
||||
- Tool
|
||||
- Core/General
|
||||
- Documentation
|
||||
- Other
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: dropdown
|
||||
id: plugin-name
|
||||
attributes:
|
||||
label: Plugin Name (Optional)
|
||||
description: Which plugin would benefit from this feature?
|
||||
options:
|
||||
- "Select a plugin..."
|
||||
- "Action - Deep Dive"
|
||||
- "Action - Export to Word Enhanced"
|
||||
- "Action - Export to Excel"
|
||||
- "Action - Flash Card"
|
||||
- "Action - Smart Infographic"
|
||||
- "Action - Smart Mind Map"
|
||||
- "Filter - Async Context Compression"
|
||||
- "Filter - Context & Model Enhancement Filter"
|
||||
- "Filter - Folder Memory"
|
||||
- "Filter - GitHub Copilot SDK Files Filter"
|
||||
- "Filter - Markdown Normalizer"
|
||||
- "Filter - Gemini Multimodel Filter"
|
||||
- "Pipeline - MOE Prompt Refiner"
|
||||
- "Pipe - GitHub Copilot SDK"
|
||||
- "Pipe - iFlow SDK"
|
||||
- "Tool - OpenWebUI Skills Manager"
|
||||
- "Tool - Smart Infographic Tool"
|
||||
- "Tool - Smart Mind Map Tool"
|
||||
- "Core/General Improvement"
|
||||
- "Other / Not Listed"
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Feature Description
|
||||
description: Clearly describe the feature you're requesting
|
||||
placeholder: |
|
||||
What feature would you like to see?
|
||||
How would it work?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation & Use Case
|
||||
description: Why is this feature important? What problem does it solve?
|
||||
placeholder: |
|
||||
What's the pain point this solves?
|
||||
How would it improve your workflow?
|
||||
Who else would benefit from this?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Information (Optional)
|
||||
description: "Mockups, alternatives considered, references, or examples"
|
||||
placeholder: |
|
||||
- Links to related plugins or tools
|
||||
- Screenshots or mockups
|
||||
- Alternative approaches you've considered
|
||||
- Code examples or references
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: I have searched existing issues/discussions for similar requests
|
||||
required: true
|
||||
- label: This feature would be useful for multiple users
|
||||
required: false
|
||||
5
.github/agents/plugin-implementer.agent.md
vendored
5
.github/agents/plugin-implementer.agent.md
vendored
@@ -56,6 +56,11 @@ When bumping, update ALL 7+ files (code docstring + 2× README + 2× doc detail
|
||||
- Never run `git commit`, `git push`, or create PRs automatically.
|
||||
- After all edits, list what changed and why, then stop.
|
||||
|
||||
## Knowledge Capture (Mandatory)
|
||||
Before ending the session, if you discovered any non-obvious internal API behaviour,
|
||||
parameter injection quirk, or workaround, save it to `.agent/learnings/{topic}.md`.
|
||||
Also browse `.agent/learnings/` at the start to reuse existing knowledge.
|
||||
|
||||
## Completion Output
|
||||
- Modified files (full relative paths, one-line descriptions)
|
||||
- Remaining manual checks
|
||||
|
||||
2
.github/agents/plugin-planner.agent.md
vendored
2
.github/agents/plugin-planner.agent.md
vendored
@@ -3,7 +3,6 @@ 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
|
||||
@@ -22,6 +21,7 @@ You are the **planning specialist** for the `openwebui-extensions` repository.
|
||||
- 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.
|
||||
- Browse `.agent/learnings/` **first** to reuse existing knowledge before researching anything.
|
||||
|
||||
## Repository Plugin Inventory
|
||||
|
||||
|
||||
4
.github/agents/plugin-reviewer.agent.md
vendored
4
.github/agents/plugin-reviewer.agent.md
vendored
@@ -54,6 +54,9 @@ Full review rules are in .github/instructions/code-review.instructions.md.
|
||||
- [ ] `docs/plugins/{type}/index.md` and `.zh.md` version badges updated.
|
||||
- [ ] Root `README.md` / `README_CN.md` date badge updated.
|
||||
|
||||
**8. Knowledge Capture**
|
||||
- [ ] Any non-obvious findings (API contracts, injection quirks, gotchas) documented in `.agent/learnings/{topic}.md`.
|
||||
|
||||
### 🟡 Non-blocking (suggestions)
|
||||
- Copilot SDK tools: `params_type=MyParams` in `define_tool()`.
|
||||
- Long tasks (>3s): periodic `_emit_notification("info")` every 5s.
|
||||
@@ -68,4 +71,5 @@ Full review rules are in .github/instructions/code-review.instructions.md.
|
||||
- **Blocking issues** (file:line references)
|
||||
- **Non-blocking suggestions**
|
||||
- **Pass / Fail verdict**
|
||||
- **Knowledge captured?** (`.agent/learnings/` updated if any discoveries were made)
|
||||
- **Next step**: Pass → handoff to Release Prep; Fail → return to Implementer with fix list
|
||||
|
||||
23
.github/agents/release-prep.agent.md
vendored
23
.github/agents/release-prep.agent.md
vendored
@@ -78,5 +78,28 @@ Plugin: {type}/{name} → v{new_version}
|
||||
### Verification Status
|
||||
{filled-in 9-file checklist for each changed plugin}
|
||||
|
||||
## Post-Release: Batch Plugin Installation
|
||||
|
||||
After release is published, users can quickly install all plugins:
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/Fu-Jie/openwebui-extensions.git
|
||||
cd openwebui-extensions
|
||||
|
||||
# Setup API key and instance URL
|
||||
echo "api_key=sk-your-api-key-here" > scripts/.env
|
||||
echo "url=http://localhost:3000" >> scripts/.env
|
||||
|
||||
# If using remote instance, configure the baseURL:
|
||||
# echo "url=http://192.168.1.10:3000" >> scripts/.env
|
||||
# echo "url=https://openwebui.example.com" >> scripts/.env
|
||||
|
||||
# Install all plugins at once
|
||||
python scripts/install_all_plugins.py
|
||||
```
|
||||
|
||||
See: [Deployment Guide](./scripts/DEPLOYMENT_GUIDE.md)
|
||||
|
||||
---
|
||||
⚠️ **Waiting for user confirmation — no git operations will run until explicitly approved.**
|
||||
|
||||
25
.github/copilot-instructions.md
vendored
25
.github/copilot-instructions.md
vendored
@@ -32,6 +32,15 @@ plugins/actions/export_to_docx/
|
||||
- `README.md` - English documentation
|
||||
- `README_CN.md` - 中文文档
|
||||
|
||||
#### 文档交付与审阅 (Documentation Delivery for Review)
|
||||
|
||||
当任务涉及文档类内容时,例如 README、Guide、Post、Release Notes、Announcement、Development Docs:
|
||||
|
||||
- **必须**同时提供英文版与中文版,方便审阅与校对。
|
||||
- 若仓库最终只提交英文文件,也**必须**在对话中额外提供中文版草稿给维护者 review。
|
||||
- 若用户未明确指定只保留单语文件,默认按双语交付处理。
|
||||
- 中文版的目标是**便于审阅**,应忠实对应英文原意,可在表达上自然调整,但不得遗漏风险、限制、步骤或结论。
|
||||
|
||||
#### README 结构规范 (README Structure Standard)
|
||||
|
||||
所有插件 README 必须遵循以下统一结构顺序:
|
||||
@@ -1151,6 +1160,7 @@ Filter 实例是**单例 (Singleton)**。
|
||||
- [ ] **README 结构**:
|
||||
- **Key Capabilities** (英文) / **核心功能** (中文): 必须包含所有核心功能
|
||||
- **What's New** (英文) / **最新更新** (中文): 仅包含最新版本的变更信息
|
||||
- [ ] **知识沉淀**: 开发过程中发现的非显而易见的规律、踩坑或内部 API 合约,必须记录到 `.agent/learnings/{topic}.md`
|
||||
|
||||
### 2. 🔄 一致性维护 (Consistency Maintenance)
|
||||
|
||||
@@ -1208,6 +1218,21 @@ Filter 实例是**单例 (Singleton)**。
|
||||
|
||||
使用 `@all-contributors please add @username for <type>` 指令。
|
||||
|
||||
### 6. 📖 知识沉淀 Knowledge Capture (Mandatory)
|
||||
|
||||
任何开发会话中发现的**非显而易见**的内部 API 行为、参数注入机制、Mock 对象要求或其他踩坑经验,
|
||||
**必须**在会话结束前记录到 `.agent/learnings/{topic}.md`。
|
||||
|
||||
- **开始前**: 先浏览 `.agent/learnings/` 确认是否存在相关先验知识,避免重复调研。
|
||||
- **格式规范**: 参见 `.agent/learnings/README.md`。
|
||||
- **现有条目**: 见 `.agent/learnings/` 目录。
|
||||
|
||||
典型需要记录的内容:
|
||||
- OpenWebUI 内部函数的参数注入机制
|
||||
- Pipe 调用 Tool 时必须提供的上下文字段
|
||||
- Mock Request 对象所需满足的接口契约
|
||||
- 模型 ID 在不同上下文中的解析规则
|
||||
|
||||
---
|
||||
|
||||
## 📚 参考资源 (Reference Resources)
|
||||
|
||||
21
.github/gh-aw/README.md
vendored
Normal file
21
.github/gh-aw/README.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# gh-aw Support Files
|
||||
|
||||
This directory stores repository-local support files for GitHub Agentic Workflows.
|
||||
|
||||
## Purpose
|
||||
|
||||
Keep review aids, policy notes, and human-facing mirrors out of `.github/workflows/` so only real gh-aw source workflows live there.
|
||||
|
||||
## Structure
|
||||
|
||||
- `review-mirrors/`: Chinese review mirrors and maintainer-facing explanations for workflow source files.
|
||||
|
||||
## Current Files
|
||||
|
||||
- `review-mirrors/aw-pr-maintainer-review.zh.md`: Chinese review mirror for `.github/workflows/aw-pr-maintainer-review.md`.
|
||||
- `review-mirrors/aw-release-preflight.zh.md`: Chinese review mirror for `.github/workflows/aw-release-preflight.md`.
|
||||
- `review-mirrors/aw-ci-audit.zh.md`: Chinese review mirror for `.github/workflows/aw-ci-audit.md`.
|
||||
|
||||
## Rule
|
||||
|
||||
Files in this directory are for maintainer review and documentation only. They are not gh-aw workflow source files and should not be compiled.
|
||||
249
.github/gh-aw/review-mirrors/aw-ci-audit.zh.md
vendored
Normal file
249
.github/gh-aw/review-mirrors/aw-ci-audit.zh.md
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
# aw-ci-audit 中文对照
|
||||
|
||||
对应源文件:`.github/workflows/aw-ci-audit.md`
|
||||
|
||||
用途:这是一份给维护者 review 用的中文对照说明,不是 gh-aw 工作流源文件,也不参与 `gh aw compile`。
|
||||
|
||||
## 工作流定位
|
||||
|
||||
这个工作流的目标是做“CI / 自动化健康审计”。
|
||||
|
||||
它不是日志转储器,也不是自动修复器,而是用于:
|
||||
|
||||
- 检查近期仓库自动化是否出现可重复的失败模式
|
||||
- 分析 release、publish、stats 等关键工作流的薄弱点
|
||||
- 只在有新且可操作的诊断结论时,创建一条维护 issue
|
||||
|
||||
如果没有新的可操作诊断,或者问题已经被现有 issue 覆盖,就执行 `noop`。
|
||||
|
||||
## Frontmatter 对照
|
||||
|
||||
### 触发方式
|
||||
|
||||
- `schedule: daily`
|
||||
- `workflow_dispatch`
|
||||
- `roles: all`
|
||||
- `skip-bots`
|
||||
- `github-actions`
|
||||
- `copilot`
|
||||
- `dependabot`
|
||||
- `renovate`
|
||||
|
||||
说明:这套设计更适合“定期体检 + 手动补查”,而不是直接绑到不确定的 workflow failure 事件上。
|
||||
|
||||
### 权限
|
||||
|
||||
当前设计为只读:
|
||||
|
||||
- `contents: read`
|
||||
- `issues: read`
|
||||
- `pull-requests: read`
|
||||
- `actions: read`
|
||||
|
||||
说明:工作流只做诊断分析,不改代码、不发 release、不创建 PR。
|
||||
|
||||
### Safe Outputs
|
||||
|
||||
已配置:
|
||||
|
||||
- `create-issue`
|
||||
- 标题前缀:`[ci-audit] `
|
||||
- labels:`ci-audit`、`maintenance`
|
||||
- 不自动关闭旧 issue
|
||||
|
||||
最终只能二选一:
|
||||
|
||||
- 有新且可操作的诊断时执行 `create_issue`
|
||||
- 无新问题时执行 `noop`
|
||||
|
||||
### 工具
|
||||
|
||||
- `github`
|
||||
- `repos`
|
||||
- `issues`
|
||||
- `pull_requests`
|
||||
- `bash`
|
||||
- 仅开放只读类命令,如 `pwd`、`ls`、`cat`、`rg`、`git diff`、`git show`
|
||||
|
||||
## 正文指令对照
|
||||
|
||||
## 主要目标
|
||||
|
||||
要求代理审计:
|
||||
|
||||
- release 相关 workflow 的失败或波动
|
||||
- 插件发布失败
|
||||
- 社区统计更新回归
|
||||
- 重复出现的 workflow 脆弱点
|
||||
- 维护者真正可以执行的下一步动作
|
||||
|
||||
明确限制:
|
||||
|
||||
- 只做诊断
|
||||
- 不改文件
|
||||
- 不推代码
|
||||
- 不开 PR
|
||||
- 不发 release
|
||||
|
||||
## 高优先级依据文件
|
||||
|
||||
在形成结论前,优先把这些文件当成“自动化规则源”:
|
||||
|
||||
- `.github/copilot-instructions.md`
|
||||
- `.github/workflows/release.yml`
|
||||
- `.github/workflows/publish_plugin.yml`
|
||||
- `.github/workflows/publish_new_plugin.yml`
|
||||
- `.github/workflows/plugin-version-check.yml`
|
||||
- `.github/workflows/community-stats.yml`
|
||||
- `docs/development/gh-aw-integration-plan.md`
|
||||
- `docs/development/gh-aw-integration-plan.zh.md`
|
||||
|
||||
## 重点关注的目标工作流
|
||||
|
||||
优先检查:
|
||||
|
||||
- `release.yml`
|
||||
- `publish_plugin.yml`
|
||||
- `publish_new_plugin.yml`
|
||||
- `plugin-version-check.yml`
|
||||
- `community-stats.yml`
|
||||
- `deploy.yml`
|
||||
|
||||
如果这些没有明显问题,不要无限扩大范围。
|
||||
|
||||
## 审查范围
|
||||
|
||||
聚焦“近期失败或可疑自动化信号”,并优先给出基于本仓库结构的诊断,而不是泛泛的 CI 建议。
|
||||
|
||||
它应该像“在看仓库自动化健康趋势的维护者”,而不是普通日志摘要机器人。
|
||||
|
||||
## 重点检查项
|
||||
|
||||
### 1. Release 与 Publish 失败
|
||||
|
||||
检查近期失败是否指向这些可操作问题:
|
||||
|
||||
- 版本提取或比较逻辑漂移
|
||||
- release note 打包缺口
|
||||
- publish 脚本的认证或环境问题
|
||||
- workflow 中的结构假设已经不匹配当前仓库
|
||||
- 如果不改仓库逻辑,就可能持续复现的失败
|
||||
|
||||
### 2. Stats 与定时任务稳定性
|
||||
|
||||
检查定时维护任务是否出现这些脆弱点:
|
||||
|
||||
- community stats 该提交时不再提交
|
||||
- badge / docs 生成逻辑过时
|
||||
- 依赖外部 API 的任务反复因同类原因失败
|
||||
- schedule 驱动任务制造低价值噪音
|
||||
|
||||
### 3. 维护者信号质量
|
||||
|
||||
只有当结论“真的值得维护者处理”时,才创建 issue。
|
||||
|
||||
适合开 issue 的情况:
|
||||
|
||||
- 同类失败在多次运行中重复出现
|
||||
- workflow 逻辑与当前仓库结构不匹配
|
||||
- 大概率缺 secret / 权限 / 路径假设过时
|
||||
- 重复出现的低信号失败值得过滤或加固
|
||||
|
||||
不要为一次性噪音失败开 issue,除非它很可能复发。
|
||||
|
||||
### 4. 已有 Issue 感知
|
||||
|
||||
在创建新 issue 前,先判断是否已有 open issue 覆盖同一类 CI 问题。
|
||||
|
||||
如果已有 issue 已经足够覆盖,就优先 `noop`,避免制造重复单。
|
||||
|
||||
## 严重级别
|
||||
|
||||
只允许三档:
|
||||
|
||||
- `High`
|
||||
- 高概率重复发生,且会持续影响仓库自动化
|
||||
- `Medium`
|
||||
- 建议尽快修,以降低维护成本或 workflow 漂移
|
||||
- `Low`
|
||||
- 可选的稳健性增强或清理建议
|
||||
|
||||
并且明确要求:
|
||||
|
||||
- 不要为了开 issue 而硬造问题
|
||||
|
||||
## Issue 格式
|
||||
|
||||
如果要创建 issue,必须只有一条维护 issue。
|
||||
|
||||
要求:
|
||||
|
||||
- 英文
|
||||
- 简洁
|
||||
- 先写 findings,不写空泛表扬
|
||||
- 带可点击路径引用
|
||||
- 不用嵌套列表
|
||||
- 不要粘贴大段原始日志,除非短摘录确实必要
|
||||
|
||||
固定结构:
|
||||
|
||||
```markdown
|
||||
## CI Audit
|
||||
|
||||
### Summary
|
||||
Short diagnosis of the failure pattern or automation risk.
|
||||
|
||||
### Findings
|
||||
- `path/to/file`: specific problem or likely root cause
|
||||
|
||||
### Suggested Next Steps
|
||||
- concrete maintainer action
|
||||
- concrete maintainer action
|
||||
|
||||
### Notes
|
||||
- Mention whether this appears recurring, new, or already partially mitigated.
|
||||
```
|
||||
|
||||
补充规则:
|
||||
|
||||
- 正常情况下控制在约 300 词以内
|
||||
- 如果是相关联的问题,合并成一个 issue,不要拆多个
|
||||
- 优先提交“单个可执行诊断”,而不是大杂烩
|
||||
|
||||
## No-Issue 规则
|
||||
|
||||
如果没有值得报告的新诊断:
|
||||
|
||||
- 不要创建状态汇报型 issue
|
||||
- 不要复述 workflows 看起来健康
|
||||
- 直接走 `noop`
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: reviewed recent repository automation signals and found no new actionable CI diagnosis worth opening as a maintenance issue."}}
|
||||
```
|
||||
|
||||
## 建议执行流程
|
||||
|
||||
1. 检查近期仓库自动化上下文
|
||||
2. 优先检查目标工作流
|
||||
3. 识别可重复或仓库特定的失败模式
|
||||
4. 判断该问题是否已被 open issue 覆盖
|
||||
5. 只有在诊断“新且可操作”时,才起草最短有用的维护 issue
|
||||
6. 最终只执行一次 `create_issue` 或一次 `noop`
|
||||
|
||||
## 额外约束
|
||||
|
||||
- 不要为单次低信号瞬时失败开 issue
|
||||
- 除非失败模式非常明确,否则不要顺势要求大规模重构
|
||||
- 优先给出仓库特定原因,而不是泛泛的“重试试试”
|
||||
- 如果根因不确定,要把不确定性写明
|
||||
- 如果现有 issue 已经覆盖,优先 `noop` 而不是重复开单
|
||||
|
||||
## 最终要求
|
||||
|
||||
必须以且仅以一次 safe output 结束:
|
||||
|
||||
- 有新且可操作的诊断:`create_issue`
|
||||
- 无新问题:`noop`
|
||||
268
.github/gh-aw/review-mirrors/aw-pr-maintainer-review.zh.md
vendored
Normal file
268
.github/gh-aw/review-mirrors/aw-pr-maintainer-review.zh.md
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
# aw-pr-maintainer-review 中文对照
|
||||
|
||||
对应源文件:`.github/workflows/aw-pr-maintainer-review.md`
|
||||
|
||||
用途:这是一份给维护者 review 用的中文对照说明,不是 gh-aw 工作流源文件,也不参与 `gh aw compile`。
|
||||
|
||||
## 工作流定位
|
||||
|
||||
这个工作流的目标是对触发 PR 做一次“维护者语义审查”。
|
||||
|
||||
它不是通用 code review 机器人,也不是自动修复器,而是用来检查以下问题:
|
||||
|
||||
- 是否违反本仓库插件开发规范
|
||||
- 是否缺失应同步更新的 README / README_CN / docs 镜像文件
|
||||
- 是否存在发布准备层面的遗漏
|
||||
- 是否引入明显的高风险行为回归
|
||||
|
||||
如果 PR 已经足够合规,没有可操作的维护者反馈,就不评论,而是执行 `noop`。
|
||||
|
||||
## Frontmatter 对照
|
||||
|
||||
### 触发方式
|
||||
|
||||
- `pull_request`
|
||||
- 类型:`opened`、`reopened`、`synchronize`、`ready_for_review`
|
||||
- 路径限制:
|
||||
- `plugins/**`
|
||||
- `docs/**`
|
||||
- `.github/**`
|
||||
- `README.md`
|
||||
- `README_CN.md`
|
||||
- `workflow_dispatch`
|
||||
- `roles: all`
|
||||
- `skip-bots`
|
||||
- `github-actions`
|
||||
- `copilot`
|
||||
- `dependabot`
|
||||
- `renovate`
|
||||
|
||||
### 权限
|
||||
|
||||
当前设计为只读:
|
||||
|
||||
- `contents: read`
|
||||
- `issues: read`
|
||||
- `pull-requests: read`
|
||||
|
||||
说明:工作流不会直接改代码,也不会提交 review comment 之外的写操作。
|
||||
|
||||
### Safe Outputs
|
||||
|
||||
已配置:
|
||||
|
||||
- `add-comment`
|
||||
- 目标:当前触发 PR
|
||||
- 最多 1 条
|
||||
- 隐藏旧评论
|
||||
- 不加 footer
|
||||
|
||||
同时要求最终必须二选一:
|
||||
|
||||
- 有问题时执行 `add_comment`
|
||||
- 无问题时执行 `noop`
|
||||
|
||||
### 工具
|
||||
|
||||
- `github`
|
||||
- `repos`
|
||||
- `issues`
|
||||
- `pull_requests`
|
||||
- `bash`
|
||||
- 仅开放只读类命令,如 `pwd`、`ls`、`cat`、`rg`、`git diff`、`git show`
|
||||
|
||||
## 正文指令对照
|
||||
|
||||
## 主要目标
|
||||
|
||||
要求代理审查:
|
||||
|
||||
- 仓库标准合规性
|
||||
- 缺失的同步更新文件
|
||||
- 发布准备缺口
|
||||
- 文档漂移
|
||||
- 插件代码中的高风险回归
|
||||
|
||||
明确限制:
|
||||
|
||||
- 只做 review
|
||||
- 不改文件
|
||||
- 不推代码
|
||||
- 不创建 PR
|
||||
|
||||
## 高优先级依据文件
|
||||
|
||||
在形成结论前,优先把这些文件当成“本仓库规则源”:
|
||||
|
||||
- `.github/copilot-instructions.md`
|
||||
- `.github/instructions/code-review.instructions.md`
|
||||
- `.github/instructions/commit-message.instructions.md`
|
||||
- `.github/skills/release-prep/SKILL.md`
|
||||
- `.github/skills/doc-mirror-sync/SKILL.md`
|
||||
- `docs/development/gh-aw-integration-plan.md`
|
||||
- `docs/development/gh-aw-integration-plan.zh.md`
|
||||
|
||||
## 审查范围
|
||||
|
||||
- 先看 PR diff 和 changed files
|
||||
- 只有在验证一致性时,才扩展读取关联文件
|
||||
- 优先遵循“仓库特定规则”,而不是泛泛的最佳实践
|
||||
|
||||
换句话说,它应该像“熟悉本仓库的维护者”,而不是通用 lint bot。
|
||||
|
||||
## 重点检查项
|
||||
|
||||
### 1. 插件代码规范
|
||||
|
||||
当 `plugins/**/*.py` 变化时,重点看:
|
||||
|
||||
- 是否保持单文件 i18n 模式
|
||||
- 用户可见文本是否进入翻译字典
|
||||
- 是否使用 `_get_user_context` 和 `_get_chat_context`
|
||||
- `__event_call__` 的 JS 执行是否具备 timeout 防护和前端兜底
|
||||
- 是否引入 `print()` 到生产插件代码
|
||||
- emitter 是否安全判空
|
||||
- filter 插件是否把请求级可变状态塞到 `self`
|
||||
- Copilot SDK / OpenWebUI tool 定义是否仍符合仓库规范
|
||||
|
||||
### 2. 版本与发布卫生
|
||||
|
||||
当 `plugins/**/*.py` 改动时,检查是否“应该同步但没同步”:
|
||||
|
||||
- 插件 docstring 的 `version:`
|
||||
- 插件目录下 `README.md`
|
||||
- 插件目录下 `README_CN.md`
|
||||
- `docs/plugins/**` 下的镜像页面
|
||||
- `docs/plugins/{type}/index.md` 等索引文件
|
||||
- 如果是明显 release-prep 类型 PR,再看根 `README.md` 和 `README_CN.md` 日期 badge
|
||||
|
||||
这里的关键语义是:
|
||||
|
||||
- 不是每个 PR 都必须当发布处理
|
||||
- 只有在“用户可见行为、元数据、版本化文档、发布面内容”发生变化时,才提示缺失同步
|
||||
|
||||
### 3. 文档同步
|
||||
|
||||
当插件 README 改动时,检查是否应同步 docs 镜像:
|
||||
|
||||
- `plugins/actions/{name}/README.md` -> `docs/plugins/actions/{name}.md`
|
||||
- `plugins/actions/{name}/README_CN.md` -> `docs/plugins/actions/{name}.zh.md`
|
||||
- `plugins/filters/{name}/README.md` -> `docs/plugins/filters/{name}.md`
|
||||
- `plugins/filters/{name}/README_CN.md` -> `docs/plugins/filters/{name}.zh.md`
|
||||
- `plugins/pipes/{name}/README.md` -> `docs/plugins/pipes/{name}.md`
|
||||
- `plugins/pipes/{name}/README_CN.md` -> `docs/plugins/pipes/{name}.zh.md`
|
||||
- `plugins/pipelines/{name}/README.md` -> `docs/plugins/pipelines/{name}.md`
|
||||
- `plugins/pipelines/{name}/README_CN.md` -> `docs/plugins/pipelines/{name}.zh.md`
|
||||
- `plugins/tools/{name}/README.md` -> `docs/plugins/tools/{name}.md`
|
||||
- `plugins/tools/{name}/README_CN.md` -> `docs/plugins/tools/{name}.zh.md`
|
||||
|
||||
如果是 docs-only 且明显有意为之,不要过度报错。
|
||||
|
||||
### 4. PR 质量
|
||||
|
||||
只在“确实让维护者审查变难”时,才指出 PR 描述缺失这些内容:
|
||||
|
||||
- 改了什么
|
||||
- 为什么改
|
||||
- 是否需要迁移或重新配置
|
||||
|
||||
## 严重级别
|
||||
|
||||
只允许三档:
|
||||
|
||||
- `Blocking`
|
||||
- 大概率 bug、发布回归、缺少必需同步、严重规范破坏
|
||||
- `Important`
|
||||
- 应该合并前修,但不一定是直接运行时错误
|
||||
- `Minor`
|
||||
- 建议项,可选
|
||||
|
||||
并且明确要求:
|
||||
|
||||
- 不要为了留言而硬凑问题
|
||||
|
||||
## 评论格式
|
||||
|
||||
如果要评论,必须只有一条总结评论。
|
||||
|
||||
要求:
|
||||
|
||||
- 英文
|
||||
- 简洁
|
||||
- 先给 findings,不先夸赞
|
||||
- 带可点击路径引用
|
||||
- 不使用嵌套列表
|
||||
- 不要机械复述 diff
|
||||
|
||||
固定结构:
|
||||
|
||||
```markdown
|
||||
## PR Maintainer Review
|
||||
|
||||
### Blocking
|
||||
- `path/to/file`: specific issue and why it matters
|
||||
|
||||
### Important
|
||||
- `path/to/file`: specific issue and what sync/check is missing
|
||||
|
||||
### Minor
|
||||
- `path/to/file`: optional improvement or consistency note
|
||||
|
||||
### Merge Readiness
|
||||
- Ready after the items above are addressed.
|
||||
```
|
||||
|
||||
补充规则:
|
||||
|
||||
- 空 section 要省略
|
||||
- 如果只有一个严重级别,只保留那个 section 和 `Merge Readiness`
|
||||
- 正常情况下控制在约 250 词以内
|
||||
|
||||
## No-Comment 规则
|
||||
|
||||
如果没有有意义的维护者反馈:
|
||||
|
||||
- 不要发“看起来不错”这类表扬评论
|
||||
- 不要复述 checks passed
|
||||
- 直接走 `noop`
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: reviewed the PR diff and repository sync expectations, and found no actionable maintainer feedback."}}
|
||||
```
|
||||
|
||||
## 建议执行流程
|
||||
|
||||
1. 找出变更文件
|
||||
2. 读取高优先级规则文件
|
||||
3. 对照插件审查规范检查插件代码
|
||||
4. 对照 doc mirror 规则检查 README / docs
|
||||
5. 判断是否缺失 version sync 或 release-facing 文件
|
||||
6. 先起草最短但有用的维护者总结
|
||||
7. 最终只执行一次 `add_comment` 或一次 `noop`
|
||||
|
||||
## 额外约束
|
||||
|
||||
- 不要要求与本 PR 无关的大重构
|
||||
- 小型内部变更不要强拉成 release-prep
|
||||
- 明显是私有/内部改动时,不要强制要求 docs sync
|
||||
- 优先给出“仓库特定”的反馈,而不是通用 code review 废话
|
||||
- 如果你不确定某个同步文件是否必需,把级别降为 `Important`
|
||||
- 如果问题依赖 PR 意图但当前信息不足,要把表述写成“条件性判断”,不要装作确定
|
||||
|
||||
## 最终要求
|
||||
|
||||
必须以且仅以一次 safe output 结束:
|
||||
|
||||
- 有可操作反馈:`add_comment`
|
||||
- 无可操作反馈:`noop`
|
||||
|
||||
## Review 结论
|
||||
|
||||
这份英文源工作流目前已经可以作为后续 `gh aw compile` 的候选源文件。
|
||||
|
||||
中文镜像的目的只有两个:
|
||||
|
||||
- 方便你逐段审阅策略是否符合预期
|
||||
- 避免把中文说明混进真正要编译的 workflow 源文件
|
||||
275
.github/gh-aw/review-mirrors/aw-release-preflight.zh.md
vendored
Normal file
275
.github/gh-aw/review-mirrors/aw-release-preflight.zh.md
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
# aw-release-preflight 中文对照
|
||||
|
||||
对应源文件:`.github/workflows/aw-release-preflight.md`
|
||||
|
||||
用途:这是一份给维护者 review 用的中文对照说明,不是 gh-aw 工作流源文件,也不参与 `gh aw compile`。
|
||||
|
||||
## 工作流定位
|
||||
|
||||
这个工作流的目标是对触发变更做一次“发布前预检语义审查”。
|
||||
|
||||
它不是发布执行器,也不是自动补版本工具,而是用于判断:
|
||||
|
||||
- 这次改动是否真的在做 release-prep
|
||||
- 如果是在做 release-prep,版本同步是否完整
|
||||
- 双语 README、docs 镜像、release notes 是否齐全
|
||||
- 是否存在会影响发布质量的说明缺失或文档漂移
|
||||
|
||||
如果当前变更并不是发布准备,或者已经足够一致、没有可操作反馈,就执行 `noop`。
|
||||
|
||||
## Frontmatter 对照
|
||||
|
||||
### 触发方式
|
||||
|
||||
- `pull_request`
|
||||
- 类型:`opened`、`reopened`、`synchronize`、`ready_for_review`
|
||||
- 路径限制:
|
||||
- `plugins/**/*.py`
|
||||
- `plugins/**/README.md`
|
||||
- `plugins/**/README_CN.md`
|
||||
- `plugins/**/v*.md`
|
||||
- `plugins/**/v*_CN.md`
|
||||
- `docs/plugins/**/*.md`
|
||||
- `README.md`
|
||||
- `README_CN.md`
|
||||
- `.github/**`
|
||||
- `workflow_dispatch`
|
||||
- `roles: all`
|
||||
- `skip-bots`
|
||||
- `github-actions`
|
||||
- `copilot`
|
||||
- `dependabot`
|
||||
- `renovate`
|
||||
|
||||
### 权限
|
||||
|
||||
当前设计为只读:
|
||||
|
||||
- `contents: read`
|
||||
- `issues: read`
|
||||
- `pull-requests: read`
|
||||
|
||||
说明:工作流不会发 release、不会推代码、不会改文件。
|
||||
|
||||
### Safe Outputs
|
||||
|
||||
已配置:
|
||||
|
||||
- `add-comment`
|
||||
- 目标:当前触发 PR
|
||||
- 最多 1 条
|
||||
- 隐藏旧评论
|
||||
- 不加 footer
|
||||
|
||||
最终只能二选一:
|
||||
|
||||
- 有问题时执行 `add_comment`
|
||||
- 无问题时执行 `noop`
|
||||
|
||||
### 工具
|
||||
|
||||
- `github`
|
||||
- `repos`
|
||||
- `issues`
|
||||
- `pull_requests`
|
||||
- `bash`
|
||||
- 仅开放只读类命令,如 `pwd`、`ls`、`cat`、`rg`、`git diff`、`git show`
|
||||
|
||||
## 正文指令对照
|
||||
|
||||
## 主要目标
|
||||
|
||||
要求代理检查:
|
||||
|
||||
- 版本同步完整性
|
||||
- 双语 README 与 docs 一致性
|
||||
- release notes 完整性
|
||||
- 发布面索引或 badge 漂移
|
||||
- 用户可见发布是否缺失迁移说明或维护者上下文
|
||||
|
||||
明确限制:
|
||||
|
||||
- 只做 review
|
||||
- 不改文件
|
||||
- 不推代码
|
||||
- 不创建 release
|
||||
- 不创建 PR
|
||||
|
||||
## 高优先级依据文件
|
||||
|
||||
在形成结论前,优先把这些文件当成“发布规则源”:
|
||||
|
||||
- `.github/copilot-instructions.md`
|
||||
- `.github/instructions/commit-message.instructions.md`
|
||||
- `.github/skills/release-prep/SKILL.md`
|
||||
- `.github/skills/doc-mirror-sync/SKILL.md`
|
||||
- `.github/workflows/release.yml`
|
||||
- `docs/development/gh-aw-integration-plan.md`
|
||||
- `docs/development/gh-aw-integration-plan.zh.md`
|
||||
|
||||
## 审查范围
|
||||
|
||||
- 从 PR diff 和 changed files 开始
|
||||
- 只有在验证发布同步时才扩展到相关 release-facing 文件
|
||||
- 优先遵循仓库既有 release-prep 规则,而不是泛泛的 release 建议
|
||||
|
||||
换句话说,它应该像“合并前最后做一致性复核的维护者”。
|
||||
|
||||
## 重点检查项
|
||||
|
||||
### 1. 发布相关文件中的版本同步
|
||||
|
||||
当某个插件明显在准备发版时,检查这些位置是否同步:
|
||||
|
||||
- 插件 Python docstring 的 `version:`
|
||||
- 插件目录下 `README.md`
|
||||
- 插件目录下 `README_CN.md`
|
||||
- `docs/plugins/**` 英文镜像页
|
||||
- `docs/plugins/**/*.zh.md` 中文镜像页
|
||||
- `docs/plugins/{type}/index.md` 中该插件的条目或版本 badge
|
||||
- `docs/plugins/{type}/index.zh.md` 中该插件的条目或版本 badge
|
||||
|
||||
但只有在“这次改动明显带有发布意图”时才提示,不要把所有 PR 都按发布处理。
|
||||
|
||||
### 2. README 与 docs 镜像一致性
|
||||
|
||||
当插件 README 变化时,检查 docs 镜像是否同步。
|
||||
|
||||
路径映射:
|
||||
|
||||
- `plugins/actions/{name}/README.md` -> `docs/plugins/actions/{name}.md`
|
||||
- `plugins/actions/{name}/README_CN.md` -> `docs/plugins/actions/{name}.zh.md`
|
||||
- `plugins/filters/{name}/README.md` -> `docs/plugins/filters/{name}.md`
|
||||
- `plugins/filters/{name}/README_CN.md` -> `docs/plugins/filters/{name}.zh.md`
|
||||
- `plugins/pipes/{name}/README.md` -> `docs/plugins/pipes/{name}.md`
|
||||
- `plugins/pipes/{name}/README_CN.md` -> `docs/plugins/pipes/{name}.zh.md`
|
||||
- `plugins/pipelines/{name}/README.md` -> `docs/plugins/pipelines/{name}.md`
|
||||
- `plugins/pipelines/{name}/README_CN.md` -> `docs/plugins/pipelines/{name}.zh.md`
|
||||
- `plugins/tools/{name}/README.md` -> `docs/plugins/tools/{name}.md`
|
||||
- `plugins/tools/{name}/README_CN.md` -> `docs/plugins/tools/{name}.zh.md`
|
||||
|
||||
如果是纯文档调整、而且并非发版预备,不要过度报错。
|
||||
|
||||
### 3. What's New 与 Release Notes 覆盖度
|
||||
|
||||
当这次更新明显是发布面插件更新时,检查:
|
||||
|
||||
- `What's New` 是否只反映最新版本
|
||||
- `最新更新` 是否与英文对应
|
||||
- 是否存在 `v{version}.md` 和 `v{version}_CN.md`
|
||||
- release notes 是否覆盖当前 diff 中有意义的功能、修复、文档或迁移变化
|
||||
|
||||
对纯内部小改动,不要强制要求 release notes。
|
||||
|
||||
### 4. 根 README 与发布面索引漂移
|
||||
|
||||
当改动明显面向正式发布时,再检查:
|
||||
|
||||
- 根 `README.md` 的日期 badge
|
||||
- 根 `README_CN.md` 的日期 badge
|
||||
- `docs/plugins/**/index.md`
|
||||
- `docs/plugins/**/index.zh.md`
|
||||
|
||||
不要把这种检查强加给普通内部 PR。
|
||||
|
||||
### 5. 维护者上下文与发布清晰度
|
||||
|
||||
检查 PR 描述或发布面文案是否缺少关键上下文:
|
||||
|
||||
- 这次到底发布了什么
|
||||
- 为什么这次发布值得做
|
||||
- 是否需要迁移或重新配置
|
||||
|
||||
只有在缺失信息会明显增加 release review 成本时,才提示。
|
||||
|
||||
## 严重级别
|
||||
|
||||
只允许三档:
|
||||
|
||||
- `Blocking`
|
||||
- 高概率发布回归、缺少必要版本同步、发布面更新明显不完整
|
||||
- `Important`
|
||||
- 合并前最好修,避免发布混乱或文档漂移
|
||||
- `Minor`
|
||||
- 可选的发布面清理或一致性建议
|
||||
|
||||
并且明确要求:
|
||||
|
||||
- 不要为了留言而造问题
|
||||
|
||||
## 评论格式
|
||||
|
||||
如果要评论,必须只有一条总结评论。
|
||||
|
||||
要求:
|
||||
|
||||
- 英文
|
||||
- 简洁
|
||||
- 先给 findings,不先夸赞
|
||||
- 带可点击路径引用
|
||||
- 不使用嵌套列表
|
||||
- 不要机械复述 diff
|
||||
|
||||
固定结构:
|
||||
|
||||
```markdown
|
||||
## Release Preflight Review
|
||||
|
||||
### Blocking
|
||||
- `path/to/file`: specific release-facing problem and why it matters
|
||||
|
||||
### Important
|
||||
- `path/to/file`: missing sync or release-documentation gap
|
||||
|
||||
### Minor
|
||||
- `path/to/file`: optional cleanup or consistency improvement
|
||||
|
||||
### Release Readiness
|
||||
- Ready after the items above are addressed.
|
||||
```
|
||||
|
||||
补充规则:
|
||||
|
||||
- 空 section 要省略
|
||||
- 如果只有一个严重级别,只保留那个 section 和 `Release Readiness`
|
||||
- 正常情况下控制在约 250 词以内
|
||||
|
||||
## No-Comment 规则
|
||||
|
||||
如果没有有意义的发布前预检反馈:
|
||||
|
||||
- 不要发“看起来不错”这类表扬评论
|
||||
- 不要复述 checks passed
|
||||
- 直接走 `noop`
|
||||
|
||||
示例:
|
||||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: reviewed the release-facing diff, version-sync expectations, and bilingual documentation coverage, and found no actionable preflight feedback."}}
|
||||
```
|
||||
|
||||
## 建议执行流程
|
||||
|
||||
1. 判断这次改动是否真的带有发布意图
|
||||
2. 检查 PR diff 中的变更文件
|
||||
3. 读取仓库的 release-prep 规则文件
|
||||
4. 只有在存在发布意图时,才检查 plugin version sync
|
||||
5. 检查 README、README_CN、docs 镜像、索引和 release notes 是否漂移
|
||||
6. 起草最短但有用的维护者总结
|
||||
7. 最终只执行一次 `add_comment` 或一次 `noop`
|
||||
|
||||
## 额外约束
|
||||
|
||||
- 不要把完整 release-prep 要求硬套到微小内部改动上
|
||||
- 非明确发布型 PR,不要强制要求根 README 日期 badge 更新
|
||||
- 如果这次改动并不现实地构成发版预备,就不要强求 release notes
|
||||
- 优先给出仓库特定的同步反馈,而不是泛泛的发布建议
|
||||
- 如果不确定某个 release-facing 同步文件是否必需,把级别降为 `Important`
|
||||
- 如果问题依赖“推测出来的意图”,要用条件式表述,不要装作确定
|
||||
|
||||
## 最终要求
|
||||
|
||||
必须以且仅以一次 safe output 结束:
|
||||
|
||||
- 有可操作反馈:`add_comment`
|
||||
- 无可操作反馈:`noop`
|
||||
90
.github/instructions/plugin-documentation.instructions.md
vendored
Normal file
90
.github/instructions/plugin-documentation.instructions.md
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: Plugin Documentation
|
||||
description: Use when writing or updating plugin README files, mirrored docs pages, bilingual release notes, or other user-facing documentation for plugins.
|
||||
applyTo: "plugins/**/README*.md"
|
||||
---
|
||||
# Plugin Documentation Standards
|
||||
|
||||
## Delivery Language
|
||||
|
||||
- Plugin directories must keep both `README.md` and `README_CN.md`
|
||||
- When a task includes docs, guides, announcements, release notes, or development docs, prepare both English and Chinese versions for review unless the user explicitly asks for single-language delivery
|
||||
- Even if only English is committed, provide a Chinese review draft in the conversation when documentation is part of the work
|
||||
|
||||
## README Structure
|
||||
|
||||
Use this order for plugin READMEs:
|
||||
|
||||
1. Title with icon
|
||||
2. README header
|
||||
3. One-sentence description
|
||||
4. `What's New` with only the latest update
|
||||
5. `Key Features`
|
||||
6. `How to Use`
|
||||
7. Configuration or Valves table
|
||||
8. Support section
|
||||
9. Other sections such as examples, template notes, troubleshooting, or changelog link
|
||||
|
||||
## README Header
|
||||
|
||||
Do not use the old pipe-separated metadata line.
|
||||
|
||||
Use a compact two-part header:
|
||||
|
||||
1. A full-width two-column line with author/version on the left and the star link on the right
|
||||
2. A single-row live badge table with no visible text header
|
||||
|
||||
English example:
|
||||
|
||||
`| By [Fu-Jie](https://github.com/Fu-Jie) · vx.y.z | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |`
|
||||
|
||||
`| :--- | ---: |`
|
||||
|
||||
`|  |  |  |  |  |  |  |`
|
||||
|
||||
`| :---: | :---: | :---: | :---: | :---: | :---: | :---: |`
|
||||
|
||||
Chinese example:
|
||||
|
||||
`| 作者:[Fu-Jie](https://github.com/Fu-Jie) · vx.y.z | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) |`
|
||||
|
||||
`| :--- | ---: |`
|
||||
|
||||
`|  |  |  |  |  |  |  |`
|
||||
|
||||
`| :---: | :---: | :---: | :---: | :---: | :---: | :---: |`
|
||||
|
||||
Guidelines:
|
||||
|
||||
- Keep the author link pointing to `https://github.com/Fu-Jie`
|
||||
- Keep the star link pointing to the repository root
|
||||
- Put the version on the left-side author line as plain text (`vx.y.z`), not as a badge
|
||||
- Use live badges for followers, points, plugin contribution count, total plugin downloads, total plugin saves, and total plugin views
|
||||
- Keep the `Top` badge compact and use the project standard wording (`Top <1%`)
|
||||
- Do not add a visible label header row above the badges
|
||||
|
||||
## Support Section
|
||||
|
||||
Use the repository-standard support wording.
|
||||
|
||||
English:
|
||||
`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.`
|
||||
|
||||
Chinese:
|
||||
`如果这个插件对你有帮助,欢迎到 [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) 点个 Star,这将是我持续改进的动力,感谢支持。`
|
||||
|
||||
## Mirror and Sync Rules
|
||||
|
||||
When plugin documentation changes, keep these layers aligned as needed:
|
||||
|
||||
- Plugin-local README files under `plugins/`
|
||||
- Mirrored docs pages under `docs/plugins/`
|
||||
- Plugin index pages under `docs/plugins/<type>/index.md` and `index.zh.md`
|
||||
- Root `README.md` and `README_CN.md` date badge when preparing a release
|
||||
|
||||
Use the `doc-mirror-sync` skill when the task includes mirroring plugin READMEs into `docs/`.
|
||||
|
||||
## Changelog Handling
|
||||
|
||||
- Keep detailed changelog history in GitHub release history or dedicated docs
|
||||
- In README files, keep `What's New` focused on the latest version only
|
||||
36
.github/skills/doc-mirror-sync/SKILL.md
vendored
36
.github/skills/doc-mirror-sync/SKILL.md
vendored
@@ -8,7 +8,43 @@ description: Automatically synchronizes plugin READMEs to the official documenta
|
||||
## Overview
|
||||
Automates the mirroring of `plugins/{type}/{name}/README.md` to `docs/plugins/{type}/{name}.md`.
|
||||
|
||||
## Docs-Only Mode (No Release Changes)
|
||||
Use this mode when the request is "only sync docs".
|
||||
|
||||
- Only update documentation mirror files under `docs/plugins/**`.
|
||||
- Do **not** bump plugin version.
|
||||
- Do **not** modify plugin code (`plugins/**.py`) unless explicitly requested.
|
||||
- Do **not** update root badges/dates for release.
|
||||
- Do **not** run release preparation steps.
|
||||
|
||||
## Workflow
|
||||
1. Identify changed READMEs.
|
||||
2. Copy content to corresponding mirror paths.
|
||||
3. Update version badges in `docs/plugins/{type}/index.md`.
|
||||
|
||||
## Commands
|
||||
|
||||
### Sync all mirrors (EN + ZH)
|
||||
|
||||
```bash
|
||||
python .github/skills/doc-mirror-sync/scripts/sync.py
|
||||
```
|
||||
|
||||
### Sync only one plugin (EN only)
|
||||
|
||||
```bash
|
||||
cp plugins/<type>/<name>/README.md docs/plugins/<type>/<name>.md
|
||||
```
|
||||
|
||||
### Sync only one plugin (EN + ZH)
|
||||
|
||||
```bash
|
||||
cp plugins/<type>/<name>/README.md docs/plugins/<type>/<name>.md
|
||||
cp plugins/<type>/<name>/README_CN.md docs/plugins/<type>/<name>.zh.md
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- If asked for English-only update, sync only `README.md` -> `.md` mirror.
|
||||
- If both languages are requested, sync both `README.md` and `README_CN.md`.
|
||||
- After syncing, verify git diff only contains docs file changes.
|
||||
|
||||
1
.github/skills/plugin-scaffolder/SKILL.md
vendored
1
.github/skills/plugin-scaffolder/SKILL.md
vendored
@@ -17,3 +17,4 @@ Generates compliant OpenWebUI plugin templates with built-in i18n, common utilit
|
||||
- `_get_user_context` with JS fallback and timeout
|
||||
- `_emit_status` and `_emit_debug_log` methods
|
||||
- Standardized docstring metadata
|
||||
- README header must use a two-column line with `By/作者 + vX.Y.Z` on the left and the Star link on the right, followed by a compact live badge row for followers, points, top (`Top <1%`), plugin contributions (`📦`), plugin downloads, plugin saves, and plugin views
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# {{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
|
||||
| By [Fu-Jie](https://github.com/Fu-Jie) · v0.1.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
|
||||
| :--- | ---: |
|
||||
|
||||
|  |  |  |  |  |  |  |
|
||||
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||
|
||||
{{DESCRIPTION}}
|
||||
|
||||
|
||||
150
.github/skills/publish-no-version-bump/SKILL.md
vendored
Normal file
150
.github/skills/publish-no-version-bump/SKILL.md
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
---
|
||||
name: publish-no-version-bump
|
||||
description: Commit and push code to GitHub, then publish to OpenWebUI official marketplace without updating version. Use when fixing bugs or optimizing performance that doesn't warrant a version bump.
|
||||
---
|
||||
|
||||
# Publish Without Version Bump
|
||||
|
||||
## Overview
|
||||
|
||||
This skill handles the workflow for pushing code changes to the remote repository and syncing them to the OpenWebUI official marketplace **without incrementing the plugin version number**.
|
||||
|
||||
This is useful for:
|
||||
- Bug fixes and patches
|
||||
- Performance optimizations
|
||||
- Code refactoring
|
||||
- Documentation fixes
|
||||
- Linting and code quality improvements
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when:
|
||||
- You've made non-breaking changes (bug fixes, optimizations, refactoring)
|
||||
- The functionality hasn't changed significantly
|
||||
- The user-facing behavior is unchanged or only improved
|
||||
- There's no need to bump the semantic version
|
||||
|
||||
**Do NOT use** if:
|
||||
- You're adding new features → use `release-prep` instead
|
||||
- You're making breaking changes → use `release-prep` instead
|
||||
- The version should be incremented → use `version-bumper` first
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1 — Stage and Commit Changes
|
||||
|
||||
Ensure all desired code changes are staged in git:
|
||||
|
||||
```bash
|
||||
git status # Verify what will be committed
|
||||
git add -A # Stage all changes
|
||||
```
|
||||
|
||||
Create a descriptive commit message using Conventional Commits format:
|
||||
|
||||
```
|
||||
fix(plugin-name): brief description
|
||||
- Detailed change 1
|
||||
- Detailed change 2
|
||||
```
|
||||
|
||||
Example commit types:
|
||||
- `fix:` — Bug fixes, patches
|
||||
- `perf:` — Performance improvements, optimization
|
||||
- `refactor:` — Code restructuring without behavior change
|
||||
- `test:` — Test updates
|
||||
- `docs:` — Documentation changes
|
||||
|
||||
**Key Rule**: The commit message should make clear that this is NOT a new feature release (no `feat:` type).
|
||||
|
||||
### Step 2 — Push to Remote
|
||||
|
||||
Push the commit to the main branch:
|
||||
|
||||
```bash
|
||||
git commit -m "<message>" && git push
|
||||
```
|
||||
|
||||
Verify the push succeeded by checking GitHub.
|
||||
|
||||
### Step 3 — Publish to Official Marketplace
|
||||
|
||||
Run the publish script with `--force` flag to update the marketplace without version change:
|
||||
|
||||
```bash
|
||||
python scripts/publish_plugin.py --force
|
||||
```
|
||||
|
||||
**Important**: The `--force` flag ensures the marketplace version is updated even if the version string in the plugin file hasn't changed.
|
||||
|
||||
### Step 4 — Verify Publication
|
||||
|
||||
Check that the plugin was successfully updated in the official marketplace:
|
||||
1. Visit https://openwebui.com/f/
|
||||
2. Search for your plugin name
|
||||
3. Verify the code is up-to-date
|
||||
4. Confirm the version number **has NOT changed**
|
||||
|
||||
---
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Full Workflow (Manual)
|
||||
|
||||
```bash
|
||||
# 1. Stage and commit
|
||||
git add -A
|
||||
git commit -m "fix(copilot-sdk): description here"
|
||||
|
||||
# 2. Push
|
||||
git push
|
||||
|
||||
# 3. Publish to marketplace
|
||||
python scripts/publish_plugin.py --force
|
||||
|
||||
# 4. Verify
|
||||
# Check OpenWebUI marketplace for the updated code
|
||||
```
|
||||
|
||||
### Automated (Using This Skill)
|
||||
|
||||
When you invoke this skill with a plugin path, Copilot will:
|
||||
1. Verify staged changes and create the commit
|
||||
2. Push to the remote repository
|
||||
3. Execute the publish script
|
||||
4. Report success/failure status
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Version Handling
|
||||
|
||||
- The plugin's version string in `docstring` (line ~10) remains **unchanged**
|
||||
- The `openwebui_id` in the plugin file must be present for the publish script to work
|
||||
- If the plugin hasn't been published before, use `publish_plugin.py --new <dir>` instead
|
||||
|
||||
### Dry Run
|
||||
|
||||
To preview what would be published without actually updating the marketplace:
|
||||
|
||||
```bash
|
||||
python scripts/publish_plugin.py --force --dry-run
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| `Error: openwebui_id not found` | The plugin hasn't been published yet. Use `publish_plugin.py --new <dir>` for first-time publishing. |
|
||||
| `Failed to authenticate` | Check that the `OPENWEBUI_API_KEY` environment variable is set. |
|
||||
| `Skipped (version unchanged)` | This is normal. Without `--force`, unchanged versions are skipped. We use `--force` to override this. |
|
||||
|
||||
---
|
||||
|
||||
## Related Skills
|
||||
|
||||
- **`release-prep`** — Use when you need to bump the version and create release notes
|
||||
- **`version-bumper`** — Use to manually update version across all 7+ files
|
||||
- **`pr-submitter`** — Use to create a PR instead of pushing directly to main
|
||||
|
||||
13
.github/skills/release-prep/SKILL.md
vendored
13
.github/skills/release-prep/SKILL.md
vendored
@@ -89,6 +89,18 @@ Each file must include:
|
||||
|
||||
If a release notes file already exists for this version, update it rather than creating a new one.
|
||||
|
||||
#### Full Coverage Rule (Mandatory)
|
||||
|
||||
Release notes must cover **all updates in the current release scope** and not only headline features.
|
||||
|
||||
Minimum required coverage in both EN/CN files:
|
||||
- New features and capability enhancements
|
||||
- Bug fixes and reliability fixes
|
||||
- Documentation/README/doc-mirror updates that affect user understanding or usage
|
||||
- Terminology/i18n/wording fixes that change visible behavior or messaging
|
||||
|
||||
Before commit, cross-check release notes against `git diff` and ensure no meaningful update is omitted.
|
||||
|
||||
### Step 5 — Verify Consistency (Pre-Commit Check)
|
||||
|
||||
Run the consistency check script:
|
||||
@@ -130,6 +142,7 @@ Confirm the commit hash and list the number of files changed.
|
||||
- [ ] Both `index.md` version badges updated
|
||||
- [ ] Root `README.md` and `README_CN.md` date badges updated to today
|
||||
- [ ] `What's New` / `最新更新` contains ONLY the latest release
|
||||
- [ ] Release notes include all meaningful updates from the current diff (feature + fix + docs/i18n)
|
||||
- [ ] `v{version}.md` and `v{version}_CN.md` created or updated
|
||||
- [ ] `python3 scripts/check_version_consistency.py` returns no errors
|
||||
- [ ] Commit message is English-only Conventional Commits format
|
||||
|
||||
1
.github/skills/source-code-analyzer/SKILL.md
vendored
1
.github/skills/source-code-analyzer/SKILL.md
vendored
@@ -17,6 +17,7 @@ When assisting with the development of `openwebui-extensions`, you (Antigravity)
|
||||
- **Open WebUI**: `../open-webui/` (Core platform context)
|
||||
- **Skills**: `../skills/` (Reusable expertise library)
|
||||
- **Awesome Copilot**: `../awesome-copilot/` (Shared extensions & resources)
|
||||
- **Open Terminal**: `../open-terminal/` (Terminal integration service)
|
||||
|
||||
### Plugin-Specific (Relevant to GitHub Copilot SDK)
|
||||
|
||||
|
||||
222
.github/workflows/aw-ci-audit.md
vendored
Normal file
222
.github/workflows/aw-ci-audit.md
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
---
|
||||
description: "CI audit workflow for failed releases, publish jobs, stats updates, and other important repository automation"
|
||||
private: true
|
||||
labels: [automation, diagnostics, ci, gh-aw]
|
||||
metadata:
|
||||
author: Fu-Jie
|
||||
category: maintenance
|
||||
maturity: draft
|
||||
on:
|
||||
schedule: daily
|
||||
workflow_dispatch:
|
||||
roles: all
|
||||
skip-bots: [github-actions, copilot, dependabot, renovate]
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
actions: read
|
||||
engine: copilot
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
safe-outputs:
|
||||
create-issue:
|
||||
title-prefix: "[ci-audit] "
|
||||
labels: [ci-audit, maintenance]
|
||||
close-older-issues: false
|
||||
allowed-github-references: [repo]
|
||||
timeout-minutes: 15
|
||||
tools:
|
||||
github:
|
||||
toolsets: [repos, issues, pull_requests]
|
||||
bash:
|
||||
- pwd
|
||||
- ls
|
||||
- cat
|
||||
- head
|
||||
- tail
|
||||
- grep
|
||||
- wc
|
||||
- rg
|
||||
- git status
|
||||
- git diff
|
||||
- git show
|
||||
- git ls-files
|
||||
---
|
||||
|
||||
# CI Audit
|
||||
|
||||
You are the repository maintainer assistant for `Fu-Jie/openwebui-extensions`.
|
||||
|
||||
Your job is to inspect recent repository automation health and create **one concise maintenance issue only when there is actionable CI or automation feedback**.
|
||||
|
||||
If there is no meaningful failure pattern, no new actionable diagnosis, or no useful maintainer issue to open, you **must call `noop`** with a short explanation.
|
||||
|
||||
## Primary Goal
|
||||
|
||||
Audit recent automation health for:
|
||||
|
||||
- failed or flaky release-related workflows
|
||||
- plugin publishing failures
|
||||
- community stats update regressions
|
||||
- repeated workflow drift or fragile maintenance steps
|
||||
- repository-specific next steps maintainers can actually act on
|
||||
|
||||
This workflow is **diagnostic-only**. Do not modify files, push code, open pull requests, or create releases.
|
||||
|
||||
## High-Priority Source Files
|
||||
|
||||
Use these files as the authoritative context before forming conclusions:
|
||||
|
||||
- `.github/copilot-instructions.md`
|
||||
- `.github/workflows/release.yml`
|
||||
- `.github/workflows/publish_plugin.yml`
|
||||
- `.github/workflows/publish_new_plugin.yml`
|
||||
- `.github/workflows/plugin-version-check.yml`
|
||||
- `.github/workflows/community-stats.yml`
|
||||
- `docs/development/gh-aw-integration-plan.md`
|
||||
- `docs/development/gh-aw-integration-plan.zh.md`
|
||||
|
||||
## Target Workflows
|
||||
|
||||
Prioritize these workflows first:
|
||||
|
||||
- `release.yml`
|
||||
- `publish_plugin.yml`
|
||||
- `publish_new_plugin.yml`
|
||||
- `plugin-version-check.yml`
|
||||
- `community-stats.yml`
|
||||
- `deploy.yml`
|
||||
|
||||
If there are no meaningful issues there, do not widen scope unnecessarily.
|
||||
|
||||
## Review Scope
|
||||
|
||||
Focus on recent failed or suspicious automation runs and repository-facing symptoms. Prefer diagnosis that is grounded in repository context, not generic CI advice.
|
||||
|
||||
This workflow should behave like a maintainer who is reviewing workflow health trends, not like a generic log summarizer.
|
||||
|
||||
Focus especially on these areas:
|
||||
|
||||
### 1. Release and Publish Failures
|
||||
|
||||
Inspect whether recent failures suggest actionable problems such as:
|
||||
|
||||
- version extraction or comparison drift
|
||||
- release-note packaging gaps
|
||||
- publish-script authentication or environment issues
|
||||
- assumptions in release jobs that no longer match repository structure
|
||||
- failures that are likely to recur until repository logic changes
|
||||
|
||||
### 2. Stats and Scheduled Workflow Reliability
|
||||
|
||||
Inspect whether scheduled maintenance jobs show drift or fragility such as:
|
||||
|
||||
- community stats commits no longer happening when expected
|
||||
- badge or docs generation assumptions becoming stale
|
||||
- external API dependent jobs failing in repeatable ways
|
||||
- schedule-driven jobs causing noisy or low-value churn
|
||||
|
||||
### 3. Signal Quality for Maintainers
|
||||
|
||||
Only create an issue if there is a useful diagnosis with at least one concrete next step.
|
||||
|
||||
Good issue-worthy findings include:
|
||||
|
||||
- a repeated failure signature across runs
|
||||
- a repository mismatch between workflow logic and current file layout
|
||||
- a likely missing secret, missing permission, or stale path assumption
|
||||
- repeated low-signal failures that should be filtered or hardened
|
||||
|
||||
Do not open issues for one-off noise unless the failure pattern is likely to recur.
|
||||
|
||||
### 4. Existing Issue Awareness
|
||||
|
||||
Before creating a new issue, check whether a recent open issue already appears to cover the same CI failure pattern.
|
||||
|
||||
If an existing issue already covers the problem well enough, prefer `noop` and mention that the diagnosis is already tracked.
|
||||
|
||||
## Severity Model
|
||||
|
||||
Use three levels only:
|
||||
|
||||
- `High`: likely recurring CI or automation failure with repository impact
|
||||
- `Medium`: useful to fix soon to reduce maintenance burden or workflow drift
|
||||
- `Low`: optional hardening or cleanup suggestion
|
||||
|
||||
Do not invent issues just to create a report.
|
||||
|
||||
## Issue Creation Rules
|
||||
|
||||
Create **one maintenance issue** only if there is actionable new diagnosis.
|
||||
|
||||
The issue must:
|
||||
|
||||
- be in English
|
||||
- be concise and maintainer-like
|
||||
- lead with findings, not generic praise
|
||||
- include clickable file references like ``.github/workflows/release.yml`` or ``scripts/publish_plugin.py``
|
||||
- avoid nested bullets
|
||||
- avoid pasting raw logs unless a short excerpt is critical
|
||||
|
||||
Use this exact structure when creating the issue:
|
||||
|
||||
```markdown
|
||||
## CI Audit
|
||||
|
||||
### Summary
|
||||
Short diagnosis of the failure pattern or automation risk.
|
||||
|
||||
### Findings
|
||||
- `path/to/file`: specific problem or likely root cause
|
||||
|
||||
### Suggested Next Steps
|
||||
- concrete maintainer action
|
||||
- concrete maintainer action
|
||||
|
||||
### Notes
|
||||
- Mention whether this appears recurring, new, or already partially mitigated.
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Keep the issue under about 300 words unless multiple workflows are affected.
|
||||
- If there are multiple related findings, group them into one issue rather than opening separate issues.
|
||||
- Prefer a single, actionable diagnosis over a broad laundry list.
|
||||
|
||||
## No-Issue Rule
|
||||
|
||||
If there is no meaningful new diagnosis to report:
|
||||
|
||||
- do not create a status-only issue
|
||||
- do not restate that workflows look healthy
|
||||
- call `noop` with a short explanation like:
|
||||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: reviewed recent repository automation signals and found no new actionable CI diagnosis worth opening as a maintenance issue."}}
|
||||
```
|
||||
|
||||
## Suggested Audit Process
|
||||
|
||||
1. Inspect recent repository automation context.
|
||||
2. Prioritize the target workflows listed above.
|
||||
3. Identify recurring or repository-specific failure patterns.
|
||||
4. Check whether the problem is already tracked in an open issue.
|
||||
5. Draft the shortest useful maintenance issue only if the diagnosis is actionable and new.
|
||||
6. Finish with exactly one `create_issue` or one `noop`.
|
||||
|
||||
## Important Constraints
|
||||
|
||||
- Do not create an issue for a single low-signal transient failure.
|
||||
- Do not propose large refactors unless the failure pattern clearly justifies them.
|
||||
- Prefer repository-specific causes over generic "retry later" style advice.
|
||||
- If the likely root cause is uncertain, state the uncertainty explicitly.
|
||||
- If the pattern appears already tracked, prefer `noop` over duplicate issue creation.
|
||||
|
||||
## Final Requirement
|
||||
|
||||
You **must** finish with exactly one safe output action:
|
||||
|
||||
- `create_issue` if there is actionable new diagnosis
|
||||
- `noop` if there is not
|
||||
236
.github/workflows/aw-pr-maintainer-review.md
vendored
Normal file
236
.github/workflows/aw-pr-maintainer-review.md
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
---
|
||||
description: "Semantic PR maintainer review for plugin standards, bilingual docs sync, and release readiness gaps"
|
||||
private: true
|
||||
labels: [automation, review, pull-request, gh-aw]
|
||||
metadata:
|
||||
author: Fu-Jie
|
||||
category: maintenance
|
||||
maturity: draft
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
- 'docs/**'
|
||||
- '.github/**'
|
||||
- 'README.md'
|
||||
- 'README_CN.md'
|
||||
forks: ["*"]
|
||||
workflow_dispatch:
|
||||
roles: all
|
||||
skip-bots: [github-actions, copilot, dependabot, renovate]
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
engine: copilot
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
safe-outputs:
|
||||
add-comment:
|
||||
target: triggering
|
||||
max: 1
|
||||
hide-older-comments: true
|
||||
footer: false
|
||||
allowed-github-references: [repo]
|
||||
timeout-minutes: 12
|
||||
tools:
|
||||
github:
|
||||
toolsets: [repos, issues, pull_requests]
|
||||
bash:
|
||||
- pwd
|
||||
- ls
|
||||
- cat
|
||||
- head
|
||||
- tail
|
||||
- grep
|
||||
- wc
|
||||
- rg
|
||||
- git status
|
||||
- git diff
|
||||
- git show
|
||||
- git ls-files
|
||||
---
|
||||
|
||||
# PR Maintainer Review
|
||||
|
||||
You are the repository maintainer assistant for `Fu-Jie/openwebui-extensions`.
|
||||
|
||||
Your job is to review the triggering pull request against this repository's standards and leave **one concise summary comment only when there is actionable feedback**.
|
||||
|
||||
If the PR already looks compliant enough and there is no useful maintainer feedback to add, you **must call `noop`** with a short explanation.
|
||||
|
||||
## Primary Goal
|
||||
|
||||
Review the PR for:
|
||||
|
||||
- repository-standard compliance
|
||||
- missing synchronized file updates
|
||||
- release-readiness gaps
|
||||
- documentation drift introduced by the change
|
||||
- risky behavior regressions in plugin code
|
||||
|
||||
This workflow is **review-only**. Do not attempt to modify files, push code, or open pull requests.
|
||||
|
||||
## High-Priority Source Files
|
||||
|
||||
Use these files as the authoritative rule set before forming conclusions:
|
||||
|
||||
- `.github/copilot-instructions.md`
|
||||
- `.github/instructions/code-review.instructions.md`
|
||||
- `.github/instructions/commit-message.instructions.md`
|
||||
- `.github/skills/release-prep/SKILL.md`
|
||||
- `.github/skills/doc-mirror-sync/SKILL.md`
|
||||
- `docs/development/gh-aw-integration-plan.md`
|
||||
- `docs/development/gh-aw-integration-plan.zh.md`
|
||||
|
||||
## Review Scope
|
||||
|
||||
Start from the PR diff and changed files only. Expand into related files only when necessary to verify consistency.
|
||||
|
||||
Prioritize repository policy over generic best practices. This workflow should behave like a maintainer who knows this repository well, not like a broad lint bot.
|
||||
|
||||
Focus especially on these areas:
|
||||
|
||||
### 1. Plugin Code Standards
|
||||
|
||||
When a plugin Python file changes, check for repository-specific correctness:
|
||||
|
||||
- single-file i18n pattern is preserved
|
||||
- user-visible text is routed through translations where appropriate
|
||||
- `_get_user_context` and `_get_chat_context` are used instead of fragile direct access
|
||||
- `__event_call__` JavaScript execution has timeout guards and JS-side fallback handling
|
||||
- `print()` is not introduced in production plugin code
|
||||
- emitter usage is guarded safely
|
||||
- filter plugins do not store request-scoped mutable state on `self`
|
||||
- OpenWebUI/Copilot SDK tool definitions remain consistent with repository conventions
|
||||
|
||||
### 2. Versioning and Release Hygiene
|
||||
|
||||
When `plugins/**/*.py` changes, verify whether the PR also updates what should normally move with it:
|
||||
|
||||
- plugin docstring `version:` changed when behavior changed
|
||||
- local `README.md` and `README_CN.md` changed where user-visible behavior changed
|
||||
- mirrored docs under `docs/plugins/**` changed where required
|
||||
- docs plugin indexes changed if a published version badge or listing text should change
|
||||
- root `README.md` and `README_CN.md` updated date badge if this PR is clearly release-prep oriented
|
||||
|
||||
Do not require every PR to be full release prep. Only flag missing sync files when the PR clearly changes published behavior, plugin metadata, versioned documentation, or release-facing content.
|
||||
|
||||
### 3. Documentation Sync
|
||||
|
||||
When plugin READMEs change, check whether matching docs mirrors should also change:
|
||||
|
||||
- `plugins/{type}/{name}/README.md` -> `docs/plugins/{type}/{name}.md`
|
||||
- `plugins/{type}/{name}/README_CN.md` -> `docs/plugins/{type}/{name}.zh.md`
|
||||
|
||||
When docs-only changes are intentional, avoid over-reporting.
|
||||
|
||||
Useful path mappings:
|
||||
|
||||
- `plugins/actions/{name}/README.md` -> `docs/plugins/actions/{name}.md`
|
||||
- `plugins/actions/{name}/README_CN.md` -> `docs/plugins/actions/{name}.zh.md`
|
||||
- `plugins/filters/{name}/README.md` -> `docs/plugins/filters/{name}.md`
|
||||
- `plugins/filters/{name}/README_CN.md` -> `docs/plugins/filters/{name}.zh.md`
|
||||
- `plugins/pipes/{name}/README.md` -> `docs/plugins/pipes/{name}.md`
|
||||
- `plugins/pipes/{name}/README_CN.md` -> `docs/plugins/pipes/{name}.zh.md`
|
||||
- `plugins/pipelines/{name}/README.md` -> `docs/plugins/pipelines/{name}.md`
|
||||
- `plugins/pipelines/{name}/README_CN.md` -> `docs/plugins/pipelines/{name}.zh.md`
|
||||
- `plugins/tools/{name}/README.md` -> `docs/plugins/tools/{name}.md`
|
||||
- `plugins/tools/{name}/README_CN.md` -> `docs/plugins/tools/{name}.zh.md`
|
||||
|
||||
### 4. PR Quality and Maintainer Signal
|
||||
|
||||
Check whether the PR description is missing key maintainer context:
|
||||
|
||||
- what changed
|
||||
- why it changed
|
||||
- whether users need migration or reconfiguration
|
||||
|
||||
Only mention this if the omission makes review materially harder.
|
||||
|
||||
## Severity Model
|
||||
|
||||
Use three levels only:
|
||||
|
||||
- `Blocking`: likely bug, release regression, missing required sync, or standards breakage
|
||||
- `Important`: should be fixed before merge, but not an obvious runtime break
|
||||
- `Minor`: worthwhile suggestion, but optional
|
||||
|
||||
Do not invent issues just to leave a comment.
|
||||
|
||||
## Commenting Rules
|
||||
|
||||
Leave **one summary comment** only if there is actionable feedback.
|
||||
|
||||
The comment must:
|
||||
|
||||
- be in English
|
||||
- be concise and maintainer-like
|
||||
- lead with findings, not compliments
|
||||
- include clickable file references like ``plugins/pipes/foo/foo.py`` or ``docs/plugins/pipes/index.md``
|
||||
- avoid nested bullets
|
||||
- avoid repeating obvious diff content
|
||||
|
||||
Use this exact structure when commenting:
|
||||
|
||||
```markdown
|
||||
## PR Maintainer Review
|
||||
|
||||
### Blocking
|
||||
- `path/to/file`: specific issue and why it matters
|
||||
|
||||
### Important
|
||||
- `path/to/file`: specific issue and what sync/check is missing
|
||||
|
||||
### Minor
|
||||
- `path/to/file`: optional improvement or consistency note
|
||||
|
||||
### Merge Readiness
|
||||
- Ready after the items above are addressed.
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Omit empty sections.
|
||||
- If there is only one severity category, include only that category plus `Merge Readiness`.
|
||||
- Keep the full comment under about 250 words unless multiple files are involved.
|
||||
|
||||
## No-Comment Rule
|
||||
|
||||
If the PR has no meaningful maintainer findings:
|
||||
|
||||
- do not leave a praise-only comment
|
||||
- do not restate that checks passed
|
||||
- call `noop` with a short explanation like:
|
||||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: reviewed the PR diff and repository sync expectations, and found no actionable maintainer feedback."}}
|
||||
```
|
||||
|
||||
## Suggested Review Process
|
||||
|
||||
1. Identify the changed files in the PR.
|
||||
2. Read the high-priority repository rule files.
|
||||
3. Compare changed plugin code against plugin review instructions.
|
||||
4. Compare changed README or docs files against doc-mirror expectations.
|
||||
5. Determine whether version-sync or release-facing files are missing.
|
||||
6. Draft the shortest useful maintainer summary.
|
||||
7. Leave exactly one `add_comment` or one `noop`.
|
||||
|
||||
## Important Constraints
|
||||
|
||||
- Do not request broad refactors unless the PR already touches that area.
|
||||
- Do not require release-prep steps for tiny internal-only edits.
|
||||
- Do not insist on docs sync when the change is clearly private/internal and not user-facing.
|
||||
- Prefer precise, repository-specific feedback over generic code review advice.
|
||||
- If you are unsure whether a sync file is required, downgrade to `Important` rather than `Blocking`.
|
||||
- If a finding depends on intent that is not visible in the PR, explicitly say it is conditional instead of presenting it as certain.
|
||||
|
||||
## Final Requirement
|
||||
|
||||
You **must** finish with exactly one safe output action:
|
||||
|
||||
- `add_comment` if there is actionable feedback
|
||||
- `noop` if there is not
|
||||
248
.github/workflows/aw-release-preflight.md
vendored
Normal file
248
.github/workflows/aw-release-preflight.md
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
---
|
||||
description: "Release preflight review for version sync, bilingual docs, release notes, and release-facing consistency"
|
||||
private: true
|
||||
labels: [automation, review, release, gh-aw]
|
||||
metadata:
|
||||
author: Fu-Jie
|
||||
category: maintenance
|
||||
maturity: draft
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
paths:
|
||||
- 'plugins/**/*.py'
|
||||
- 'plugins/**/README.md'
|
||||
- 'plugins/**/README_CN.md'
|
||||
- 'plugins/**/v*.md'
|
||||
- 'plugins/**/v*_CN.md'
|
||||
- 'docs/plugins/**/*.md'
|
||||
- 'README.md'
|
||||
- 'README_CN.md'
|
||||
- '.github/**'
|
||||
forks: ["*"]
|
||||
workflow_dispatch:
|
||||
roles: all
|
||||
skip-bots: [github-actions, copilot, dependabot, renovate]
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
pull-requests: read
|
||||
engine: copilot
|
||||
network:
|
||||
allowed:
|
||||
- defaults
|
||||
safe-outputs:
|
||||
add-comment:
|
||||
target: triggering
|
||||
max: 1
|
||||
hide-older-comments: true
|
||||
footer: false
|
||||
allowed-github-references: [repo]
|
||||
timeout-minutes: 12
|
||||
tools:
|
||||
github:
|
||||
toolsets: [repos, issues, pull_requests]
|
||||
bash:
|
||||
- pwd
|
||||
- ls
|
||||
- cat
|
||||
- head
|
||||
- tail
|
||||
- grep
|
||||
- wc
|
||||
- rg
|
||||
- git status
|
||||
- git diff
|
||||
- git show
|
||||
- git ls-files
|
||||
---
|
||||
|
||||
# Release Preflight Review
|
||||
|
||||
You are the repository maintainer assistant for `Fu-Jie/openwebui-extensions`.
|
||||
|
||||
Your job is to perform a **release-preflight review** for the triggering change and leave **one concise summary comment only when there is actionable release-facing feedback**.
|
||||
|
||||
If the change is not actually release-prep, or it already looks consistent enough that there is no useful maintainer feedback to add, you **must call `noop`** with a short explanation.
|
||||
|
||||
## Primary Goal
|
||||
|
||||
Review the change for:
|
||||
|
||||
- version-sync completeness
|
||||
- bilingual README and docs consistency
|
||||
- release-notes completeness
|
||||
- release-facing index or badge drift
|
||||
- missing migration or maintainer context for a user-visible release
|
||||
|
||||
This workflow is **review-only**. Do not modify files, push code, create releases, or open pull requests.
|
||||
|
||||
## High-Priority Source Files
|
||||
|
||||
Use these files as the authoritative rule set before forming conclusions:
|
||||
|
||||
- `.github/copilot-instructions.md`
|
||||
- `.github/instructions/commit-message.instructions.md`
|
||||
- `.github/skills/release-prep/SKILL.md`
|
||||
- `.github/skills/doc-mirror-sync/SKILL.md`
|
||||
- `.github/workflows/release.yml`
|
||||
- `docs/development/gh-aw-integration-plan.md`
|
||||
- `docs/development/gh-aw-integration-plan.zh.md`
|
||||
|
||||
## Review Scope
|
||||
|
||||
Start from the PR diff and changed files only. Expand into related release-facing files only when needed to verify sync.
|
||||
|
||||
Prioritize repository release policy over generic release advice. This workflow should act like a maintainer performing a final consistency pass before a release-oriented merge.
|
||||
|
||||
Focus especially on these areas:
|
||||
|
||||
### 1. Version Sync Across Release Files
|
||||
|
||||
When a plugin release is being prepared, check whether the expected version bump is consistently reflected across the release-facing file set:
|
||||
|
||||
- plugin Python docstring `version:`
|
||||
- plugin-local `README.md`
|
||||
- plugin-local `README_CN.md`
|
||||
- docs mirror page in `docs/plugins/**`
|
||||
- Chinese docs mirror page in `docs/plugins/**/*.zh.md`
|
||||
- plugin list entries or badges in `docs/plugins/{type}/index.md`
|
||||
- plugin list entries or badges in `docs/plugins/{type}/index.zh.md`
|
||||
|
||||
Only flag this when the change is clearly release-oriented, version-oriented, or user-visible enough that a synchronized release update is expected.
|
||||
|
||||
### 2. README and Docs Mirror Consistency
|
||||
|
||||
When plugin README files change, check whether the mirrored docs pages were updated consistently.
|
||||
|
||||
Useful path mappings:
|
||||
|
||||
- `plugins/actions/{name}/README.md` -> `docs/plugins/actions/{name}.md`
|
||||
- `plugins/actions/{name}/README_CN.md` -> `docs/plugins/actions/{name}.zh.md`
|
||||
- `plugins/filters/{name}/README.md` -> `docs/plugins/filters/{name}.md`
|
||||
- `plugins/filters/{name}/README_CN.md` -> `docs/plugins/filters/{name}.zh.md`
|
||||
- `plugins/pipes/{name}/README.md` -> `docs/plugins/pipes/{name}.md`
|
||||
- `plugins/pipes/{name}/README_CN.md` -> `docs/plugins/pipes/{name}.zh.md`
|
||||
- `plugins/pipelines/{name}/README.md` -> `docs/plugins/pipelines/{name}.md`
|
||||
- `plugins/pipelines/{name}/README_CN.md` -> `docs/plugins/pipelines/{name}.zh.md`
|
||||
- `plugins/tools/{name}/README.md` -> `docs/plugins/tools/{name}.md`
|
||||
- `plugins/tools/{name}/README_CN.md` -> `docs/plugins/tools/{name}.zh.md`
|
||||
|
||||
Do not over-report if the change is intentionally docs-only and not a release-prep change.
|
||||
|
||||
### 3. What's New and Release Notes Coverage
|
||||
|
||||
When a release-facing plugin update is present, check whether the release documentation covers the current scope clearly enough:
|
||||
|
||||
- the current `What's New` section reflects the latest release only
|
||||
- the Chinese `最新更新` section is aligned with the English version
|
||||
- `v{version}.md` and `v{version}_CN.md` exist when release notes are expected
|
||||
- release notes cover meaningful feature, fix, docs, or migration changes in the current diff
|
||||
|
||||
Do not require release notes for tiny internal-only edits. Do flag missing release notes if the PR is obviously preparing a published plugin release.
|
||||
|
||||
### 4. Root Readme and Release-Facing Index Drift
|
||||
|
||||
For clearly release-oriented changes, check whether repository-level release-facing surfaces also need updates:
|
||||
|
||||
- root `README.md` updated date badge
|
||||
- root `README_CN.md` updated date badge
|
||||
- plugin index entries under `docs/plugins/**/index.md`
|
||||
- plugin index entries under `docs/plugins/**/index.zh.md`
|
||||
|
||||
Only mention missing root-level updates when the PR is truly release-prep oriented, not for routine internal edits.
|
||||
|
||||
### 5. Maintainer Context and Release Clarity
|
||||
|
||||
Check whether the PR description or visible release-facing text is missing essential context:
|
||||
|
||||
- what is being released
|
||||
- why the release matters
|
||||
- whether migration or reconfiguration is needed
|
||||
|
||||
Only mention this if the omission makes release review materially harder.
|
||||
|
||||
## Severity Model
|
||||
|
||||
Use three levels only:
|
||||
|
||||
- `Blocking`: likely release regression, missing required version sync, or clearly incomplete release-facing update
|
||||
- `Important`: should be fixed before merge to avoid release confusion or drift
|
||||
- `Minor`: worthwhile release-facing cleanup or consistency suggestion
|
||||
|
||||
Do not invent issues just to leave a comment.
|
||||
|
||||
## Commenting Rules
|
||||
|
||||
Leave **one summary comment** only if there is actionable release-preflight feedback.
|
||||
|
||||
The comment must:
|
||||
|
||||
- be in English
|
||||
- be concise and maintainer-like
|
||||
- lead with findings, not compliments
|
||||
- include clickable file references like ``plugins/pipes/foo/README.md`` or ``docs/plugins/pipes/index.md``
|
||||
- avoid nested bullets
|
||||
- avoid restating obvious diff content
|
||||
|
||||
Use this exact structure when commenting:
|
||||
|
||||
```markdown
|
||||
## Release Preflight Review
|
||||
|
||||
### Blocking
|
||||
- `path/to/file`: specific release-facing problem and why it matters
|
||||
|
||||
### Important
|
||||
- `path/to/file`: missing sync or release-documentation gap
|
||||
|
||||
### Minor
|
||||
- `path/to/file`: optional cleanup or consistency improvement
|
||||
|
||||
### Release Readiness
|
||||
- Ready after the items above are addressed.
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Omit empty sections.
|
||||
- If there is only one severity category, include only that category plus `Release Readiness`.
|
||||
- Keep the full comment under about 250 words unless multiple files are involved.
|
||||
|
||||
## No-Comment Rule
|
||||
|
||||
If the change has no meaningful release-preflight findings:
|
||||
|
||||
- do not leave a praise-only comment
|
||||
- do not restate that checks passed
|
||||
- call `noop` with a short explanation like:
|
||||
|
||||
```json
|
||||
{"noop": {"message": "No action needed: reviewed the release-facing diff, version-sync expectations, and bilingual documentation coverage, and found no actionable preflight feedback."}}
|
||||
```
|
||||
|
||||
## Suggested Review Process
|
||||
|
||||
1. Identify whether the change is actually release-oriented.
|
||||
2. Inspect the changed files in the PR diff.
|
||||
3. Read the repository release-prep rule files.
|
||||
4. Check plugin version-sync expectations only where release intent is visible.
|
||||
5. Check README, README_CN, docs mirrors, indexes, and release notes for drift.
|
||||
6. Draft the shortest useful maintainer summary.
|
||||
7. Leave exactly one `add_comment` or one `noop`.
|
||||
|
||||
## Important Constraints
|
||||
|
||||
- Do not force full release-prep expectations onto tiny internal edits.
|
||||
- Do not require root README badge updates unless the PR is clearly release-facing.
|
||||
- Do not ask for release notes if the change is not realistically a release-prep PR.
|
||||
- Prefer repository-specific sync feedback over generic release advice.
|
||||
- If you are unsure whether a release-facing sync file is required, downgrade to `Important` rather than `Blocking`.
|
||||
- If a finding depends on inferred intent, state it conditionally instead of presenting it as certain.
|
||||
|
||||
## Final Requirement
|
||||
|
||||
You **must** finish with exactly one safe output action:
|
||||
|
||||
- `add_comment` if there is actionable feedback
|
||||
- `noop` if there is not
|
||||
16
.github/workflows/community-stats.yml
vendored
16
.github/workflows/community-stats.yml
vendored
@@ -38,9 +38,12 @@ jobs:
|
||||
id: old_stats
|
||||
run: |
|
||||
if [ -f docs/community-stats.json ]; then
|
||||
cp docs/community-stats.json docs/community-stats.json.old
|
||||
echo "total_posts=$(jq -r '.total_posts // 0' docs/community-stats.json)" >> $GITHUB_OUTPUT
|
||||
echo "versions=$(jq -r '[.posts[] | {slug: .slug, version: .version}] | sort_by(.slug) | map("\(.slug):\(.version)") | join(",")' docs/community-stats.json)" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "total_posts=0" >> $GITHUB_OUTPUT
|
||||
echo "versions=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Generate stats report
|
||||
@@ -56,12 +59,15 @@ jobs:
|
||||
id: new_stats
|
||||
run: |
|
||||
echo "total_posts=$(jq -r '.total_posts // 0' docs/community-stats.json)" >> $GITHUB_OUTPUT
|
||||
echo "versions=$(jq -r '[.posts[] | {slug: .slug, version: .version}] | sort_by(.slug) | map("\(.slug):\(.version)") | join(",")' docs/community-stats.json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check for significant changes
|
||||
id: check_changes
|
||||
run: |
|
||||
OLD_POSTS="${{ steps.old_stats.outputs.total_posts }}"
|
||||
NEW_POSTS="${{ steps.new_stats.outputs.total_posts }}"
|
||||
OLD_VERSIONS="${{ steps.old_stats.outputs.versions }}"
|
||||
NEW_VERSIONS="${{ steps.new_stats.outputs.versions }}"
|
||||
|
||||
SHOULD_COMMIT="false"
|
||||
CHANGE_REASON=""
|
||||
@@ -69,14 +75,20 @@ jobs:
|
||||
if [ "$NEW_POSTS" -gt "$OLD_POSTS" ]; then
|
||||
SHOULD_COMMIT="true"
|
||||
CHANGE_REASON="new plugin added ($OLD_POSTS -> $NEW_POSTS)"
|
||||
echo "📦 New plugin detected: $OLD_POSTS -> $NEW_POSTS"
|
||||
elif [ "$NEW_POSTS" -lt "$OLD_POSTS" ]; then
|
||||
SHOULD_COMMIT="true"
|
||||
CHANGE_REASON="plugin removed ($OLD_POSTS -> $NEW_POSTS)"
|
||||
elif [ "$OLD_VERSIONS" != "$NEW_VERSIONS" ]; then
|
||||
SHOULD_COMMIT="true"
|
||||
CHANGE_REASON="plugin versions updated"
|
||||
echo "🔄 Version change detected"
|
||||
fi
|
||||
|
||||
echo "should_commit=$SHOULD_COMMIT" >> $GITHUB_OUTPUT
|
||||
echo "change_reason=$CHANGE_REASON" >> $GITHUB_OUTPUT
|
||||
|
||||
if [ "$SHOULD_COMMIT" = "false" ]; then
|
||||
echo "ℹ️ No significant changes detected, skipping commit"
|
||||
echo "ℹ️ No significant changes (posts or versions), skipping commit"
|
||||
else
|
||||
echo "✅ Significant changes detected: $CHANGE_REASON"
|
||||
fi
|
||||
|
||||
276
.github/workflows/release.yml
vendored
276
.github/workflows/release.yml
vendored
@@ -5,13 +5,13 @@
|
||||
# Triggers:
|
||||
# - Push to main branch when plugins are modified (auto-release)
|
||||
# - Manual trigger (workflow_dispatch) with custom release notes
|
||||
# - Push of version tags (v*)
|
||||
# - Push of plugin version tags (<plugin>-v*)
|
||||
#
|
||||
# What it does:
|
||||
# 1. Detects plugin version changes compared to the last release
|
||||
# 2. Generates release notes with updated plugin information
|
||||
# 3. Creates a GitHub Release with plugin files as downloadable assets
|
||||
# 4. Supports multiple plugin updates in a single release
|
||||
# 4. Enforces one plugin creation/update per release
|
||||
|
||||
name: Plugin Release
|
||||
|
||||
@@ -22,14 +22,20 @@ on:
|
||||
- main
|
||||
paths:
|
||||
- 'plugins/**/*.py'
|
||||
- 'plugins/**/README.md'
|
||||
- 'plugins/**/README_CN.md'
|
||||
- 'plugins/**/v*.md'
|
||||
- 'plugins/**/v*_CN.md'
|
||||
- 'docs/plugins/**/*.md'
|
||||
tags:
|
||||
- '*-v*'
|
||||
- 'v*'
|
||||
|
||||
# Manual trigger with inputs
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version (e.g., v1.0.0). Leave empty for auto-generated version.'
|
||||
description: 'Release tag (e.g., markdown-normalizer-v1.2.8). Leave empty for auto-generated tag.'
|
||||
required: false
|
||||
type: string
|
||||
release_title:
|
||||
@@ -52,13 +58,23 @@ permissions:
|
||||
jobs:
|
||||
check-changes:
|
||||
runs-on: ubuntu-latest
|
||||
# Skip release if commit message contains [skip release]
|
||||
if: ${{ !contains(github.event.head_commit.message, '[skip release]') }}
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
LC_ALL: en_US.UTF-8
|
||||
outputs:
|
||||
has_changes: ${{ steps.detect.outputs.has_changes }}
|
||||
changed_plugins: ${{ steps.detect.outputs.changed_plugins }}
|
||||
changed_plugin_title: ${{ steps.detect.outputs.changed_plugin_title }}
|
||||
changed_plugin_slug: ${{ steps.detect.outputs.changed_plugin_slug }}
|
||||
changed_plugin_version: ${{ steps.detect.outputs.changed_plugin_version }}
|
||||
changed_plugin_count: ${{ steps.detect.outputs.changed_plugin_count }}
|
||||
release_notes: ${{ steps.detect.outputs.release_notes }}
|
||||
has_doc_changes: ${{ steps.detect.outputs.has_doc_changes }}
|
||||
changed_doc_files: ${{ steps.detect.outputs.changed_doc_files }}
|
||||
previous_release_tag: ${{ steps.detect.outputs.previous_release_tag }}
|
||||
compare_ref: ${{ steps.detect.outputs.compare_ref }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -80,32 +96,43 @@ jobs:
|
||||
- name: Detect plugin changes
|
||||
id: detect
|
||||
run: |
|
||||
# Get the last release tag
|
||||
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$LAST_TAG" ]; then
|
||||
echo "No previous release found, treating all plugins as new"
|
||||
COMPARE_REF="$(git rev-list --max-parents=0 HEAD)"
|
||||
else
|
||||
echo "Comparing with last release: $LAST_TAG"
|
||||
COMPARE_REF="$LAST_TAG"
|
||||
# Always compare against the most recent previously released version.
|
||||
CURRENT_TAG=""
|
||||
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
||||
CURRENT_TAG="${GITHUB_REF#refs/tags/}"
|
||||
echo "Current tag event detected: $CURRENT_TAG"
|
||||
fi
|
||||
|
||||
PREVIOUS_RELEASE_TAG=$(git tag --sort=-creatordate | grep -Fxv "$CURRENT_TAG" | head -n1 || true)
|
||||
|
||||
if [ -n "$PREVIOUS_RELEASE_TAG" ]; then
|
||||
echo "Comparing with previous release tag: $PREVIOUS_RELEASE_TAG"
|
||||
COMPARE_REF="$PREVIOUS_RELEASE_TAG"
|
||||
else
|
||||
COMPARE_REF="$(git rev-list --max-parents=0 HEAD)"
|
||||
echo "No previous release tag found, using repository root commit: $COMPARE_REF"
|
||||
fi
|
||||
|
||||
echo "previous_release_tag=$PREVIOUS_RELEASE_TAG" >> "$GITHUB_OUTPUT"
|
||||
echo "compare_ref=$COMPARE_REF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Get current plugin versions
|
||||
python scripts/extract_plugin_versions.py --json --output current_versions.json
|
||||
|
||||
# Get previous plugin versions by checking out old plugins
|
||||
if git worktree add /tmp/old_repo ${COMPARE_REF} 2>/dev/null; then
|
||||
if [ -d /tmp/old_repo/plugins ]; then
|
||||
python scripts/extract_plugin_versions.py --plugins-dir /tmp/old_repo/plugins --json --output old_versions.json
|
||||
OLD_WORKTREE=$(mktemp -d)
|
||||
if git worktree add "$OLD_WORKTREE" ${COMPARE_REF} 2>/dev/null; then
|
||||
if [ -d "$OLD_WORKTREE/plugins" ]; then
|
||||
python scripts/extract_plugin_versions.py --plugins-dir "$OLD_WORKTREE/plugins" --json --output old_versions.json
|
||||
else
|
||||
echo "[]" > old_versions.json
|
||||
fi
|
||||
git worktree remove /tmp/old_repo 2>/dev/null || true
|
||||
git worktree remove "$OLD_WORKTREE" 2>/dev/null || true
|
||||
else
|
||||
echo "Failed to create worktree, using empty version list"
|
||||
echo "[]" > old_versions.json
|
||||
fi
|
||||
rm -rf "$OLD_WORKTREE" 2>/dev/null || true
|
||||
|
||||
# Compare versions and generate release notes
|
||||
python scripts/extract_plugin_versions.py --compare old_versions.json --ignore-removed --output changes.md
|
||||
@@ -114,32 +141,105 @@ jobs:
|
||||
echo "=== Version Changes ==="
|
||||
cat changes.md
|
||||
|
||||
# Detect documentation/release-note changes that should be reflected in release notes
|
||||
git diff --name-only "$COMPARE_REF"..HEAD -- \
|
||||
'plugins/**/README.md' \
|
||||
'plugins/**/README_CN.md' \
|
||||
'plugins/**/v*.md' \
|
||||
'plugins/**/v*_CN.md' \
|
||||
'docs/plugins/**/*.md' > changed_docs.txt || true
|
||||
|
||||
if [ -s changed_docs.txt ]; then
|
||||
echo "has_doc_changes=true" >> $GITHUB_OUTPUT
|
||||
echo "changed_doc_files<<EOF" >> $GITHUB_OUTPUT
|
||||
cat changed_docs.txt >> $GITHUB_OUTPUT
|
||||
echo "" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has_doc_changes=false" >> $GITHUB_OUTPUT
|
||||
echo "changed_doc_files=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Check if there are any changes
|
||||
if grep -q "No changes detected" changes.md; then
|
||||
# Only trigger release if there are actual version changes, not just doc changes
|
||||
echo "has_changes=false" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugins=" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_title=" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_slug=" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_version=" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_count=0" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "has_changes=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Extract changed plugin file paths using Python
|
||||
python3 -c "
|
||||
# Extract changed plugin metadata and enforce a single-plugin release.
|
||||
python3 <<'PY'
|
||||
import json
|
||||
with open('changes.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
files = []
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
data = json.load(open('changes.json', 'r', encoding='utf-8'))
|
||||
|
||||
def get_plugin_meta(plugin):
|
||||
manifest = plugin.get('data', {}).get('function', {}).get('meta', {}).get('manifest', {})
|
||||
title = (manifest.get('title') or plugin.get('title') or '').strip()
|
||||
version = (manifest.get('version') or plugin.get('version') or '').strip()
|
||||
file_path = (plugin.get('file_path') or '').strip()
|
||||
slug = Path(file_path).parent.name.replace('_', '-').strip() if file_path else ''
|
||||
return {
|
||||
'title': title,
|
||||
'slug': slug,
|
||||
'version': version,
|
||||
'file_path': file_path,
|
||||
}
|
||||
|
||||
plugins = []
|
||||
seen_keys = set()
|
||||
|
||||
for plugin in data.get('added', []):
|
||||
if 'file_path' in plugin:
|
||||
files.append(plugin['file_path'])
|
||||
meta = get_plugin_meta(plugin)
|
||||
key = meta['file_path'] or meta['title']
|
||||
if key and key not in seen_keys:
|
||||
plugins.append(meta)
|
||||
seen_keys.add(key)
|
||||
|
||||
for update in data.get('updated', []):
|
||||
if 'current' in update and 'file_path' in update['current']:
|
||||
files.append(update['current']['file_path'])
|
||||
print('\n'.join(files))
|
||||
" > changed_files.txt
|
||||
meta = get_plugin_meta(update.get('current', {}))
|
||||
key = meta['file_path'] or meta['title']
|
||||
if key and key not in seen_keys:
|
||||
plugins.append(meta)
|
||||
seen_keys.add(key)
|
||||
|
||||
Path('changed_files.txt').write_text(
|
||||
'\n'.join(meta['file_path'] for meta in plugins if meta['file_path']),
|
||||
encoding='utf-8',
|
||||
)
|
||||
Path('changed_plugin_count.txt').write_text(str(len(plugins)), encoding='utf-8')
|
||||
|
||||
if len(plugins) > 1:
|
||||
print('Error: release workflow only supports one plugin creation/update per release.', file=sys.stderr)
|
||||
for meta in plugins:
|
||||
print(
|
||||
f"- {meta['title'] or 'Unknown'} v{meta['version'] or '?'} ({meta['file_path'] or 'unknown path'})",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
selected = plugins[0] if plugins else {'title': '', 'slug': '', 'version': ''}
|
||||
Path('changed_plugin_title.txt').write_text(selected['title'], encoding='utf-8')
|
||||
Path('changed_plugin_slug.txt').write_text(selected['slug'], encoding='utf-8')
|
||||
Path('changed_plugin_version.txt').write_text(selected['version'], encoding='utf-8')
|
||||
PY
|
||||
|
||||
echo "changed_plugins<<EOF" >> $GITHUB_OUTPUT
|
||||
cat changed_files.txt >> $GITHUB_OUTPUT
|
||||
echo "" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "changed_plugin_title=$(cat changed_plugin_title.txt)" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_slug=$(cat changed_plugin_slug.txt)" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_version=$(cat changed_plugin_version.txt)" >> $GITHUB_OUTPUT
|
||||
echo "changed_plugin_count=$(cat changed_plugin_count.txt)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Store release notes
|
||||
@@ -152,7 +252,7 @@ jobs:
|
||||
|
||||
release:
|
||||
needs: check-changes
|
||||
if: needs.check-changes.outputs.has_changes == 'true' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')
|
||||
if: needs.check-changes.outputs.has_changes == 'true' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
@@ -180,41 +280,45 @@ jobs:
|
||||
id: version
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CHANGED_PLUGIN_SLUG: ${{ needs.check-changes.outputs.changed_plugin_slug }}
|
||||
CHANGED_PLUGIN_VERSION: ${{ needs.check-changes.outputs.changed_plugin_version }}
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then
|
||||
VERSION="${{ github.event.inputs.version }}"
|
||||
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||
VERSION="${GITHUB_REF#refs/tags/}"
|
||||
elif [ -n "$CHANGED_PLUGIN_SLUG" ] && [ -n "$CHANGED_PLUGIN_VERSION" ]; then
|
||||
VERSION="${CHANGED_PLUGIN_SLUG}-v${CHANGED_PLUGIN_VERSION}"
|
||||
else
|
||||
# Auto-generate version based on date and daily release count
|
||||
TODAY=$(date +'%Y.%m.%d')
|
||||
TODAY_PREFIX="v${TODAY}-"
|
||||
|
||||
# Count existing releases with today's date prefix
|
||||
# grep -c returns 1 if count is 0, so we use || true to avoid script failure
|
||||
EXISTING_COUNT=$(gh release list --limit 100 2>/dev/null | grep -c "^${TODAY_PREFIX}" || true)
|
||||
|
||||
# Clean up output (handle potential newlines or fallback issues)
|
||||
EXISTING_COUNT=$(echo "$EXISTING_COUNT" | tr -cd '0-9')
|
||||
if [ -z "$EXISTING_COUNT" ]; then EXISTING_COUNT=0; fi
|
||||
|
||||
NEXT_NUM=$((EXISTING_COUNT + 1))
|
||||
|
||||
VERSION="${TODAY_PREFIX}${NEXT_NUM}"
|
||||
|
||||
# Final fallback to ensure VERSION is never empty
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION="v$(date +'%Y.%m.%d-%H%M%S')"
|
||||
fi
|
||||
echo "Error: failed to determine plugin-scoped release tag." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Release version: $VERSION"
|
||||
echo "Release tag: $VERSION"
|
||||
|
||||
- name: Build release metadata
|
||||
id: meta
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
INPUT_TITLE: ${{ github.event.inputs.release_title }}
|
||||
CHANGED_PLUGIN_TITLE: ${{ needs.check-changes.outputs.changed_plugin_title }}
|
||||
CHANGED_PLUGIN_VERSION: ${{ needs.check-changes.outputs.changed_plugin_version }}
|
||||
run: |
|
||||
if [ -n "$INPUT_TITLE" ]; then
|
||||
RELEASE_NAME="$INPUT_TITLE"
|
||||
elif [ -n "$CHANGED_PLUGIN_TITLE" ] && [ -n "$CHANGED_PLUGIN_VERSION" ]; then
|
||||
RELEASE_NAME="$CHANGED_PLUGIN_TITLE v$CHANGED_PLUGIN_VERSION"
|
||||
else
|
||||
RELEASE_NAME="$VERSION"
|
||||
fi
|
||||
|
||||
echo "release_name=$RELEASE_NAME" >> "$GITHUB_OUTPUT"
|
||||
echo "Release name: $RELEASE_NAME"
|
||||
|
||||
- name: Extract plugin versions
|
||||
id: plugins
|
||||
run: |
|
||||
python scripts/extract_plugin_versions.py --json --output plugin_versions.json
|
||||
python scripts/extract_plugin_versions.py --json --output plugin_versions.json
|
||||
|
||||
- name: Collect plugin files for release
|
||||
id: collect_files
|
||||
@@ -304,13 +408,16 @@ jobs:
|
||||
- name: Get commit messages
|
||||
id: commits
|
||||
if: github.event_name == 'push'
|
||||
env:
|
||||
PREVIOUS_RELEASE_TAG: ${{ needs.check-changes.outputs.previous_release_tag }}
|
||||
COMPARE_REF: ${{ needs.check-changes.outputs.compare_ref }}
|
||||
run: |
|
||||
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$LAST_TAG" ]; then
|
||||
COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s" --no-merges -- plugins/ | head -20)
|
||||
if [ -n "$PREVIOUS_RELEASE_TAG" ]; then
|
||||
COMMITS=$(git log ${PREVIOUS_RELEASE_TAG}..HEAD --pretty=format:"- **%s**%n%b" --no-merges -- plugins/ | sed '/^$/d' | head -40)
|
||||
elif [ -n "$COMPARE_REF" ]; then
|
||||
COMMITS=$(git log ${COMPARE_REF}..HEAD --pretty=format:"- **%s**%n%b" --no-merges -- plugins/ | sed '/^$/d' | head -40)
|
||||
else
|
||||
COMMITS=$(git log --pretty=format:"- %s" --no-merges -10 -- plugins/)
|
||||
COMMITS=$(git log --pretty=format:"- **%s**%n%b" --no-merges -10 -- plugins/ | sed '/^$/d')
|
||||
fi
|
||||
|
||||
{
|
||||
@@ -326,30 +433,37 @@ jobs:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
TITLE: ${{ github.event.inputs.release_title }}
|
||||
NOTES: ${{ github.event.inputs.release_notes }}
|
||||
CHANGED_PLUGIN_TITLE: ${{ needs.check-changes.outputs.changed_plugin_title }}
|
||||
CHANGED_PLUGIN_VERSION: ${{ needs.check-changes.outputs.changed_plugin_version }}
|
||||
DETECTED_CHANGES: ${{ needs.check-changes.outputs.release_notes }}
|
||||
COMMITS: ${{ steps.commits.outputs.commits }}
|
||||
DOC_FILES: ${{ needs.check-changes.outputs.changed_doc_files }}
|
||||
run: |
|
||||
> release_notes.md
|
||||
|
||||
if [ -n "$TITLE" ]; then
|
||||
echo "## $TITLE" >> release_notes.md
|
||||
# 1. Primary content from v*.md files (highest priority)
|
||||
if [ -n "$DOC_FILES" ]; then
|
||||
RELEASE_NOTE_FILES=$(echo "$DOC_FILES" | grep -E '^plugins/.*/v[^/]*\.md$' | grep -v '_CN\.md$' || true)
|
||||
if [ -n "$RELEASE_NOTE_FILES" ]; then
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
if [ -f "$file" ]; then
|
||||
# Extract content, removing any H1 title from the file to avoid duplication
|
||||
python3 -c "import pathlib, re; file_path = pathlib.Path(r'''$file'''); text = file_path.read_text(encoding='utf-8'); text = re.sub(r'^#\s+.+?(?:\r?\n)+', '', text, count=1, flags=re.MULTILINE); print(text.lstrip().rstrip())" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
fi
|
||||
done <<< "$RELEASE_NOTE_FILES"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2. Automated plugin version change summary
|
||||
if [ -n "$DETECTED_CHANGES" ] && ! echo "$DETECTED_CHANGES" | grep -q "No changes detected"; then
|
||||
echo "## What's Changed" >> release_notes.md
|
||||
echo "## Version Changes" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
echo "$DETECTED_CHANGES" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
fi
|
||||
|
||||
if [ -n "$COMMITS" ]; then
|
||||
echo "## Commits" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
echo "$COMMITS" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
fi
|
||||
|
||||
# 3. Manual additional notes from workflow dispatch
|
||||
if [ -n "$NOTES" ]; then
|
||||
echo "## Additional Notes" >> release_notes.md
|
||||
echo "" >> release_notes.md
|
||||
@@ -357,38 +471,22 @@ jobs:
|
||||
echo "" >> release_notes.md
|
||||
fi
|
||||
|
||||
|
||||
|
||||
cat >> release_notes.md << 'EOF'
|
||||
|
||||
## Download
|
||||
|
||||
📦 **Download the updated plugin files below**
|
||||
|
||||
### Installation
|
||||
|
||||
#### From OpenWebUI Community
|
||||
1. Open OpenWebUI Admin Panel
|
||||
2. Navigate to Functions/Tools
|
||||
3. Search for the plugin name
|
||||
4. Click Install
|
||||
|
||||
#### Manual Installation
|
||||
1. Download the plugin file (`.py`) from the assets below
|
||||
2. Open OpenWebUI Admin Panel → Functions
|
||||
3. Click "Create Function" → Import
|
||||
4. Paste the plugin code
|
||||
|
||||
---
|
||||
|
||||
📚 [Documentation](https://fu-jie.github.io/openwebui-extensions/)
|
||||
📚 [Documentation Portal](https://fu-jie.github.io/openwebui-extensions/)
|
||||
🐛 [Report Issues](https://github.com/Fu-Jie/openwebui-extensions/issues)
|
||||
EOF
|
||||
|
||||
echo "=== Final Release Notes ==="
|
||||
cat release_notes.md
|
||||
|
||||
echo "=== Release Notes ==="
|
||||
cat release_notes.md
|
||||
|
||||
- name: Create Git Tag
|
||||
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
|
||||
@@ -412,7 +510,7 @@ jobs:
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.version }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
name: ${{ github.event.inputs.release_title || steps.version.outputs.version }}
|
||||
name: ${{ steps.meta.outputs.release_name }}
|
||||
body_path: release_notes.md
|
||||
prerelease: ${{ github.event.inputs.prerelease || false }}
|
||||
make_latest: true
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -142,3 +142,4 @@ logs/
|
||||
# OpenWebUI specific
|
||||
# Add any specific ignores for OpenWebUI plugins if needed
|
||||
.git-worktrees/
|
||||
plugins/filters/auth_model_info/
|
||||
|
||||
75
CHANGELOG.md
75
CHANGELOG.md
@@ -1,75 +0,0 @@
|
||||
# Changelog / 更新日志
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
本项目的所有重要更改都将记录在此文件中。
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
||||
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
||||
|
||||
---
|
||||
|
||||
## [Unreleased] / 未发布
|
||||
|
||||
### Added / 新增
|
||||
- 插件发布工作流 (Plugin release workflow)
|
||||
|
||||
### Changed / 变更
|
||||
|
||||
### Fixed / 修复
|
||||
|
||||
### Removed / 移除
|
||||
|
||||
---
|
||||
|
||||
## Plugin Versions / 插件版本
|
||||
|
||||
### Actions
|
||||
|
||||
| Plugin / 插件 | Version / 版本 |
|
||||
|---------------|----------------|
|
||||
| Smart Mind Map / 思维导图 | 0.8.0 |
|
||||
| Flash Card / 闪记卡 | 0.2.1 |
|
||||
| Export to Word / 导出为 Word | 0.1.0 |
|
||||
| Export to Excel / 导出为 Excel | 0.3.3 |
|
||||
| Deep Reading & Summary / 精读 | 0.1.0 / 2.0.0 |
|
||||
| Smart Infographic / 智能信息图 | 1.3.0 |
|
||||
|
||||
### Filters
|
||||
|
||||
| Plugin / 插件 | Version / 版本 |
|
||||
|---------------|----------------|
|
||||
| Async Context Compression / 异步上下文压缩 | 1.1.0 |
|
||||
| Context & Model Enhancement Filter | 0.2 |
|
||||
| Gemini Manifold Companion | 1.7.0 |
|
||||
| Gemini 多模态过滤器 | 0.3.2 |
|
||||
|
||||
### Pipes
|
||||
|
||||
| Plugin / 插件 | Version / 版本 |
|
||||
|---------------|----------------|
|
||||
| Gemini Manifold google_genai | 1.26.0 |
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Release Template / 发布模板:
|
||||
|
||||
## [x.x.x] - YYYY-MM-DD
|
||||
|
||||
### Added / 新增
|
||||
- New feature description
|
||||
|
||||
### Changed / 变更
|
||||
- Change description
|
||||
|
||||
### Fixed / 修复
|
||||
- Bug fix description
|
||||
|
||||
### Plugin Updates / 插件更新
|
||||
- `plugin_name`: v0.x.0 -> v0.y.0
|
||||
- Feature 1
|
||||
- Feature 2
|
||||
-->
|
||||
32
CLAUDE.md
Normal file
32
CLAUDE.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# 🤖 OpenWebUI Extensions
|
||||
|
||||
## 🤝 Project Standards
|
||||
Read these BEFORE writing any code:
|
||||
- `.agent/rules/plugin_standards.md`
|
||||
|
||||
## 📖 Development Guidelines
|
||||
|
||||
### Writing Documentation
|
||||
- All plugins MUST have both English (`README.md`) and Chinese (`README_CN.md`) documentation
|
||||
- Follow the template at `docs/PLUGIN_README_TEMPLATE.md`
|
||||
- Keep versions in sync across all files
|
||||
|
||||
### Code Standards
|
||||
- Use logging instead of print
|
||||
- Implement Valves for configuration
|
||||
- Use Lucide icons
|
||||
- Include i18n support
|
||||
|
||||
### Release Process
|
||||
- Update version numbers in ALL relevant files (code, READMEs, docs)
|
||||
- Use Conventional Commits format (`feat`, `fix`, `docs`, etc.)
|
||||
- Create PRs using GitHub CLI (`gh pr create`)
|
||||
|
||||
## Author
|
||||
|
||||
Fu-Jie
|
||||
GitHub: [Fu-Jie/openwebui-extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
@@ -21,6 +21,7 @@ Plugin types: `actions` / `filters` / `pipes` / `pipelines` / `tools`
|
||||
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.
|
||||
5. **Knowledge capture.** Whenever you discover a non-obvious pattern, gotcha, or workaround (e.g., internal API contracts, mock object requirements, parameter injection quirks), save it to `.agent/learnings/{topic}.md` **before ending the session**. See `.agent/learnings/README.md` for format and existing entries.
|
||||
|
||||
---
|
||||
|
||||
|
||||
1
LICENSE
1
LICENSE
@@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
95
README.md
95
README.md
@@ -5,34 +5,32 @@
|
||||
|
||||
English | [中文](./README_CN.md)
|
||||
|
||||
A collection of enhancements, plugins, and prompts for [OpenWebUI](https://github.com/open-webui/open-webui), developed and curated for personal use to extend functionality and improve experience.
|
||||
A collection of enhancements, plugins, and prompts for [open-webui](https://github.com/open-webui/open-webui), developed and curated for personal use to extend functionality and improve experience.
|
||||
|
||||
<!-- STATS_START -->
|
||||
## 📊 Community Stats
|
||||
>
|
||||
> 
|
||||
|
||||
| 👤 Author | 👥 Followers | ⭐ Points | 🏆 Contributions |
|
||||
| 👤 Author | 👥 Followers | ⭐ Points | 🧩 Plugin Contributions |
|
||||
| :---: | :---: | :---: | :---: |
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) |  |  |  |
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) |  |  |  |
|
||||
|
||||
| 📝 Posts | ⬇️ Downloads | 👁️ Views | 👍 Upvotes | 💾 Saves |
|
||||
| 📝 Posts | ⬇️ Plugin Downloads | 👁️ Plugin Views | 👍 Upvotes | 💾 Plugin Saves |
|
||||
| :---: | :---: | :---: | :---: | :---: |
|
||||
|  |  |  |  |  |
|
||||
|  |  |  |  |  |
|
||||
|
||||
|
||||
### 🔥 Top 6 Popular Plugins
|
||||
|
||||
| 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) |  |  |  |  |
|
||||
| 🥇 | [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️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) |  |  |  |  |
|
||||
| 5️⃣ | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) |  |  |  |  |
|
||||
| 6️⃣ | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) |  |  |  |  |
|
||||
|
||||
### 📈 Total Downloads Trend
|
||||
|
||||

|
||||
|
||||
*See full stats and charts in [Community Stats Report](./docs/community-stats.md)*
|
||||
@@ -40,46 +38,67 @@ A collection of enhancements, plugins, and prompts for [OpenWebUI](https://githu
|
||||
|
||||
## 🌟 Star Features
|
||||
|
||||
### 1. [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) [](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4)
|
||||
### 1. [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4)    
|
||||
|
||||
**The ultimate autonomous Agent for OpenWebUI.** Transforming your LLM into a powerful OS-level engineer with native code execution, deep tool autonomy, and professional skill management.
|
||||
**The ultimate autonomous Agent integration for OpenWebUI.** Deeply bridging GitHub Copilot SDK with your OpenWebUI ecosystem. It enables the Agent to autonomously perform **intent recognition**, **web search**, and **context compaction** while reusing your existing tools, skills, and configurations for a professional, full-featured experience.
|
||||
|
||||
> [!TIP]
|
||||
> **No GitHub Copilot subscription required!** Supports **BYOK (Bring Your Own Key)** mode using your own OpenAI/Anthropic API keys.
|
||||
|
||||
#### 🚀 Key Leap (v0.9.0+)
|
||||
#### 🚀 Key Leap (v0.12.0)
|
||||
|
||||
- **🧩 Skills Revolution**: Native support for **SKILL directories** (scripts, templates, resources) coupled with a **Bidirectional Bridge** to OpenWebUI Workspace Skills.
|
||||
- **🛡️ Secure Isolation**: Strict user/session-level **Workspace Sandboxing** with persistent configuration.
|
||||
- **📊 Interactive Delivery**: Professional **File Delivery Protocol** for instant HTML artifacts and persistent downloadable results.
|
||||
- **🚀 High-Performance Shared Pool**: Eliminated 1-2s process startup latency between turns via a persistent client pool.
|
||||
- **🔑 Pure BYOK Mode**: Now supports full operation without a `GH_TOKEN`, relying solely on custom API keys.
|
||||
- **📏 RichUI Stability**: Fixed height calculation issues for a rock-solid interactive component experience.
|
||||
- **🩺 Smart Stall Detection**: Integrated `client.ping()` to rescue heavy tasks from premature timeouts.
|
||||
- **📋 Live TODO Widget**: Compact real-time task tracking synchronized with `session.db`, now automatically hidden when all tasks are completed.
|
||||
- **🔌 Seamless Ecosystem Integration**: Automatically injects and reuses your OpenWebUI **Tools**, **MCP**, **OpenAPI Servers**, and **Skills**.
|
||||
- **🌐 Language Consistency**: System prompts mandate that Agent output language remains strictly consistent with user input.
|
||||
- **🛡️ Secure Isolation**: Strict user/session-level **Workspace Sandboxing** with user-isolated environment variables.
|
||||
- **📊 Interactive Delivery**: Full support for **HTML Artifacts** and **RichUI** rendering, providing instant interactive previews and persistent downloadable results.
|
||||
- **🛠️ Deterministic Toolchain**: Built-in specialized tools for skill lifecycles (`manage_skills`) and system optimization.
|
||||
|
||||
> [!TIP]
|
||||
> **💡 Pro Tip: Enhanced Visualization**
|
||||
> We highly recommend asking the Agent to install the [Visual Explainer](https://github.com/nicobailon/visual-explainer) skill during your conversation. It dramatically improves the aesthetics and interactivity of generated **HTML Artifacts**. Simply tell the AI:
|
||||
> "Please install this skill: <https://github.com/nicobailon/visual-explainer>" to get started.
|
||||
|
||||
#### 📺 Demo: Visual Skills & Data Analysis
|
||||
|
||||

|
||||
> *In this demo, the Agent installs a visual enhancement skill and automatically generates an interactive dashboard from World Cup data.*
|
||||
|
||||

|
||||
> *Combined with the Excel Expert skill, the Agent can automate complex data cleaning, multi-dimensional statistics, and generate professional data dashboards.*
|
||||
|
||||
#### 🌟 Featured Real-World Cases
|
||||
|
||||
- **[GitHub Star Forecasting](./docs/plugins/pipes/star-prediction-example.md)**: Automatically parsing CSV data, writing analysis scripts, and generating interactive growth dashboards.
|
||||
- **[Video Optimization](./docs/plugins/pipes/video-processing-example.md)**: Direct control of system-level tools (FFmpeg) to accelerate and compress media with professional color optimization.
|
||||
|
||||
### 2. [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) [](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a)
|
||||
### 2. [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a)
|
||||
|
||||
**Experience interactive thinking.** Seamlessly transforms complex chat sessions into structured, clickable mind maps for better visual modeling and rapid idea extraction.
|
||||
|
||||
### 3. [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) [](https://openwebui.com/posts/smart_infographic_ad6f0c7f)
|
||||
### 3. [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f)
|
||||
|
||||
**Professional data storytelling.** Converts raw information into sleek, boardroom-ready infographics powered by AntV, perfect for summarizing long-form content instantly.
|
||||
|
||||
### 4. [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) [](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315)
|
||||
### 4. [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315)
|
||||
|
||||
**High-fidelity reporting.** Export conversation history into professionally formatted Word documents with preserved headers, code blocks, and math formulas.
|
||||
|
||||
### 5. [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) [](https://openwebui.com/posts/async_context_compression_b1655bc8)
|
||||
### 5. [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8)
|
||||
|
||||
**Maximize your context window.** Intelligently compresses chat history using LLM logic to save tokens and costs while maintaining a high-quality reasoning chain.
|
||||
|
||||
### 6. [Batch Install Plugins from GitHub](https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80) [](https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80)
|
||||
|
||||
**Faster plugin onboarding across community repositories.** Pull plugins from multiple GitHub repositories in one request, then narrow the result set inside an interactive dialog with repository tags, type filters, keyword search, and descriptions before installing only the subset you want.
|
||||
|
||||

|
||||
> *A single install dialog can merge multiple repositories and let you filter visually before anything is installed.*
|
||||
|
||||
## 📦 Project Contents
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
@@ -97,6 +116,12 @@ Located in the `plugins/` directory, containing Python-based enhancements:
|
||||
- **Export to Excel** (`export_to_excel`): Exports chat history to Excel files.
|
||||
- **Export to Word** (`export_to_docx`): Exports chat history to Word documents.
|
||||
|
||||
### Tools
|
||||
|
||||
- **Smart Mind Map Tool** (`smart-mind-map-tool`): The tool version of Smart Mind Map, enabling AI proactive/autonomous invocation.
|
||||
- **OpenWebUI Skills Manager Tool** (`openwebui-skills-manager-tool`): Native tool for managing OpenWebUI skills.
|
||||
- **Batch Install Plugins from GitHub** (`batch-install-plugins`): Discovers plugins from multiple GitHub repositories and installs them through an interactive repository/type-filtered selection dialog.
|
||||
|
||||
### Filters
|
||||
|
||||
- **GitHub Copilot SDK Files Filter** (`github_copilot_sdk_files_filter`): Essential companion for Copilot SDK. Bypasses RAG to ensure full file accessibility for Agents.
|
||||
@@ -108,7 +133,7 @@ Located in the `plugins/` directory, containing Python-based enhancements:
|
||||
|
||||
### Pipes
|
||||
|
||||
- **GitHub Copilot SDK** (`github-copilot-sdk`): Official GitHub Copilot SDK integration. Supports dynamic models (GPT-4o, Claude 3.5, o1), multi-turn conversation, streaming, and infinite sessions.
|
||||
- **GitHub Copilot SDK** (`github-copilot-sdk`): Official GitHub Copilot SDK integration (v0.12.0). Supports dynamic models (GPT-4o, Claude 3.7, o1), multi-turn conversation, and high-performance process pooling.
|
||||
|
||||
### Pipelines
|
||||
|
||||
@@ -148,13 +173,6 @@ For code examples, please check the `docs/examples/` directory.
|
||||
|
||||
This project is a collection of resources and does not require a Python environment. Simply download the files you need and import them into your OpenWebUI instance.
|
||||
|
||||
### Using Prompts
|
||||
|
||||
1. Browse the `/prompts` directory and select a prompt file (`.md`).
|
||||
2. Copy the file content.
|
||||
3. In the OpenWebUI chat interface, click the "Prompt" button above the input box.
|
||||
4. Paste the content and save.
|
||||
|
||||
### Using Plugins
|
||||
|
||||
1. **Install from OpenWebUI Community (Recommended)**:
|
||||
@@ -162,11 +180,14 @@ This project is a collection of resources and does not require a Python environm
|
||||
- Browse the plugins and select the one you like.
|
||||
- Click "Get" to import it directly into your OpenWebUI instance.
|
||||
|
||||
2. **Manual Installation**:
|
||||
- Browse the `/plugins` directory and download the plugin file (`.py`) you need.
|
||||
- Go to OpenWebUI **Admin Panel** -> **Settings** -> **Plugins**.
|
||||
- Click the upload button and select the `.py` file you just downloaded.
|
||||
- Once uploaded, refresh the page to enable the plugin in your chat settings or toolbar.
|
||||
2. **Quick Install All Plugins**: To install all plugins to your local OpenWebUI instance at once, clone this repo and run `python scripts/install_all_plugins.py` after configuring your API key in `.env` — see [Deployment Guide](./scripts/DEPLOYMENT_GUIDE.md) for details.
|
||||
|
||||
### Using Prompts
|
||||
|
||||
1. Browse the `/prompts` directory and select a prompt file (`.md`).
|
||||
2. Copy the file content.
|
||||
3. In the OpenWebUI chat interface, click the "Prompt" button above the input box.
|
||||
4. Paste the content and save.
|
||||
|
||||
### Contributing
|
||||
|
||||
|
||||
81
README_CN.md
81
README_CN.md
@@ -6,30 +6,28 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
|
||||
<!-- STATS_START -->
|
||||
## 📊 社区统计
|
||||
>
|
||||
> 
|
||||
|
||||
| 👤 作者 | 👥 粉丝 | ⭐ 积分 | 🏆 贡献 |
|
||||
| 👤 作者 | 👥 粉丝 | ⭐ 积分 | 🧩 插件贡献 |
|
||||
| :---: | :---: | :---: | :---: |
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) |  |  |  |
|
||||
| [Fu-Jie](https://openwebui.com/u/Fu-Jie) |  |  |  |
|
||||
|
||||
| 📝 发布 | ⬇️ 下载 | 👁️ 浏览 | 👍 点赞 | 💾 收藏 |
|
||||
| 📝 发布 | ⬇️ 插件下载 | 👁️ 插件浏览 | 👍 点赞 | 💾 插件收藏 |
|
||||
| :---: | :---: | :---: | :---: | :---: |
|
||||
|  |  |  |  |  |
|
||||
|  |  |  |  |  |
|
||||
|
||||
|
||||
### 🔥 热门插件 Top 6
|
||||
|
||||
| 排名 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 |
|
||||
| :---: | :--- | :---: | :---: | :---: | :---: |
|
||||
| 🥇 | [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) |  |  |  |  |
|
||||
| 🥇 | [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️⃣ | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) |  |  |  |  |
|
||||
| 5️⃣ | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) |  |  |  |  |
|
||||
| 6️⃣ | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) |  |  |  |  |
|
||||
|
||||
### 📈 总下载量累计趋势
|
||||
|
||||

|
||||
|
||||
*完整统计与趋势图请查看 [社区统计报告](./docs/community-stats.zh.md)*
|
||||
@@ -37,25 +35,37 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
|
||||
## 🌟 精选功能
|
||||
|
||||
### 1. [GitHub Copilot SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) [](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4)
|
||||
### 1. [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) [](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) 
|
||||
|
||||
**OpenWebUI 终极自主 Agent 增强。** 将 LLM 转化为具备 OS 级操作能力的专业工程师,支持原生代码执行、深度工具自治以及专业技能管理。
|
||||
**OpenWebUI 终极自主 Agent 深度集成。** 将 GitHub Copilot SDK 与 OpenWebUI 生态完美桥接。它允许 Agent 具备**智能意图识别**、**自主网页搜索**与**自动上下文压缩**能力,同时直接复用您现有的工具、技能与配置,通过全功能 Skill 体系带来极致的专业交互体验。
|
||||
|
||||
> [!TIP]
|
||||
> **无需 GitHub Copilot 订阅!** 支持 **BYOK (Bring Your Own Key)** 模式,使用你自己的 OpenAI/Anthropic API Key。
|
||||
|
||||
#### 🚀 核心进化 (v0.9.0+)
|
||||
#### 🚀 核心进化 (v0.12.0)
|
||||
|
||||
- **🧩 技能革命**: 原生支持 **SKILL 目录**(含脚本、模板与资源),并实现与 OpenWebUI **工作区 > Skills** 的深度双向桥接。
|
||||
- **🛡️ 安全沙箱**: 严格的用户/会话级 **工作区隔离** 与持久化配置环境。
|
||||
- **📊 交互交付**: 专业 **文件交付协议**,支持即时预览交互式 HTML Artifacts 与持久化结果下载。
|
||||
- **🛠️ 确定性工具链**: 内置 `manage_skills` 等专业工具,赋予 Agent 完整的技能生命周期管理能力。
|
||||
- **🚀 高性能共享池**:通过单例进程池消除了对话间 1-2 秒的进程冷启动延迟,响应更迅速。
|
||||
- **🔑 纯 BYOK 模式支持**:解除对 `GH_TOKEN` 的强制依赖,仅凭自定义 API Key 即可完整运行。
|
||||
- **📏 RichUI 稳定性修复**:彻底解决高度计算循环导致的页面无限变高问题,交互体验更稳固。
|
||||
- **🩺 智能防挂死探测**:在超时判断中引入 `client.ping()` 探测机制,有效减少复杂任务下的误杀中断。
|
||||
- **📋 Live TODO 小组件**:基于 `session.db` 实时任务状态,现在所有任务完成后将自动隐藏 UI,保持界面整洁。
|
||||
- **🔌 生态深度注入**: 自动读取并复用 OpenWebUI **工具 (Tools)**、**MCP**、**OpenAPI Server** 与 **技能 (Skills)**。
|
||||
- **🛡️ 安全沙箱**: 严格的用户/会话级 **工作区隔离**,并实现用户级环境变量隔离。
|
||||
- **🌐 语言一致性**: 提示词强制要求 Agent 输出语言与用户输入保持一致。
|
||||
|
||||
> [!TIP]
|
||||
> **💡 进阶实战建议**
|
||||
> 强烈推荐在对话中让 Agent 为其安装 [Visual Explainer](https://github.com/nicobailon/visual-explainer) 技能。该技能能显著提升 **HTML Artifacts** 的美观度与交互深度,只需对 AI 说:
|
||||
> “请帮我安装这个技能:<https://github.com/nicobailon/visual-explainer”> 即可瞬间启用。
|
||||
|
||||
#### 📺 演示:可视化技能与数据分析
|
||||
|
||||

|
||||
> *在此演示中,Agent 自动安装可视化增强技能,并根据世界杯表格数据瞬间生成交互式看板。*
|
||||
|
||||

|
||||
> *结合 Excel 专家技能,Agent 可以自动化执行复杂的数据清洗、多维度统计并生成专业的数据看板。*
|
||||
|
||||
#### 🌟 核心实战案例
|
||||
|
||||
- **[GitHub Star 增长预测](./docs/plugins/pipes/star-prediction-example.zh.md)**:自动解析 CSV 数据,编写 Python 分析脚本并生成动态增长看板。
|
||||
@@ -77,6 +87,13 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
|
||||
**挑战 Token 極限。** 采用多专家异步压缩逻辑,在保持高吞吐量推理链的同时,大幅降低 Token 消耗。
|
||||
|
||||
### 6. [Batch Install Plugins from GitHub](https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80) [](https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80)
|
||||
|
||||
**更快试用多个社区插件仓库。** 一次请求即可聚合多个 GitHub 仓库里的插件,再通过交互式对话框里的仓库标签、类型筛选、关键词搜索和描述信息,把要安装的范围缩小到真正需要的子集。
|
||||
|
||||

|
||||
> *一个安装对话框就能合并多个仓库,并在真正安装前先完成可视化筛选。*
|
||||
|
||||
## 📦 项目内容
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
@@ -94,6 +111,12 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
- **Export to Excel** (`export_to_excel`): 将对话内容导出为 Excel 文件。
|
||||
- **Export to Word** (`export_to_docx`): 将对话内容导出为 Word 文档。
|
||||
|
||||
### Tools (工具)
|
||||
|
||||
- **智能思维导图工具** (`smart-mind-map-tool`): 思维导图的 Tool 版本,支持 AI 主动/自主调用。
|
||||
- **OpenWebUI Skills 管理工具** (`openwebui-skills-manager-tool`): 用于管理 OpenWebUI Skills 的原生工具。
|
||||
- **Batch Install Plugins from GitHub** (`batch-install-plugins`): 从多个 GitHub 仓库发现插件,并通过支持仓库/类型筛选的交互式选择对话框完成安装。
|
||||
|
||||
### Filters (消息处理)
|
||||
|
||||
- **GitHub Copilot SDK Files Filter** (`github_copilot_sdk_files_filter`): Copilot SDK 必备搭档。绕过 RAG,确保 Agent 能真正看到你的每一个文件。
|
||||
@@ -105,7 +128,7 @@ OpenWebUI 增强功能集合。包含个人开发与收集的插件、提示词
|
||||
|
||||
### Pipes (模型管道)
|
||||
|
||||
- **GitHub Copilot SDK** (`github-copilot-sdk`): GitHub Copilot SDK 官方集成。支持动态模型、多轮对话、流式输出、图片输入及无限会话。
|
||||
- **GitHub Copilot SDK** (`github-copilot-sdk`): 深度集成 GitHub Copilot SDK 的强大 Agent (v0.12.0)。支持高性能进程池优化、纯 BYOK 模式、智能意图识别、自主网页搜索与上下文压缩。
|
||||
|
||||
### Pipelines (工作流管道)
|
||||
|
||||
@@ -151,4 +174,20 @@ Open WebUI 的前端增强扩展:
|
||||
|
||||
本项目是一个资源集合,无需安装 Python 环境。你只需要下载对应的文件并导入到你的 OpenWebUI 实例中即可。
|
||||
|
||||
### 使用插件
|
||||
|
||||
1. **从官方社区安装(推荐)**:
|
||||
- 访问我的主页:[Fu-Jie 的个人页面](https://openwebui.com/u/Fu-Jie)
|
||||
- 浏览插件并选择你喜欢的
|
||||
- 点击"Get"按钮直接导入到你的 OpenWebUI 实例
|
||||
|
||||
2. **快速安装所有插件**:如果想一次性安装此项目中的所有插件到本地 OpenWebUI 实例,克隆此仓库后运行 `python scripts/install_all_plugins.py`,并在 `.env` 中配置好 API 密钥,详见 [部署指南](./scripts/DEPLOYMENT_GUIDE.md)。
|
||||
|
||||
### 使用提示词
|
||||
|
||||
1. 浏览 `/prompts` 目录并选择一个提示词文件(`.md`)。
|
||||
2. 复制文件内容。
|
||||
3. 在 OpenWebUI 聊天界面中,点击输入框上方的"提示词"按钮。
|
||||
4. 粘贴内容并保存。
|
||||
|
||||
[贡献指南](./CONTRIBUTING_CN.md) | [更新日志](./CHANGELOG.md)
|
||||
|
||||
139
ai-tabs.sh
Executable file
139
ai-tabs.sh
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================
|
||||
# ai-tabs - Ultra Orchestrator
|
||||
# Version: v1.0.0
|
||||
# License: MIT
|
||||
# Author: Fu-Jie
|
||||
# Description: Batch-launches and orchestrates multiple AI CLI tools as Tabs.
|
||||
# ==============================================================================
|
||||
|
||||
# 1. Single-Instance Lock
|
||||
LOCK_FILE="/tmp/ai_terminal_launch.lock"
|
||||
# If lock is less than 10 seconds old, another instance is running. Exit.
|
||||
if [ -f "$LOCK_FILE" ]; then
|
||||
LOCK_TIME=$(stat -f %m "$LOCK_FILE")
|
||||
NOW=$(date +%s)
|
||||
if (( NOW - LOCK_TIME < 10 )); then
|
||||
echo "⚠️ Another launch in progress. Skipping to prevent duplicates."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
touch "$LOCK_FILE"
|
||||
trap 'rm -f "$LOCK_FILE"' EXIT
|
||||
|
||||
# 2. Configuration & Constants
|
||||
INIT_DELAY=4.5
|
||||
PASTE_DELAY=0.3
|
||||
CMD_CREATION_DELAY=0.3
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Search for .env
|
||||
if [ -f "${SCRIPT_DIR}/.env" ]; then
|
||||
ENV_FILE="${SCRIPT_DIR}/.env"
|
||||
elif [ -f "${PARENT_DIR}/.env" ]; then
|
||||
ENV_FILE="${PARENT_DIR}/.env"
|
||||
fi
|
||||
|
||||
# Supported Tools
|
||||
SUPPORTED_TOOLS=(
|
||||
"claude:--continue"
|
||||
"opencode:--continue"
|
||||
"gemini:--resume latest"
|
||||
"copilot:--continue"
|
||||
"iflow:--continue"
|
||||
"kilo:--continue"
|
||||
)
|
||||
|
||||
FOUND_TOOLS_NAMES=()
|
||||
FOUND_CMDS=()
|
||||
|
||||
# 3. Part A: Load Manual Configuration
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
for var in $(compgen -v | grep '^TOOL_[0-9]' | sort -V); do
|
||||
TPATH="${!var}"
|
||||
if [ -x "$TPATH" ]; then
|
||||
NAME=$(basename "$TPATH")
|
||||
FLAG="--continue"
|
||||
for item in "${SUPPORTED_TOOLS[@]}"; do
|
||||
[[ "${item%%:*}" == "$NAME" ]] && FLAG="${item#*:}" && break
|
||||
done
|
||||
FOUND_TOOLS_NAMES+=("$NAME")
|
||||
FOUND_CMDS+=("'$TPATH' $FLAG || '$TPATH' || exec \$SHELL")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 4. Part B: Automatic Tool Discovery
|
||||
for item in "${SUPPORTED_TOOLS[@]}"; do
|
||||
NAME="${item%%:*}"
|
||||
FLAG="${item#*:}"
|
||||
ALREADY_CONFIGURED=false
|
||||
for configured in "${FOUND_TOOLS_NAMES[@]}"; do
|
||||
[[ "$configured" == "$NAME" ]] && ALREADY_CONFIGURED=true && break
|
||||
done
|
||||
[[ "$ALREADY_CONFIGURED" == true ]] && continue
|
||||
TPATH=$(which "$NAME" 2>/dev/null)
|
||||
if [ -z "$TPATH" ]; then
|
||||
SEARCH_PATHS=(
|
||||
"/opt/homebrew/bin/$NAME"
|
||||
"/usr/local/bin/$NAME"
|
||||
"$HOME/.local/bin/$NAME"
|
||||
"$HOME/bin/$NAME"
|
||||
"$HOME/.$NAME/bin/$NAME"
|
||||
"$HOME/.nvm/versions/node/*/bin/$NAME"
|
||||
"$HOME/.npm-global/bin/$NAME"
|
||||
"$HOME/.cargo/bin/$NAME"
|
||||
)
|
||||
for p in "${SEARCH_PATHS[@]}"; do
|
||||
for found_p in $p; do [[ -x "$found_p" ]] && TPATH="$found_p" && break 2; done
|
||||
done
|
||||
fi
|
||||
if [ -n "$TPATH" ]; then
|
||||
FOUND_TOOLS_NAMES+=("$NAME")
|
||||
FOUND_CMDS+=("'$TPATH' $FLAG || '$TPATH' || exec \$SHELL")
|
||||
fi
|
||||
done
|
||||
|
||||
NUM_FOUND=${#FOUND_CMDS[@]}
|
||||
[[ "$NUM_FOUND" -eq 0 ]] && exit 1
|
||||
|
||||
# 5. Core Orchestration (Reset + Launch)
|
||||
# Using Command Palette automation to avoid the need for manual shortcut binding.
|
||||
AS_SCRIPT="tell application \"System Events\"\n"
|
||||
|
||||
# Phase A: Creation (Using Command Palette to ensure it opens in Editor Area)
|
||||
for ((i=1; i<=NUM_FOUND; i++)); do
|
||||
AS_SCRIPT+=" keystroke \"p\" using {command down, shift down}\n"
|
||||
AS_SCRIPT+=" delay 0.1\n"
|
||||
# Ensure we are searching for the command. Using clipboard for speed and universal language support.
|
||||
AS_SCRIPT+=" set the clipboard to \"Terminal: Create New Terminal in Editor Area\"\n"
|
||||
AS_SCRIPT+=" keystroke \"v\" using {command down}\n"
|
||||
AS_SCRIPT+=" delay 0.1\n"
|
||||
AS_SCRIPT+=" keystroke return\n"
|
||||
AS_SCRIPT+=" delay $CMD_CREATION_DELAY\n"
|
||||
done
|
||||
|
||||
# Phase B: Warmup
|
||||
AS_SCRIPT+=" delay $INIT_DELAY\n"
|
||||
|
||||
# Phase C: Command Injection (Reverse)
|
||||
for ((i=NUM_FOUND-1; i>=0; i--)); do
|
||||
FULL_CMD="${FOUND_CMDS[$i]}"
|
||||
CLEAN_CMD=$(echo "$FULL_CMD" | sed 's/"/\\"/g')
|
||||
AS_SCRIPT+=" set the clipboard to \"$CLEAN_CMD\"\n"
|
||||
AS_SCRIPT+=" delay 0.1\n"
|
||||
AS_SCRIPT+=" keystroke \"v\" using {command down}\n"
|
||||
AS_SCRIPT+=" delay $PASTE_DELAY\n"
|
||||
AS_SCRIPT+=" keystroke return\n"
|
||||
if [ $i -gt 0 ]; then
|
||||
AS_SCRIPT+=" delay 0.5\n"
|
||||
AS_SCRIPT+=" keystroke \"[\" using {command down, shift down}\n"
|
||||
fi
|
||||
done
|
||||
AS_SCRIPT+="end tell"
|
||||
|
||||
# Execute
|
||||
echo -e "$AS_SCRIPT" | osascript
|
||||
echo "✨ Ai tabs initialized successfully ($NUM_FOUND tools found)."
|
||||
@@ -1,53 +1,76 @@
|
||||
<!--
|
||||
NOTE: This template is for the English version (README.md).
|
||||
The Chinese version (README_CN.md) MUST be translated based on this English version to ensure consistency in structure and content.
|
||||
The Chinese version (README_CN.md) MUST be translated from this file so both versions keep the same structure and installation guidance.
|
||||
-->
|
||||
# [Plugin Name] [Optional Emoji]
|
||||
# [Plugin Name]
|
||||
|
||||
[Brief description of what the plugin does. Keep it concise and engaging.]
|
||||
[One-sentence summary of what the plugin does and why it is useful.]
|
||||
|
||||
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 1.0.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
|
||||
| By [Fu-Jie](https://github.com/Fu-Jie) · v1.0.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
|
||||
| :--- | ---: |
|
||||
|
||||
|  |  |  |  |  |  |  |
|
||||
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||
|
||||
## Preview
|
||||
|
||||
<!-- Add a screenshot or description here -->
|
||||
<!-- If you have a screenshot, add it as:  -->
|
||||
<!-- If you do not have a screenshot yet, replace with one short sentence explaining what users will see. -->
|
||||
|
||||
## Install with Batch Install Plugins
|
||||
|
||||
If you already use [Batch Install Plugins from GitHub](https://github.com/Fu-Jie/openwebui-extensions/tree/main/plugins/tools/batch-install-plugins), you can install or update this plugin with:
|
||||
|
||||
```text
|
||||
Install plugin from Fu-Jie/openwebui-extensions
|
||||
```
|
||||
|
||||
When the selection dialog opens, search for this plugin, check it, and continue.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If the official OpenWebUI Community version is already installed, remove it first. After that, Batch Install Plugins can keep this plugin updated in future runs.
|
||||
|
||||
## What's New
|
||||
|
||||
<!-- Keep only the latest update here. Remove this section for the initial release. -->
|
||||
<!-- Keep only the latest 1-3 versions here. Remove this section for the initial release. -->
|
||||
|
||||
### v1.0.0
|
||||
|
||||
- **Initial Release**: Released the first version of the plugin.
|
||||
- **[Feature Name]**: [Brief description of the feature].
|
||||
|
||||
## Key Features 🔑
|
||||
## Key Features
|
||||
|
||||
- **[Feature 1]**: [Description of feature 1].
|
||||
- **[Feature 2]**: [Description of feature 2].
|
||||
- **[Feature 3]**: [Description of feature 3].
|
||||
|
||||
## How to Use 🛠️
|
||||
## How to Use
|
||||
|
||||
1. **Install**: Add the plugin to your OpenWebUI instance.
|
||||
2. **Configure**: Adjust settings in the Valves menu (optional).
|
||||
3. **[Action Step]**: Describe how to trigger or use the plugin.
|
||||
4. **[Result Step]**: Describe the expected outcome.
|
||||
1. **Install**: Add the plugin to your OpenWebUI instance from the marketplace, or use the Batch Install prompt above.
|
||||
2. **Configure**: Adjust settings in the Valves menu if needed.
|
||||
3. **Use**: Describe how to trigger or run the plugin.
|
||||
4. **Result**: Describe what users should expect to see.
|
||||
|
||||
## Configuration (Valves) ⚙️
|
||||
## Configuration (Valves)
|
||||
|
||||
| Valve | Default | Description |
|
||||
|-------|---------|-------------|
|
||||
| --- | --- | --- |
|
||||
| `VALVE_NAME` | `Default Value` | Description of what this setting does. |
|
||||
| `ANOTHER_VALVE` | `True` | Another setting description. |
|
||||
|
||||
## ⭐ Support
|
||||
## Troubleshooting
|
||||
|
||||
- **Plugin not working?**: Check if the filter, action, pipe, or tool is enabled in the relevant OpenWebUI settings.
|
||||
- **Debug Logs**: Enable the debug valve if available and check the browser console (F12) or backend logs.
|
||||
- **Official version conflict**: If installation fails because the same plugin already exists from the official marketplace, remove the old version first and try again.
|
||||
- **Submit an Issue**: If the problem continues, report it here: [OpenWebUI Extensions Issues](https://github.com/Fu-Jie/openwebui-extensions/issues)
|
||||
|
||||
## 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.
|
||||
|
||||
## Troubleshooting ❓
|
||||
|
||||
- **Plugin not working?**: Check if the filter/action is enabled in the model settings.
|
||||
- **Debug Logs**: Enable `SHOW_DEBUG_LOG` in Valves and check the browser console (F12) for detailed logs.
|
||||
- **Error Messages**: If you see an error, please copy the full error message and report it.
|
||||
- **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
|
||||
|
||||
See the full history on GitHub: [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)
|
||||
|
||||
BIN
docs/assets/images/development/worldcup_enhanced_charts.png
Normal file
BIN
docs/assets/images/development/worldcup_enhanced_charts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 818 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 MiB After Width: | Height: | Size: 10 MiB |
6
docs/badges/contributions.json
Normal file
6
docs/badges/contributions.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "contributions",
|
||||
"message": "21",
|
||||
"color": "green"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "downloads",
|
||||
"message": "6.4k",
|
||||
"message": "10.2k",
|
||||
"color": "blue",
|
||||
"namedLogo": "openwebui"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "followers",
|
||||
"message": "295",
|
||||
"message": "396",
|
||||
"color": "blue"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "plugins",
|
||||
"message": "25",
|
||||
"message": "28",
|
||||
"color": "green"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "points",
|
||||
"message": "299",
|
||||
"message": "398",
|
||||
"color": "orange"
|
||||
}
|
||||
6
docs/badges/saves.json
Normal file
6
docs/badges/saves.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "saves",
|
||||
"message": "449",
|
||||
"color": "lightgrey"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "upvotes",
|
||||
"message": "254",
|
||||
"message": "340",
|
||||
"color": "brightgreen"
|
||||
}
|
||||
6
docs/badges/views.json
Normal file
6
docs/badges/views.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "views",
|
||||
"message": "109.4k",
|
||||
"color": "blueviolet"
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"total_posts": 25,
|
||||
"total_downloads": 6379,
|
||||
"total_views": 67827,
|
||||
"total_upvotes": 254,
|
||||
"total_downvotes": 3,
|
||||
"total_saves": 337,
|
||||
"total_comments": 58,
|
||||
"total_posts": 28,
|
||||
"total_downloads": 10214,
|
||||
"total_views": 109390,
|
||||
"total_upvotes": 340,
|
||||
"total_downvotes": 16,
|
||||
"total_saves": 449,
|
||||
"total_comments": 84,
|
||||
"plugin_contributions": 21,
|
||||
"by_type": {
|
||||
"post": 6,
|
||||
"pipe": 1,
|
||||
"tool": 3,
|
||||
"action": 12,
|
||||
"filter": 4,
|
||||
"prompt": 1,
|
||||
"review": 1
|
||||
"prompt": 1
|
||||
},
|
||||
"posts": [
|
||||
{
|
||||
@@ -22,13 +22,14 @@
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
|
||||
"downloads": 1328,
|
||||
"views": 11410,
|
||||
"upvotes": 23,
|
||||
"saves": 59,
|
||||
"comments": 15,
|
||||
"downloads": 1969,
|
||||
"views": 17206,
|
||||
"upvotes": 34,
|
||||
"saves": 79,
|
||||
"comments": 23,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-02-27",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a"
|
||||
},
|
||||
{
|
||||
@@ -38,31 +39,50 @@
|
||||
"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": 1076,
|
||||
"views": 10746,
|
||||
"upvotes": 25,
|
||||
"saves": 40,
|
||||
"comments": 10,
|
||||
"downloads": 1470,
|
||||
"views": 14788,
|
||||
"upvotes": 29,
|
||||
"saves": 58,
|
||||
"comments": 12,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/smart_infographic_ad6f0c7f"
|
||||
},
|
||||
{
|
||||
"title": "Markdown Normalizer",
|
||||
"slug": "markdown_normalizer_baaa8732",
|
||||
"type": "filter",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"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. Including LaTeX command protection.",
|
||||
"downloads": 609,
|
||||
"views": 6795,
|
||||
"upvotes": 18,
|
||||
"saves": 37,
|
||||
"comments": 5,
|
||||
"downloads": 928,
|
||||
"views": 9494,
|
||||
"upvotes": 25,
|
||||
"saves": 52,
|
||||
"comments": 6,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-12",
|
||||
"updated_at": "2026-02-27",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/markdown_normalizer_baaa8732"
|
||||
},
|
||||
{
|
||||
"title": "Async Context Compression",
|
||||
"slug": "async_context_compression_b1655bc8",
|
||||
"type": "filter",
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Reduces token consumption in long conversations while maintaining coherence through intelligent summarization and message compression.",
|
||||
"downloads": 889,
|
||||
"views": 8096,
|
||||
"upvotes": 21,
|
||||
"saves": 56,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/async_context_compression_b1655bc8"
|
||||
},
|
||||
{
|
||||
"title": "Export to Word Enhanced",
|
||||
"slug": "export_to_word_enhanced_formatting_fca6a315",
|
||||
@@ -70,47 +90,16 @@
|
||||
"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": 578,
|
||||
"views": 4611,
|
||||
"upvotes": 16,
|
||||
"saves": 30,
|
||||
"downloads": 880,
|
||||
"views": 6908,
|
||||
"upvotes": 21,
|
||||
"saves": 42,
|
||||
"comments": 5,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-03",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-03-16",
|
||||
"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",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Reduces token consumption in long conversations while maintaining coherence through intelligent summarization and message compression.",
|
||||
"downloads": 559,
|
||||
"views": 5452,
|
||||
"upvotes": 15,
|
||||
"saves": 41,
|
||||
"comments": 0,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-02-21",
|
||||
"url": "https://openwebui.com/posts/async_context_compression_b1655bc8"
|
||||
},
|
||||
{
|
||||
"title": "Export to Excel",
|
||||
"slug": "export_mulit_table_to_excel_244b8f9d",
|
||||
"type": "action",
|
||||
"version": "0.3.7",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Extracts tables from chat messages and exports them to Excel (.xlsx) files with smart formatting.",
|
||||
"downloads": 492,
|
||||
"views": 2693,
|
||||
"upvotes": 10,
|
||||
"saves": 8,
|
||||
"comments": 0,
|
||||
"created_at": "2025-05-30",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d"
|
||||
},
|
||||
{
|
||||
"title": "AI Task Instruction Generator",
|
||||
"slug": "ai_task_instruction_generator_9bab8b37",
|
||||
@@ -118,15 +107,67 @@
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 473,
|
||||
"views": 5498,
|
||||
"upvotes": 9,
|
||||
"saves": 14,
|
||||
"downloads": 805,
|
||||
"views": 8931,
|
||||
"upvotes": 11,
|
||||
"saves": 26,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-28",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37"
|
||||
},
|
||||
{
|
||||
"title": "Export to Excel",
|
||||
"slug": "export_mulit_table_to_excel_244b8f9d",
|
||||
"type": "action",
|
||||
"version": "0.3.7",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Extracts tables from chat messages and exports them to Excel (.xlsx) files with smart formatting.",
|
||||
"downloads": 657,
|
||||
"views": 3933,
|
||||
"upvotes": 13,
|
||||
"saves": 13,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-05-30",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d"
|
||||
},
|
||||
{
|
||||
"title": "OpenWebUI Skills Manager Tool",
|
||||
"slug": "openwebui_skills_manager_tool_b4bce8e4",
|
||||
"type": "tool",
|
||||
"version": "0.3.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Standalone OpenWebUI tool for managing native Workspace Skills (list/show/install/create/update/delete) for any model.",
|
||||
"downloads": 609,
|
||||
"views": 7411,
|
||||
"upvotes": 9,
|
||||
"saves": 27,
|
||||
"comments": 4,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-02-28",
|
||||
"updated_at": "2026-03-19",
|
||||
"url": "https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot Official SDK Pipe",
|
||||
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
|
||||
"type": "pipe",
|
||||
"version": "0.11.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "A powerful Agent SDK integration for OpenWebUI. It deeply bridges GitHub Copilot SDK with OpenWebUI's ecosystem, enabling the Agent to autonomously perform intent recognition, web search, and context compaction. It seamlessly reuses your existing Tools, MCP servers, OpenAPI servers, and Skills for a professional, full-featured experience.",
|
||||
"downloads": 432,
|
||||
"views": 6212,
|
||||
"upvotes": 17,
|
||||
"saves": 12,
|
||||
"comments": 8,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-03-19",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
},
|
||||
{
|
||||
"title": "Flash Card",
|
||||
"slug": "flash_card_65a2ea8f",
|
||||
@@ -134,31 +175,16 @@
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Quickly generates beautiful flashcards from text, extracting key points and categories.",
|
||||
"downloads": 285,
|
||||
"views": 4128,
|
||||
"downloads": 353,
|
||||
"views": 5014,
|
||||
"upvotes": 13,
|
||||
"saves": 18,
|
||||
"saves": 23,
|
||||
"comments": 2,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-03-16",
|
||||
"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.9.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Integrate GitHub Copilot SDK. Supports dynamic models, multi-turn conversation, streaming, multimodal input, infinite sessions, bidirectional OpenWebUI Skills bridge, and manage_skills tool.",
|
||||
"downloads": 263,
|
||||
"views": 4106,
|
||||
"upvotes": 14,
|
||||
"saves": 10,
|
||||
"comments": 6,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-02-27",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
},
|
||||
{
|
||||
"title": "Deep Dive",
|
||||
"slug": "deep_dive_c0b846e4",
|
||||
@@ -166,15 +192,33 @@
|
||||
"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": 204,
|
||||
"views": 1631,
|
||||
"upvotes": 6,
|
||||
"saves": 13,
|
||||
"downloads": 252,
|
||||
"views": 2068,
|
||||
"upvotes": 7,
|
||||
"saves": 16,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-08",
|
||||
"updated_at": "2026-01-08",
|
||||
"url": "https://openwebui.com/posts/deep_dive_c0b846e4"
|
||||
},
|
||||
{
|
||||
"title": "🧠 Smart Mind Map Tool: Auto-Generate Interactive Knowledge Graphs",
|
||||
"slug": "smart_mind_map_tool_auto_generate_interactive_know_d25f4e3d",
|
||||
"type": "tool",
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
|
||||
"downloads": 184,
|
||||
"views": 3021,
|
||||
"upvotes": 7,
|
||||
"saves": 8,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-03-04",
|
||||
"updated_at": "2026-03-05",
|
||||
"url": "https://openwebui.com/posts/smart_mind_map_tool_auto_generate_interactive_know_d25f4e3d"
|
||||
},
|
||||
{
|
||||
"title": "导出为Word增强版",
|
||||
"slug": "导出为_word_支持公式流程图表格和代码块_8a6306c0",
|
||||
@@ -182,13 +226,14 @@
|
||||
"version": "0.4.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "将对话导出为 Word (.docx),支持 Mermaid 图表 (客户端渲染 SVG+PNG)、LaTeX 数学公式、真实超链接、增强表格格式、代码高亮和引用块。",
|
||||
"downloads": 153,
|
||||
"views": 2631,
|
||||
"downloads": 178,
|
||||
"views": 3197,
|
||||
"upvotes": 14,
|
||||
"saves": 7,
|
||||
"comments": 4,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-04",
|
||||
"updated_at": "2026-02-13",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0"
|
||||
},
|
||||
{
|
||||
@@ -198,30 +243,32 @@
|
||||
"version": "0.1.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Automatically extracts project rules from conversations and injects them into the folder's system prompt.",
|
||||
"downloads": 99,
|
||||
"views": 1839,
|
||||
"downloads": 139,
|
||||
"views": 2301,
|
||||
"upvotes": 7,
|
||||
"saves": 11,
|
||||
"saves": 14,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-20",
|
||||
"updated_at": "2026-01-20",
|
||||
"url": "https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2"
|
||||
},
|
||||
{
|
||||
"title": "智能信息图",
|
||||
"slug": "智能信息图_e04a48ff",
|
||||
"type": "action",
|
||||
"version": "1.5.0",
|
||||
"title": "Batch Install Plugins from GitHub",
|
||||
"slug": "batch_install_plugins_install_popular_plugins_in_s_c9fd6e80",
|
||||
"type": "tool",
|
||||
"version": "1.1.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "基于 AntV Infographic 的智能信息图生成插件。支持多种专业模板,自动图标匹配,并提供 SVG/PNG 下载功能。",
|
||||
"downloads": 65,
|
||||
"views": 1304,
|
||||
"upvotes": 10,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/智能信息图_e04a48ff"
|
||||
"description": "One-click batch install plugins from one or more GitHub repositories to your OpenWebUI instance. If a user mentions multiple repositories in one request, combine them into a single tool call.",
|
||||
"downloads": 120,
|
||||
"views": 3066,
|
||||
"upvotes": 9,
|
||||
"saves": 5,
|
||||
"comments": 6,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-03-15",
|
||||
"updated_at": "2026-03-19",
|
||||
"url": "https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot SDK Files Filter",
|
||||
@@ -230,15 +277,33 @@
|
||||
"version": "0.1.3",
|
||||
"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": 54,
|
||||
"views": 2098,
|
||||
"upvotes": 3,
|
||||
"downloads": 97,
|
||||
"views": 2541,
|
||||
"upvotes": 5,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-02-09",
|
||||
"updated_at": "2026-02-25",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee"
|
||||
},
|
||||
{
|
||||
"title": "智能信息图",
|
||||
"slug": "智能信息图_e04a48ff",
|
||||
"type": "action",
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "基于 AntV Infographic 的智能信息图生成插件。支持多种专业模板,自动图标匹配,并提供 SVG/PNG 下载功能。",
|
||||
"downloads": 73,
|
||||
"views": 1673,
|
||||
"upvotes": 10,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/智能信息图_e04a48ff"
|
||||
},
|
||||
{
|
||||
"title": "思维导图",
|
||||
"slug": "智能生成交互式思维导图帮助用户可视化知识_8d4b097b",
|
||||
@@ -246,11 +311,12 @@
|
||||
"version": "0.9.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "智能分析文本内容,生成交互式思维导图,帮助用户结构化和可视化知识。",
|
||||
"downloads": 45,
|
||||
"views": 691,
|
||||
"downloads": 57,
|
||||
"views": 858,
|
||||
"upvotes": 6,
|
||||
"saves": 2,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-31",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b"
|
||||
@@ -262,31 +328,16 @@
|
||||
"version": "1.2.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "通过智能摘要和消息压缩,降低长对话的 token 消耗,同时保持对话连贯性。",
|
||||
"downloads": 38,
|
||||
"views": 783,
|
||||
"downloads": 48,
|
||||
"views": 944,
|
||||
"upvotes": 7,
|
||||
"saves": 5,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/异步上下文压缩_5c0617cb"
|
||||
},
|
||||
{
|
||||
"title": "闪记卡 (Flash Card)",
|
||||
"slug": "闪记卡生成插件_4a31eac3",
|
||||
"type": "action",
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "快速将文本提炼为精美的学习记忆卡片,支持核心要点提取与分类。",
|
||||
"downloads": 32,
|
||||
"views": 830,
|
||||
"upvotes": 7,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/闪记卡生成插件_4a31eac3"
|
||||
},
|
||||
{
|
||||
"title": "精读",
|
||||
"slug": "精读_99830b0f",
|
||||
@@ -294,75 +345,97 @@
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "全方位的思维透镜 —— 从背景全景到逻辑脉络,从深度洞察到行动路径。",
|
||||
"downloads": 26,
|
||||
"views": 581,
|
||||
"downloads": 38,
|
||||
"views": 736,
|
||||
"upvotes": 5,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-08",
|
||||
"updated_at": "2026-01-08",
|
||||
"url": "https://openwebui.com/posts/精读_99830b0f"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.9.0: Copilot SDK Skills Core Capabilities & Extended Delivery",
|
||||
"slug": "github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452",
|
||||
"type": "post",
|
||||
"title": "闪记卡 (Flash Card)",
|
||||
"slug": "闪记卡生成插件_4a31eac3",
|
||||
"type": "action",
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "快速将文本提炼为精美的学习记忆卡片,支持核心要点提取与分类。",
|
||||
"downloads": 36,
|
||||
"views": 992,
|
||||
"upvotes": 7,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/闪记卡生成插件_4a31eac3"
|
||||
},
|
||||
{
|
||||
"title": "An Unconventional Use of Open Terminal ⚡",
|
||||
"slug": "an_unconventional_use_of_open_terminal_35498f8f",
|
||||
"type": "action",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 7,
|
||||
"upvotes": 0,
|
||||
"saves": 0,
|
||||
"views": 3710,
|
||||
"upvotes": 8,
|
||||
"saves": 1,
|
||||
"comments": 2,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-03-06",
|
||||
"updated_at": "2026-03-07",
|
||||
"url": "https://openwebui.com/posts/an_unconventional_use_of_open_terminal_35498f8f"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.9.0: Skills & RichUI",
|
||||
"slug": "github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452",
|
||||
"type": "pipe",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1883,
|
||||
"upvotes": 6,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-02-27",
|
||||
"updated_at": "2026-02-27",
|
||||
"updated_at": "2026-02-28",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.8.0: Conditional Tool Filtering & Publish Reliability 🎛️",
|
||||
"slug": "github_copilot_sdk_pipe_v080_conditional_tool_filt_a5a3322d",
|
||||
"type": "post",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1059,
|
||||
"upvotes": 2,
|
||||
"saves": 2,
|
||||
"comments": 0,
|
||||
"created_at": "2026-02-25",
|
||||
"updated_at": "2026-02-25",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_pipe_v080_conditional_tool_filt_a5a3322d"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.7.0: Native Tool UI & Zero-Config CLI 🛠️",
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.7.0: Skills & Rich UI 🛠️",
|
||||
"slug": "github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131",
|
||||
"type": "post",
|
||||
"type": "pipe",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 2162,
|
||||
"upvotes": 7,
|
||||
"saves": 2,
|
||||
"views": 2871,
|
||||
"upvotes": 9,
|
||||
"saves": 4,
|
||||
"comments": 1,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-02-22",
|
||||
"updated_at": "2026-02-22",
|
||||
"updated_at": "2026-02-28",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks",
|
||||
"slug": "github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293",
|
||||
"type": "post",
|
||||
"type": "pipe",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 2257,
|
||||
"views": 2465,
|
||||
"upvotes": 7,
|
||||
"saves": 4,
|
||||
"saves": 5,
|
||||
"comments": 0,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-02-10",
|
||||
"updated_at": "2026-02-10",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293"
|
||||
@@ -370,15 +443,16 @@
|
||||
{
|
||||
"title": "🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager",
|
||||
"slug": "open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e",
|
||||
"type": "post",
|
||||
"type": "action",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1839,
|
||||
"upvotes": 12,
|
||||
"saves": 19,
|
||||
"comments": 8,
|
||||
"views": 2108,
|
||||
"upvotes": 15,
|
||||
"saves": 24,
|
||||
"comments": 9,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-01-25",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e"
|
||||
@@ -391,10 +465,11 @@
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 234,
|
||||
"views": 276,
|
||||
"upvotes": 2,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-01-14",
|
||||
"updated_at": "2026-01-14",
|
||||
"url": "https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39"
|
||||
@@ -402,15 +477,16 @@
|
||||
{
|
||||
"title": " 🛠️ Debug Open WebUI Plugins in Your Browser",
|
||||
"slug": "debug_open_webui_plugins_in_your_browser_81bf7960",
|
||||
"type": "post",
|
||||
"type": "action",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1502,
|
||||
"views": 1614,
|
||||
"upvotes": 16,
|
||||
"saves": 11,
|
||||
"saves": 13,
|
||||
"comments": 2,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-01-10",
|
||||
"updated_at": "2026-01-10",
|
||||
"url": "https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960"
|
||||
@@ -421,11 +497,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": 295,
|
||||
"following": 6,
|
||||
"total_points": 299,
|
||||
"post_points": 251,
|
||||
"comment_points": 48,
|
||||
"contributions": 54
|
||||
"followers": 396,
|
||||
"following": 8,
|
||||
"total_points": 398,
|
||||
"post_points": 327,
|
||||
"comment_points": 71,
|
||||
"contributions": 79
|
||||
}
|
||||
}
|
||||
507
docs/community-stats.json.old
Normal file
507
docs/community-stats.json.old
Normal file
@@ -0,0 +1,507 @@
|
||||
{
|
||||
"total_posts": 28,
|
||||
"total_downloads": 9491,
|
||||
"total_views": 99759,
|
||||
"total_upvotes": 315,
|
||||
"total_downvotes": 4,
|
||||
"total_saves": 428,
|
||||
"total_comments": 79,
|
||||
"plugin_contributions": 21,
|
||||
"by_type": {
|
||||
"action": 13,
|
||||
"tool": 2,
|
||||
"pipe": 1,
|
||||
"filter": 4,
|
||||
"prompt": 1
|
||||
},
|
||||
"posts": [
|
||||
{
|
||||
"title": "Smart Mind Map",
|
||||
"slug": "turn_any_text_into_beautiful_mind_maps_3094c59a",
|
||||
"type": "action",
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
|
||||
"downloads": 1852,
|
||||
"views": 15897,
|
||||
"upvotes": 32,
|
||||
"saves": 77,
|
||||
"comments": 23,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a"
|
||||
},
|
||||
{
|
||||
"title": "Smart Infographic",
|
||||
"slug": "smart_infographic_ad6f0c7f",
|
||||
"type": "action",
|
||||
"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": 1392,
|
||||
"views": 13891,
|
||||
"upvotes": 28,
|
||||
"saves": 54,
|
||||
"comments": 12,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/smart_infographic_ad6f0c7f"
|
||||
},
|
||||
{
|
||||
"title": "Markdown Normalizer",
|
||||
"slug": "markdown_normalizer_baaa8732",
|
||||
"type": "filter",
|
||||
"version": "1.2.8",
|
||||
"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. Including LaTeX command protection.",
|
||||
"downloads": 871,
|
||||
"views": 8976,
|
||||
"upvotes": 21,
|
||||
"saves": 47,
|
||||
"comments": 5,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-12",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/markdown_normalizer_baaa8732"
|
||||
},
|
||||
{
|
||||
"title": "Async Context Compression",
|
||||
"slug": "async_context_compression_b1655bc8",
|
||||
"type": "filter",
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Reduces token consumption in long conversations while maintaining coherence through intelligent summarization and message compression.",
|
||||
"downloads": 842,
|
||||
"views": 7568,
|
||||
"upvotes": 18,
|
||||
"saves": 55,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/async_context_compression_b1655bc8"
|
||||
},
|
||||
{
|
||||
"title": "Export to Word Enhanced",
|
||||
"slug": "export_to_word_enhanced_formatting_fca6a315",
|
||||
"type": "action",
|
||||
"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": 822,
|
||||
"views": 6340,
|
||||
"upvotes": 21,
|
||||
"saves": 42,
|
||||
"comments": 5,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-03",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315"
|
||||
},
|
||||
{
|
||||
"title": "AI Task Instruction Generator",
|
||||
"slug": "ai_task_instruction_generator_9bab8b37",
|
||||
"type": "prompt",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 740,
|
||||
"views": 8152,
|
||||
"upvotes": 10,
|
||||
"saves": 23,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-28",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37"
|
||||
},
|
||||
{
|
||||
"title": "Export to Excel",
|
||||
"slug": "export_mulit_table_to_excel_244b8f9d",
|
||||
"type": "action",
|
||||
"version": "0.3.7",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Extracts tables from chat messages and exports them to Excel (.xlsx) files with smart formatting.",
|
||||
"downloads": 626,
|
||||
"views": 3609,
|
||||
"upvotes": 12,
|
||||
"saves": 13,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-05-30",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d"
|
||||
},
|
||||
{
|
||||
"title": "OpenWebUI Skills Manager Tool",
|
||||
"slug": "openwebui_skills_manager_tool_b4bce8e4",
|
||||
"type": "tool",
|
||||
"version": "0.3.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Standalone OpenWebUI tool for managing native Workspace Skills (list/show/install/create/update/delete) for any model.",
|
||||
"downloads": 543,
|
||||
"views": 6549,
|
||||
"upvotes": 8,
|
||||
"saves": 27,
|
||||
"comments": 4,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-02-28",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot Official SDK Pipe",
|
||||
"slug": "github_copilot_official_sdk_pipe_ce96f7b4",
|
||||
"type": "pipe",
|
||||
"version": "0.10.1",
|
||||
"author": "Fu-Jie",
|
||||
"description": "A powerful Agent SDK integration for OpenWebUI. It deeply bridges GitHub Copilot SDK with OpenWebUI's ecosystem, enabling the Agent to autonomously perform intent recognition, web search, and context compaction. It seamlessly reuses your existing Tools, MCP servers, OpenAPI servers, and Skills for a professional, full-featured experience.",
|
||||
"downloads": 410,
|
||||
"views": 5867,
|
||||
"upvotes": 16,
|
||||
"saves": 12,
|
||||
"comments": 8,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-26",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4"
|
||||
},
|
||||
{
|
||||
"title": "Flash Card",
|
||||
"slug": "flash_card_65a2ea8f",
|
||||
"type": "action",
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Quickly generates beautiful flashcards from text, extracting key points and categories.",
|
||||
"downloads": 340,
|
||||
"views": 4824,
|
||||
"upvotes": 13,
|
||||
"saves": 23,
|
||||
"comments": 2,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/flash_card_65a2ea8f"
|
||||
},
|
||||
{
|
||||
"title": "Deep Dive",
|
||||
"slug": "deep_dive_c0b846e4",
|
||||
"type": "action",
|
||||
"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": 240,
|
||||
"views": 1943,
|
||||
"upvotes": 7,
|
||||
"saves": 15,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-08",
|
||||
"updated_at": "2026-01-08",
|
||||
"url": "https://openwebui.com/posts/deep_dive_c0b846e4"
|
||||
},
|
||||
{
|
||||
"title": "导出为Word增强版",
|
||||
"slug": "导出为_word_支持公式流程图表格和代码块_8a6306c0",
|
||||
"type": "action",
|
||||
"version": "0.4.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "将对话导出为 Word (.docx),支持 Mermaid 图表 (客户端渲染 SVG+PNG)、LaTeX 数学公式、真实超链接、增强表格格式、代码高亮和引用块。",
|
||||
"downloads": 173,
|
||||
"views": 3088,
|
||||
"upvotes": 14,
|
||||
"saves": 7,
|
||||
"comments": 4,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-04",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0"
|
||||
},
|
||||
{
|
||||
"title": "🧠 Smart Mind Map Tool: Auto-Generate Interactive Knowledge Graphs",
|
||||
"slug": "smart_mind_map_tool_auto_generate_interactive_know_d25f4e3d",
|
||||
"type": "tool",
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Intelligently analyzes text content and generates interactive mind maps to help users structure and visualize knowledge.",
|
||||
"downloads": 141,
|
||||
"views": 2607,
|
||||
"upvotes": 6,
|
||||
"saves": 6,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-03-04",
|
||||
"updated_at": "2026-03-05",
|
||||
"url": "https://openwebui.com/posts/smart_mind_map_tool_auto_generate_interactive_know_d25f4e3d"
|
||||
},
|
||||
{
|
||||
"title": "📂 Folder Memory – Auto-Evolving Project Context",
|
||||
"slug": "folder_memory_auto_evolving_project_context_4a9875b2",
|
||||
"type": "filter",
|
||||
"version": "0.1.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "Automatically extracts project rules from conversations and injects them into the folder's system prompt.",
|
||||
"downloads": 133,
|
||||
"views": 2215,
|
||||
"upvotes": 7,
|
||||
"saves": 13,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-20",
|
||||
"updated_at": "2026-01-20",
|
||||
"url": "https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2"
|
||||
},
|
||||
{
|
||||
"title": "GitHub Copilot SDK Files Filter",
|
||||
"slug": "github_copilot_sdk_files_filter_403a62ee",
|
||||
"type": "filter",
|
||||
"version": "0.1.3",
|
||||
"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": 96,
|
||||
"views": 2505,
|
||||
"upvotes": 4,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-02-09",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee"
|
||||
},
|
||||
{
|
||||
"title": "智能信息图",
|
||||
"slug": "智能信息图_e04a48ff",
|
||||
"type": "action",
|
||||
"version": "1.5.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "基于 AntV Infographic 的智能信息图生成插件。支持多种专业模板,自动图标匹配,并提供 SVG/PNG 下载功能。",
|
||||
"downloads": 72,
|
||||
"views": 1605,
|
||||
"upvotes": 10,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-28",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/智能信息图_e04a48ff"
|
||||
},
|
||||
{
|
||||
"title": "思维导图",
|
||||
"slug": "智能生成交互式思维导图帮助用户可视化知识_8d4b097b",
|
||||
"type": "action",
|
||||
"version": "0.9.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "智能分析文本内容,生成交互式思维导图,帮助用户结构化和可视化知识。",
|
||||
"downloads": 57,
|
||||
"views": 835,
|
||||
"upvotes": 6,
|
||||
"saves": 2,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-31",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b"
|
||||
},
|
||||
{
|
||||
"title": "异步上下文压缩",
|
||||
"slug": "异步上下文压缩_5c0617cb",
|
||||
"type": "action",
|
||||
"version": "1.2.2",
|
||||
"author": "Fu-Jie",
|
||||
"description": "通过智能摘要和消息压缩,降低长对话的 token 消耗,同时保持对话连贯性。",
|
||||
"downloads": 44,
|
||||
"views": 918,
|
||||
"upvotes": 7,
|
||||
"saves": 5,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-11-08",
|
||||
"updated_at": "2026-02-13",
|
||||
"url": "https://openwebui.com/posts/异步上下文压缩_5c0617cb"
|
||||
},
|
||||
{
|
||||
"title": "精读",
|
||||
"slug": "精读_99830b0f",
|
||||
"type": "action",
|
||||
"version": "1.0.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "全方位的思维透镜 —— 从背景全景到逻辑脉络,从深度洞察到行动路径。",
|
||||
"downloads": 38,
|
||||
"views": 724,
|
||||
"upvotes": 5,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-01-08",
|
||||
"updated_at": "2026-01-08",
|
||||
"url": "https://openwebui.com/posts/精读_99830b0f"
|
||||
},
|
||||
{
|
||||
"title": "闪记卡 (Flash Card)",
|
||||
"slug": "闪记卡生成插件_4a31eac3",
|
||||
"type": "action",
|
||||
"version": "0.2.4",
|
||||
"author": "Fu-Jie",
|
||||
"description": "快速将文本提炼为精美的学习记忆卡片,支持核心要点提取与分类。",
|
||||
"downloads": 34,
|
||||
"views": 949,
|
||||
"upvotes": 7,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2025-12-30",
|
||||
"updated_at": "2026-03-15",
|
||||
"url": "https://openwebui.com/posts/闪记卡生成插件_4a31eac3"
|
||||
},
|
||||
{
|
||||
"title": "Batch Install Plugins from GitHub",
|
||||
"slug": "batch_install_plugins_install_popular_plugins_in_s_c9fd6e80",
|
||||
"type": "action",
|
||||
"version": "1.1.0",
|
||||
"author": "Fu-Jie",
|
||||
"description": "One-click batch install plugins from GitHub repositories to your OpenWebUI instance.",
|
||||
"downloads": 25,
|
||||
"views": 697,
|
||||
"upvotes": 4,
|
||||
"saves": 3,
|
||||
"comments": 2,
|
||||
"is_published_plugin": true,
|
||||
"created_at": "2026-03-15",
|
||||
"updated_at": "2026-03-16",
|
||||
"url": "https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80"
|
||||
},
|
||||
{
|
||||
"title": "An Unconventional Use of Open Terminal ⚡",
|
||||
"slug": "an_unconventional_use_of_open_terminal_35498f8f",
|
||||
"type": "action",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 3490,
|
||||
"upvotes": 7,
|
||||
"saves": 1,
|
||||
"comments": 2,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-03-06",
|
||||
"updated_at": "2026-03-07",
|
||||
"url": "https://openwebui.com/posts/an_unconventional_use_of_open_terminal_35498f8f"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.9.0: Skills & RichUI",
|
||||
"slug": "github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452",
|
||||
"type": "pipe",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1850,
|
||||
"upvotes": 5,
|
||||
"saves": 1,
|
||||
"comments": 0,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-02-27",
|
||||
"updated_at": "2026-02-28",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe v0.7.0: Skills & Rich UI 🛠️",
|
||||
"slug": "github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131",
|
||||
"type": "pipe",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 2827,
|
||||
"upvotes": 8,
|
||||
"saves": 4,
|
||||
"comments": 1,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-02-22",
|
||||
"updated_at": "2026-02-28",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131"
|
||||
},
|
||||
{
|
||||
"title": "🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks",
|
||||
"slug": "github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293",
|
||||
"type": "pipe",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 2454,
|
||||
"upvotes": 7,
|
||||
"saves": 5,
|
||||
"comments": 0,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-02-10",
|
||||
"updated_at": "2026-02-10",
|
||||
"url": "https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293"
|
||||
},
|
||||
{
|
||||
"title": "🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager",
|
||||
"slug": "open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e",
|
||||
"type": "action",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 2042,
|
||||
"upvotes": 14,
|
||||
"saves": 24,
|
||||
"comments": 9,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-01-25",
|
||||
"updated_at": "2026-01-28",
|
||||
"url": "https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e"
|
||||
},
|
||||
{
|
||||
"title": "Review of Claude Haiku 4.5",
|
||||
"slug": "review_of_claude_haiku_45_41b0db39",
|
||||
"type": "review",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 273,
|
||||
"upvotes": 2,
|
||||
"saves": 0,
|
||||
"comments": 0,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-01-14",
|
||||
"updated_at": "2026-01-14",
|
||||
"url": "https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39"
|
||||
},
|
||||
{
|
||||
"title": " 🛠️ Debug Open WebUI Plugins in Your Browser",
|
||||
"slug": "debug_open_webui_plugins_in_your_browser_81bf7960",
|
||||
"type": "action",
|
||||
"version": "",
|
||||
"author": "",
|
||||
"description": "",
|
||||
"downloads": 0,
|
||||
"views": 1599,
|
||||
"upvotes": 16,
|
||||
"saves": 13,
|
||||
"comments": 2,
|
||||
"is_published_plugin": false,
|
||||
"created_at": "2026-01-10",
|
||||
"updated_at": "2026-01-10",
|
||||
"url": "https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"username": "Fu-Jie",
|
||||
"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": 367,
|
||||
"following": 7,
|
||||
"total_points": 378,
|
||||
"post_points": 314,
|
||||
"comment_points": 64,
|
||||
"contributions": 76
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
> *Blue: Downloads | Purple: Views (Real-time dynamic)*
|
||||
|
||||
### 📂 Content Distribution
|
||||

|
||||

|
||||
|
||||
|
||||
## 📈 Overview
|
||||
@@ -16,48 +16,51 @@
|
||||
| Metric | Value |
|
||||
|------|------|
|
||||
| 📝 Total Posts |  |
|
||||
| ⬇️ Total Downloads |  |
|
||||
| 👁️ Total Views |  |
|
||||
| ⬇️ Total Plugin Downloads |  |
|
||||
| 👁️ Total Plugin Views |  |
|
||||
| 👍 Total Upvotes |  |
|
||||
| 💾 Total Saves |  |
|
||||
| 💾 Total Plugin Saves |  |
|
||||
| ⭐ Author Points |  |
|
||||
| 👥 Followers |  |
|
||||
| 🧩 Published Plugins |  |
|
||||
|
||||
## 📂 By Type
|
||||
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
|
||||
## 📋 Posts List
|
||||
|
||||
| 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-27 |
|
||||
| 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-27 |
|
||||
| 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-27 |
|
||||
| 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 |
|
||||
| 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 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-02-25 |
|
||||
| 15 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 16 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 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.9.0: Copilot SDK Skills Core Capabilities & Extended Delivery](https://openwebui.com/posts/github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452) | post |  |  |  |  |  | 2026-02-27 |
|
||||
| 20 | [🚀 GitHub Copilot SDK Pipe v0.8.0: Conditional Tool Filtering & Publish Reliability 🎛️](https://openwebui.com/posts/github_copilot_sdk_pipe_v080_conditional_tool_filt_a5a3322d) | post |  |  |  |  |  | 2026-02-25 |
|
||||
| 21 | [🚀 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 |
|
||||
| 22 | [🚀 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 |
|
||||
| 23 | [🚀 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 |
|
||||
| 24 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 25 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post |  |  |  |  |  | 2026-01-10 |
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 3 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | filter |  |  |  |  |  | 2026-03-16 |
|
||||
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter |  |  |  |  |  | 2026-03-16 |
|
||||
| 5 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 6 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | prompt |  |  |  |  |  | 2026-01-28 |
|
||||
| 7 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 8 | [OpenWebUI Skills Manager Tool](https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4) | tool |  |  |  |  |  | 2026-03-19 |
|
||||
| 9 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe |  |  |  |  |  | 2026-03-19 |
|
||||
| 10 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 11 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 12 | [🧠 Smart Mind Map Tool: Auto-Generate Interactive Knowledge Graphs](https://openwebui.com/posts/smart_mind_map_tool_auto_generate_interactive_know_d25f4e3d) | tool |  |  |  |  |  | 2026-03-05 |
|
||||
| 13 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 14 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter |  |  |  |  |  | 2026-01-20 |
|
||||
| 15 | [Batch Install Plugins from GitHub](https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80) | tool |  |  |  |  |  | 2026-03-19 |
|
||||
| 16 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-03-16 |
|
||||
| 17 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 18 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 19 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 20 | [精读](https://openwebui.com/posts/精读_99830b0f) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 21 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 22 | [An Unconventional Use of Open Terminal ⚡](https://openwebui.com/posts/an_unconventional_use_of_open_terminal_35498f8f) | action |  |  |  |  |  | 2026-03-07 |
|
||||
| 23 | [🚀 GitHub Copilot SDK Pipe v0.9.0: Skills & RichUI](https://openwebui.com/posts/github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452) | pipe |  |  |  |  |  | 2026-02-28 |
|
||||
| 24 | [🚀 GitHub Copilot SDK Pipe v0.7.0: Skills & Rich UI 🛠️](https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131) | pipe |  |  |  |  |  | 2026-02-28 |
|
||||
| 25 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | pipe |  |  |  |  |  | 2026-02-10 |
|
||||
| 26 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | action |  |  |  |  |  | 2026-01-28 |
|
||||
| 27 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 28 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | action |  |  |  |  |  | 2026-01-10 |
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
> *蓝色: 总下载量 | 紫色: 总浏览量 (实时动态生成)*
|
||||
|
||||
### 📂 内容分类占比 (Distribution)
|
||||

|
||||

|
||||
|
||||
|
||||
## 📈 总览
|
||||
@@ -16,48 +16,51 @@
|
||||
| 指标 | 数值 |
|
||||
|------|------|
|
||||
| 📝 发布数量 |  |
|
||||
| ⬇️ 总下载量 |  |
|
||||
| 👁️ 总浏览量 |  |
|
||||
| ⬇️ 插件总下载量 |  |
|
||||
| 👁️ 插件总浏览量 |  |
|
||||
| 👍 总点赞数 |  |
|
||||
| 💾 总收藏数 |  |
|
||||
| 💾 插件总收藏数 |  |
|
||||
| ⭐ 作者总积分 |  |
|
||||
| 👥 粉丝数量 |  |
|
||||
| 🧩 已发布插件数 |  |
|
||||
|
||||
## 📂 按类型分类
|
||||
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
- 
|
||||
|
||||
## 📋 发布列表
|
||||
|
||||
| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |
|
||||
|:---:|------|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action |  |  |  |  |  | 2026-02-27 |
|
||||
| 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-27 |
|
||||
| 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-27 |
|
||||
| 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 |
|
||||
| 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 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-02-25 |
|
||||
| 15 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 16 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 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.9.0: Copilot SDK Skills Core Capabilities & Extended Delivery](https://openwebui.com/posts/github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452) | post |  |  |  |  |  | 2026-02-27 |
|
||||
| 20 | [🚀 GitHub Copilot SDK Pipe v0.8.0: Conditional Tool Filtering & Publish Reliability 🎛️](https://openwebui.com/posts/github_copilot_sdk_pipe_v080_conditional_tool_filt_a5a3322d) | post |  |  |  |  |  | 2026-02-25 |
|
||||
| 21 | [🚀 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 |
|
||||
| 22 | [🚀 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 |
|
||||
| 23 | [🚀 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 |
|
||||
| 24 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 25 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | post |  |  |  |  |  | 2026-01-10 |
|
||||
| 1 | [Smart Mind Map](https://openwebui.com/posts/turn_any_text_into_beautiful_mind_maps_3094c59a) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 2 | [Smart Infographic](https://openwebui.com/posts/smart_infographic_ad6f0c7f) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 3 | [Markdown Normalizer](https://openwebui.com/posts/markdown_normalizer_baaa8732) | filter |  |  |  |  |  | 2026-03-16 |
|
||||
| 4 | [Async Context Compression](https://openwebui.com/posts/async_context_compression_b1655bc8) | filter |  |  |  |  |  | 2026-03-16 |
|
||||
| 5 | [Export to Word Enhanced](https://openwebui.com/posts/export_to_word_enhanced_formatting_fca6a315) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 6 | [AI Task Instruction Generator](https://openwebui.com/posts/ai_task_instruction_generator_9bab8b37) | prompt |  |  |  |  |  | 2026-01-28 |
|
||||
| 7 | [Export to Excel](https://openwebui.com/posts/export_mulit_table_to_excel_244b8f9d) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 8 | [OpenWebUI Skills Manager Tool](https://openwebui.com/posts/openwebui_skills_manager_tool_b4bce8e4) | tool |  |  |  |  |  | 2026-03-19 |
|
||||
| 9 | [GitHub Copilot Official SDK Pipe](https://openwebui.com/posts/github_copilot_official_sdk_pipe_ce96f7b4) | pipe |  |  |  |  |  | 2026-03-19 |
|
||||
| 10 | [Flash Card](https://openwebui.com/posts/flash_card_65a2ea8f) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 11 | [Deep Dive](https://openwebui.com/posts/deep_dive_c0b846e4) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 12 | [🧠 Smart Mind Map Tool: Auto-Generate Interactive Knowledge Graphs](https://openwebui.com/posts/smart_mind_map_tool_auto_generate_interactive_know_d25f4e3d) | tool |  |  |  |  |  | 2026-03-05 |
|
||||
| 13 | [导出为Word增强版](https://openwebui.com/posts/导出为_word_支持公式流程图表格和代码块_8a6306c0) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 14 | [📂 Folder Memory – Auto-Evolving Project Context](https://openwebui.com/posts/folder_memory_auto_evolving_project_context_4a9875b2) | filter |  |  |  |  |  | 2026-01-20 |
|
||||
| 15 | [Batch Install Plugins from GitHub](https://openwebui.com/posts/batch_install_plugins_install_popular_plugins_in_s_c9fd6e80) | tool |  |  |  |  |  | 2026-03-19 |
|
||||
| 16 | [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/github_copilot_sdk_files_filter_403a62ee) | filter |  |  |  |  |  | 2026-03-16 |
|
||||
| 17 | [智能信息图](https://openwebui.com/posts/智能信息图_e04a48ff) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 18 | [思维导图](https://openwebui.com/posts/智能生成交互式思维导图帮助用户可视化知识_8d4b097b) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 19 | [异步上下文压缩](https://openwebui.com/posts/异步上下文压缩_5c0617cb) | action |  |  |  |  |  | 2026-02-13 |
|
||||
| 20 | [精读](https://openwebui.com/posts/精读_99830b0f) | action |  |  |  |  |  | 2026-01-08 |
|
||||
| 21 | [闪记卡 (Flash Card)](https://openwebui.com/posts/闪记卡生成插件_4a31eac3) | action |  |  |  |  |  | 2026-03-16 |
|
||||
| 22 | [An Unconventional Use of Open Terminal ⚡](https://openwebui.com/posts/an_unconventional_use_of_open_terminal_35498f8f) | action |  |  |  |  |  | 2026-03-07 |
|
||||
| 23 | [🚀 GitHub Copilot SDK Pipe v0.9.0: Skills & RichUI](https://openwebui.com/posts/github_copilot_sdk_pipe_v090_copilot_sdk_skills_co_99a42452) | pipe |  |  |  |  |  | 2026-02-28 |
|
||||
| 24 | [🚀 GitHub Copilot SDK Pipe v0.7.0: Skills & Rich UI 🛠️](https://openwebui.com/posts/github_copilot_sdk_pipe_v070_native_tool_ui_zero_c_4af38131) | pipe |  |  |  |  |  | 2026-02-28 |
|
||||
| 25 | [🚀 GitHub Copilot SDK Pipe: AI That Executes, Not Just Talks](https://openwebui.com/posts/github_copilot_sdk_for_openwebui_elevate_your_ai_t_a140f293) | pipe |  |  |  |  |  | 2026-02-10 |
|
||||
| 26 | [🚀 Open WebUI Prompt Plus: AI-Powered Prompt Manager](https://openwebui.com/posts/open_webui_prompt_plus_ai_powered_prompt_manager_s_15fa060e) | action |  |  |  |  |  | 2026-01-28 |
|
||||
| 27 | [Review of Claude Haiku 4.5](https://openwebui.com/posts/review_of_claude_haiku_45_41b0db39) | review |  |  |  |  |  | 2026-01-14 |
|
||||
| 28 | [ 🛠️ Debug Open WebUI Plugins in Your Browser](https://openwebui.com/posts/debug_open_webui_plugins_in_your_browser_81bf7960) | action |  |  |  |  |  | 2026-01-10 |
|
||||
|
||||
124
docs/development/fix-role-tool-error.md
Normal file
124
docs/development/fix-role-tool-error.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Fix: OpenAI API Error "messages with role 'tool' must be a response to a preceding message with 'tool_calls'"
|
||||
|
||||
## Problem Description
|
||||
In the `async-context-compression` filter, chat history can be trimmed or summarized when the conversation grows. If the retained tail starts in the middle of a native tool-calling sequence, the next request may begin with a `tool` message whose triggering `assistant` message is no longer present.
|
||||
|
||||
That produces the OpenAI API error:
|
||||
`"messages with role 'tool' must be a response to a preceding message with 'tool_calls'"`
|
||||
|
||||
## Root Cause
|
||||
History compression boundaries were not fully aware of atomic tool-call chains. A valid chain may include:
|
||||
|
||||
1. An `assistant` message with `tool_calls`
|
||||
2. One or more `tool` messages
|
||||
3. An optional assistant follow-up that consumes the tool results
|
||||
|
||||
If truncation happens inside that chain, the request sent to the model becomes invalid.
|
||||
|
||||
## Solution: Atomic Boundary Alignment
|
||||
The fix groups tool-call sequences into atomic units and aligns trim boundaries to those groups.
|
||||
|
||||
### 1. `_get_atomic_groups()`
|
||||
This helper groups message indices into units that must be kept or dropped together. It explicitly recognizes native tool-calling patterns such as:
|
||||
|
||||
- `assistant(tool_calls)`
|
||||
- `tool`
|
||||
- assistant follow-up response
|
||||
|
||||
Conceptually, it treats the whole sequence as one atomic block instead of independent messages.
|
||||
|
||||
```python
|
||||
def _get_atomic_groups(self, messages: List[Dict]) -> List[List[int]]:
|
||||
groups = []
|
||||
current_group = []
|
||||
|
||||
for i, msg in enumerate(messages):
|
||||
role = msg.get("role")
|
||||
has_tool_calls = bool(msg.get("tool_calls"))
|
||||
|
||||
if role == "assistant" and has_tool_calls:
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
current_group = [i]
|
||||
elif role == "tool":
|
||||
if not current_group:
|
||||
groups.append([i])
|
||||
else:
|
||||
current_group.append(i)
|
||||
elif (
|
||||
role == "assistant"
|
||||
and current_group
|
||||
and messages[current_group[-1]].get("role") == "tool"
|
||||
):
|
||||
current_group.append(i)
|
||||
groups.append(current_group)
|
||||
current_group = []
|
||||
else:
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
current_group = []
|
||||
groups.append([i])
|
||||
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
|
||||
return groups
|
||||
```
|
||||
|
||||
### 2. `_align_tail_start_to_atomic_boundary()`
|
||||
This helper checks whether a proposed trim point falls inside one of those atomic groups. If it does, the start index is moved backward to the beginning of that group.
|
||||
|
||||
```python
|
||||
def _align_tail_start_to_atomic_boundary(
|
||||
self, messages: List[Dict], raw_start_index: int, protected_prefix: int
|
||||
) -> int:
|
||||
aligned_start = max(raw_start_index, protected_prefix)
|
||||
|
||||
if aligned_start <= protected_prefix or aligned_start >= len(messages):
|
||||
return aligned_start
|
||||
|
||||
trimmable = messages[protected_prefix:]
|
||||
local_start = aligned_start - protected_prefix
|
||||
|
||||
for group in self._get_atomic_groups(trimmable):
|
||||
group_start = group[0]
|
||||
group_end = group[-1] + 1
|
||||
|
||||
if local_start == group_start:
|
||||
return aligned_start
|
||||
|
||||
if group_start < local_start < group_end:
|
||||
return protected_prefix + group_start
|
||||
|
||||
return aligned_start
|
||||
```
|
||||
|
||||
### 3. Applied to Tail Retention and Summary Progress
|
||||
The aligned boundary is now used when rebuilding the retained tail and when calculating how much history can be summarized safely.
|
||||
|
||||
Example from the current implementation:
|
||||
|
||||
```python
|
||||
raw_start_index = max(compressed_count, effective_keep_first)
|
||||
start_index = self._align_tail_start_to_atomic_boundary(
|
||||
messages, raw_start_index, effective_keep_first
|
||||
)
|
||||
tail_messages = messages[start_index:]
|
||||
```
|
||||
|
||||
And during summary progress calculation:
|
||||
|
||||
```python
|
||||
raw_target_compressed_count = max(0, len(messages) - self.valves.keep_last)
|
||||
target_compressed_count = self._align_tail_start_to_atomic_boundary(
|
||||
messages, raw_target_compressed_count, effective_keep_first
|
||||
)
|
||||
```
|
||||
|
||||
## Verification Results
|
||||
- **First compression boundary**: When history first crosses the compression threshold, the retained tail no longer starts inside a tool-call block.
|
||||
- **Complex sessions**: Real-world testing with 30+ messages, multiple tool calls, and failed calls remained stable during background summarization.
|
||||
- **Regression behavior**: The filter now prefers a valid boundary even if that means retaining slightly more context than a naive raw slice would allow.
|
||||
|
||||
## Conclusion
|
||||
The fix prevents orphaned `tool` messages by making history trimming and summary progress aware of atomic tool-call groups. This eliminates the 400 error during long conversations and background compression.
|
||||
126
docs/development/fix-role-tool-error.zh.md
Normal file
126
docs/development/fix-role-tool-error.zh.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 修复:OpenAI API 错误 "messages with role 'tool' must be a response to a preceding message with 'tool_calls'"
|
||||
|
||||
## 问题描述
|
||||
在 `async-context-compression` 过滤器中,当对话历史变长时,系统会对消息进行裁剪或摘要。如果保留下来的尾部历史恰好从一个原生工具调用序列的中间开始,那么下一次请求就可能以一条 `tool` 消息开头,而触发它的 `assistant` 消息已经被裁掉。
|
||||
|
||||
这就会触发 OpenAI API 的错误:
|
||||
`"messages with role 'tool' must be a response to a preceding message with 'tool_calls'"`
|
||||
|
||||
## 根本原因
|
||||
|
||||
真正的缺陷在于历史压缩边界没有完整识别工具调用链的“原子性”。一个合法的工具调用链通常包括:
|
||||
|
||||
1. 一条带有 `tool_calls` 的 `assistant` 消息
|
||||
2. 一条或多条 `tool` 消息
|
||||
3. 一条可选的 assistant 跟进回复,用于消费工具结果
|
||||
|
||||
如果裁剪点落在这段链条内部,发给模型的消息序列就会变成非法格式。
|
||||
|
||||
## 解决方案:对齐原子边界
|
||||
修复通过把工具调用序列分组为原子单元,并使裁剪边界对齐到这些单元。
|
||||
|
||||
### 1. `_get_atomic_groups()`
|
||||
这个辅助函数会把消息索引分组为“必须一起保留或一起丢弃”的原子单元。它显式识别以下原生工具调用模式:
|
||||
|
||||
- `assistant(tool_calls)`
|
||||
- `tool`
|
||||
- assistant 跟进回复
|
||||
|
||||
也就是说,它不再把这些消息看成彼此独立的单条消息,而是把整段序列视为一个原子块。
|
||||
|
||||
```python
|
||||
def _get_atomic_groups(self, messages: List[Dict]) -> List[List[int]]:
|
||||
groups = []
|
||||
current_group = []
|
||||
|
||||
for i, msg in enumerate(messages):
|
||||
role = msg.get("role")
|
||||
has_tool_calls = bool(msg.get("tool_calls"))
|
||||
|
||||
if role == "assistant" and has_tool_calls:
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
current_group = [i]
|
||||
elif role == "tool":
|
||||
if not current_group:
|
||||
groups.append([i])
|
||||
else:
|
||||
current_group.append(i)
|
||||
elif (
|
||||
role == "assistant"
|
||||
and current_group
|
||||
and messages[current_group[-1]].get("role") == "tool"
|
||||
):
|
||||
current_group.append(i)
|
||||
groups.append(current_group)
|
||||
current_group = []
|
||||
else:
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
current_group = []
|
||||
groups.append([i])
|
||||
|
||||
if current_group:
|
||||
groups.append(current_group)
|
||||
|
||||
return groups
|
||||
```
|
||||
|
||||
### 2. `_align_tail_start_to_atomic_boundary()`
|
||||
这个辅助函数会检查一个拟定的裁剪起点是否落在某个原子块内部。如果是,它会把起点向前回退到该原子块的开头位置。
|
||||
|
||||
```python
|
||||
def _align_tail_start_to_atomic_boundary(
|
||||
self, messages: List[Dict], raw_start_index: int, protected_prefix: int
|
||||
) -> int:
|
||||
aligned_start = max(raw_start_index, protected_prefix)
|
||||
|
||||
if aligned_start <= protected_prefix or aligned_start >= len(messages):
|
||||
return aligned_start
|
||||
|
||||
trimmable = messages[protected_prefix:]
|
||||
local_start = aligned_start - protected_prefix
|
||||
|
||||
for group in self._get_atomic_groups(trimmable):
|
||||
group_start = group[0]
|
||||
group_end = group[-1] + 1
|
||||
|
||||
if local_start == group_start:
|
||||
return aligned_start
|
||||
|
||||
if group_start < local_start < group_end:
|
||||
return protected_prefix + group_start
|
||||
|
||||
return aligned_start
|
||||
```
|
||||
|
||||
### 3. 应用于尾部保留和摘要进度计算
|
||||
这个对齐后的边界现在被用于重建保留尾部消息,以及计算可以安全摘要的历史范围。
|
||||
|
||||
当前实现中的示例:
|
||||
|
||||
```python
|
||||
raw_start_index = max(compressed_count, effective_keep_first)
|
||||
start_index = self._align_tail_start_to_atomic_boundary(
|
||||
messages, raw_start_index, effective_keep_first
|
||||
)
|
||||
tail_messages = messages[start_index:]
|
||||
```
|
||||
|
||||
在摘要进度计算中同样如此:
|
||||
|
||||
```python
|
||||
raw_target_compressed_count = max(0, len(messages) - self.valves.keep_last)
|
||||
target_compressed_count = self._align_tail_start_to_atomic_boundary(
|
||||
messages, raw_target_compressed_count, effective_keep_first
|
||||
)
|
||||
```
|
||||
|
||||
## 验证结果
|
||||
|
||||
- **首次压缩边界**:当历史第一次越过压缩阈值时,保留尾部不再从工具调用块中间开始。
|
||||
- **复杂会话验证**:在 30+ 条消息、多个工具调用和失败调用的真实场景下,后台摘要过程保持稳定。
|
||||
- **回归行为更安全**:过滤器现在会优先选择合法边界,即使这意味着比原始的朴素切片稍微多保留一点上下文。
|
||||
|
||||
## 结论
|
||||
通过让历史裁剪与摘要进度计算具备"工具调用原子块感知"能力,避免孤立的 `tool` 消息出现,消除长对话与后台压缩期间的 400 错误。
|
||||
426
docs/development/gh-aw-integration-plan.md
Normal file
426
docs/development/gh-aw-integration-plan.md
Normal file
@@ -0,0 +1,426 @@
|
||||
# gh-aw Integration Plan
|
||||
|
||||
> This document proposes a safe, incremental adoption plan for GitHub Agentic Workflows (`gh-aw`) in the `openwebui-extensions` repository.
|
||||
|
||||
---
|
||||
|
||||
## 1. Goals
|
||||
|
||||
- Add repository-aware AI maintenance without replacing stable script-based CI.
|
||||
- Use `gh-aw` where natural language reasoning is stronger than deterministic shell logic.
|
||||
- Preserve the current release, deploy, publish, and stats workflows as the execution backbone.
|
||||
- Introduce observability, diagnosis, and long-term maintenance memory for repository operations.
|
||||
|
||||
---
|
||||
|
||||
## 2. Why gh-aw Fits This Repository
|
||||
|
||||
This repository already has strong deterministic automation:
|
||||
|
||||
- `/.github/workflows/release.yml`
|
||||
- `/.github/workflows/plugin-version-check.yml`
|
||||
- `/.github/workflows/deploy.yml`
|
||||
- `/.github/workflows/publish_plugin.yml`
|
||||
- `/.github/workflows/community-stats.yml`
|
||||
|
||||
Those workflows are good at exact execution, but they do not deeply understand repository policy.
|
||||
|
||||
`gh-aw` is a good fit for tasks that require:
|
||||
|
||||
- reading code, docs, and PR descriptions together
|
||||
- applying repository conventions with nuance
|
||||
- generating structured review comments
|
||||
- diagnosing failed workflow runs
|
||||
- keeping long-term maintenance notes across runs
|
||||
|
||||
This matches the repository's real needs:
|
||||
|
||||
- bilingual documentation synchronization
|
||||
- plugin code + README + docs consistency
|
||||
- release-prep validation across many files
|
||||
- issue and PR maintenance at scale
|
||||
|
||||
---
|
||||
|
||||
## 3. Non-Goals
|
||||
|
||||
The first adoption phase should not:
|
||||
|
||||
- replace `release.yml`
|
||||
- replace `publish_plugin.yml`
|
||||
- replace MkDocs deployment
|
||||
- auto-merge or auto-push code changes by default
|
||||
- grant broad write permissions to the agent
|
||||
|
||||
`gh-aw` should begin as a review, diagnosis, and preflight layer.
|
||||
|
||||
---
|
||||
|
||||
## 4. Adoption Principles
|
||||
|
||||
### 4.1 Keep deterministic workflows for execution
|
||||
|
||||
Existing YAML workflows remain responsible for:
|
||||
|
||||
- release creation
|
||||
- plugin publishing
|
||||
- documentation deployment
|
||||
- version extraction and comparison
|
||||
- stats generation
|
||||
|
||||
### 4.2 Add agentic workflows for judgment
|
||||
|
||||
`gh-aw` workflows should focus on:
|
||||
|
||||
- policy-aware review
|
||||
- release readiness checks
|
||||
- docs drift analysis
|
||||
- CI failure investigation
|
||||
- issue triage and response drafting
|
||||
|
||||
### 4.3 Default to read-only behavior
|
||||
|
||||
Start with minimal permissions and use safe outputs only for controlled comments or issue creation.
|
||||
|
||||
### 4.4 Keep the blast radius small
|
||||
|
||||
Roll out one workflow at a time, verify output quality, then expand.
|
||||
|
||||
---
|
||||
|
||||
## 5. Proposed Repository Layout
|
||||
|
||||
### 5.1 New files and directories
|
||||
|
||||
```text
|
||||
.github/
|
||||
├── workflows/
|
||||
│ ├── release.yml
|
||||
│ ├── plugin-version-check.yml
|
||||
│ ├── deploy.yml
|
||||
│ ├── publish_plugin.yml
|
||||
│ ├── community-stats.yml
|
||||
│ ├── aw-pr-maintainer-review.md
|
||||
│ ├── aw-pr-maintainer-review.lock.yml
|
||||
│ ├── aw-release-preflight.md
|
||||
│ ├── aw-release-preflight.lock.yml
|
||||
│ ├── aw-ci-audit.md
|
||||
│ ├── aw-ci-audit.lock.yml
|
||||
│ ├── aw-docs-drift-review.md
|
||||
│ └── aw-docs-drift-review.lock.yml
|
||||
├── gh-aw/
|
||||
│ ├── prompts/
|
||||
│ │ ├── pr-review-policy.md
|
||||
│ │ ├── release-preflight-policy.md
|
||||
│ │ ├── ci-audit-policy.md
|
||||
│ │ └── docs-drift-policy.md
|
||||
│ ├── schemas/
|
||||
│ │ └── review-output-example.json
|
||||
│ └── README.md
|
||||
└── copilot-instructions.md
|
||||
```
|
||||
|
||||
### 5.2 Naming convention
|
||||
|
||||
Use an `aw-` prefix for all agentic workflow source files:
|
||||
|
||||
- `aw-pr-maintainer-review.md`
|
||||
- `aw-release-preflight.md`
|
||||
- `aw-ci-audit.md`
|
||||
- `aw-docs-drift-review.md`
|
||||
|
||||
Reasons:
|
||||
|
||||
- clearly separates agentic workflows from existing handwritten YAML workflows
|
||||
- keeps `gh-aw` assets easy to search
|
||||
- avoids ambiguity during debugging and release review
|
||||
|
||||
### 5.3 Why not replace `.yml` files
|
||||
|
||||
The current workflows are production logic. `gh-aw` should complement them first, not absorb their responsibility.
|
||||
|
||||
---
|
||||
|
||||
## 6. Recommended Workflow Portfolio
|
||||
|
||||
### 6.1 Phase 1: PR Maintainer Review
|
||||
|
||||
**File**: `/.github/workflows/aw-pr-maintainer-review.md`
|
||||
|
||||
**Purpose**:
|
||||
|
||||
- review PRs that touch plugins, docs, or development guidance
|
||||
- comment on missing repository-standard updates
|
||||
- act as a semantic layer on top of `plugin-version-check.yml`
|
||||
|
||||
**Checks to perform**:
|
||||
|
||||
- plugin version updated when code changes
|
||||
- `README.md` and `README_CN.md` both updated when required
|
||||
- docs mirror pages updated when required
|
||||
- root README badge/date update needed for release-related changes
|
||||
- i18n and helper-method standards followed for plugin code
|
||||
- Conventional Commit quality in PR title/body if relevant
|
||||
|
||||
**Suggested permissions**:
|
||||
|
||||
```yaml
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
```
|
||||
|
||||
**Suggested tools**:
|
||||
|
||||
- `github:` read-focused issue/PR/repo tools
|
||||
- `bash:` limited read commands only
|
||||
- `edit:` disabled in early phase
|
||||
- `agentic-workflows:` optional only after adoption matures
|
||||
|
||||
### 6.2 Phase 1: Release Preflight
|
||||
|
||||
**File**: `/.github/workflows/aw-release-preflight.md`
|
||||
|
||||
**Purpose**:
|
||||
|
||||
- run before release or on manual dispatch
|
||||
- verify release completeness before `release.yml` does packaging and publishing
|
||||
|
||||
**Checks to perform**:
|
||||
|
||||
- code version and docs versions are aligned
|
||||
- bilingual README updates exist
|
||||
- docs plugin mirrors exist and match the release target
|
||||
- release notes sources exist where expected
|
||||
- commit message and release draft are coherent
|
||||
|
||||
**Output style**:
|
||||
|
||||
- summary comment on PR or issue
|
||||
- optional checklist artifact
|
||||
- no direct release creation
|
||||
|
||||
### 6.3 Phase 2: CI Audit
|
||||
|
||||
**File**: `/.github/workflows/aw-ci-audit.md`
|
||||
|
||||
**Purpose**:
|
||||
|
||||
- inspect failed runs of `release.yml`, `publish_plugin.yml`, `community-stats.yml`, and other important workflows
|
||||
- summarize likely root cause and next fix steps
|
||||
|
||||
**Why gh-aw is strong here**:
|
||||
|
||||
- it can use `logs` and `audit` via `gh aw mcp-server`
|
||||
- it is designed for workflow introspection and post-hoc analysis
|
||||
|
||||
### 6.4 Phase 2: Docs Drift Review
|
||||
|
||||
**File**: `/.github/workflows/aw-docs-drift-review.md`
|
||||
|
||||
**Purpose**:
|
||||
|
||||
- periodically inspect whether plugin code, local README files, mirrored docs, and root indexes have drifted apart
|
||||
|
||||
**Checks to perform**:
|
||||
|
||||
- missing `README_CN.md`
|
||||
- README sections out of order
|
||||
- docs page missing after plugin update
|
||||
- version mismatches across code and docs
|
||||
|
||||
### 6.5 Phase 3: Issue Maintainer
|
||||
|
||||
**Candidate file**: `/.github/workflows/aw-issue-maintainer.md`
|
||||
|
||||
**Purpose**:
|
||||
|
||||
- summarize unreplied issues
|
||||
- propose bilingual responses
|
||||
- group repeated bug reports by plugin
|
||||
|
||||
This should come after the earlier review and audit flows are trusted.
|
||||
|
||||
---
|
||||
|
||||
## 7. Mapping to Existing Workflows
|
||||
|
||||
| Current Workflow | Keep As-Is | gh-aw Companion | Role Split |
|
||||
|------|------|------|------|
|
||||
| `/.github/workflows/release.yml` | Yes | `aw-release-preflight.md` | `release.yml` executes; `gh-aw` judges readiness |
|
||||
| `/.github/workflows/plugin-version-check.yml` | Yes | `aw-pr-maintainer-review.md` | hard gate + semantic review |
|
||||
| `/.github/workflows/deploy.yml` | Yes | none initially | deterministic build and deploy |
|
||||
| `/.github/workflows/publish_plugin.yml` | Yes | `aw-ci-audit.md` | deterministic publish + failure diagnosis |
|
||||
| `/.github/workflows/community-stats.yml` | Yes | `aw-ci-audit.md` | deterministic stats + anomaly diagnosis |
|
||||
|
||||
---
|
||||
|
||||
## 8. Tooling Model
|
||||
|
||||
### 8.1 Built-in tools to enable first
|
||||
|
||||
For early workflows, prefer a narrow tool set:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
github:
|
||||
toolsets: [default]
|
||||
bash:
|
||||
- echo
|
||||
- pwd
|
||||
- ls
|
||||
- cat
|
||||
- head
|
||||
- tail
|
||||
- grep
|
||||
- wc
|
||||
- git status
|
||||
- git diff
|
||||
```
|
||||
|
||||
Do not enable unrestricted shell access in phase 1.
|
||||
|
||||
### 8.2 MCP usage model
|
||||
|
||||
Use `gh aw mcp-server` later for:
|
||||
|
||||
- workflow `status`
|
||||
- workflow `compile`
|
||||
- workflow `logs`
|
||||
- workflow `audit`
|
||||
- `mcp-inspect`
|
||||
|
||||
This is especially valuable for `aw-ci-audit.md`.
|
||||
|
||||
### 8.3 Safe output policy
|
||||
|
||||
In early adoption, only allow safe outputs that:
|
||||
|
||||
- comment on PRs
|
||||
- comment on issues
|
||||
- open a low-risk maintenance issue when explicitly needed
|
||||
|
||||
Avoid any automatic code-writing safe outputs at first.
|
||||
|
||||
---
|
||||
|
||||
## 9. Repo Memory Strategy
|
||||
|
||||
`gh-aw` repo memory is a strong fit for this repository, but it should be constrained.
|
||||
|
||||
### 9.1 Recommended first use cases
|
||||
|
||||
- recurring CI failure signatures
|
||||
- repeated docs sync omissions
|
||||
- common reviewer reminders
|
||||
- issue clusters by plugin name
|
||||
|
||||
### 9.2 Recommended configuration shape
|
||||
|
||||
- store only `.md` and `.json`
|
||||
- small patch size limit
|
||||
- one memory stream per concern
|
||||
|
||||
Suggested conceptual layout:
|
||||
|
||||
```text
|
||||
memory/review-notes/*.md
|
||||
memory/ci-patterns/*.md
|
||||
memory/issue-clusters/*.json
|
||||
```
|
||||
|
||||
### 9.3 Important caution
|
||||
|
||||
Do not store secrets, tokens, or unpublished sensitive data in repo memory.
|
||||
|
||||
---
|
||||
|
||||
## 10. Rollout Plan
|
||||
|
||||
### Phase 0: Preparation
|
||||
|
||||
- install `gh-aw` locally for maintainers
|
||||
- add a short `/.github/gh-aw/README.md`
|
||||
- document workflow naming and review expectations
|
||||
|
||||
### Phase 1: Read-only semantic review
|
||||
|
||||
- introduce `aw-pr-maintainer-review.md`
|
||||
- introduce `aw-release-preflight.md`
|
||||
- keep outputs limited to summaries and comments
|
||||
|
||||
### Phase 2: Diagnostics and memory
|
||||
|
||||
- introduce `aw-ci-audit.md`
|
||||
- enable `agentic-workflows:` where useful
|
||||
- add constrained `repo-memory` configuration for repeated failure patterns
|
||||
|
||||
### Phase 3: Maintenance automation
|
||||
|
||||
- add docs drift patrol
|
||||
- add issue maintenance workflow
|
||||
- consider limited code-change proposals only after trust is established
|
||||
|
||||
---
|
||||
|
||||
## 11. Local Maintainer Setup
|
||||
|
||||
For local experimentation and debugging:
|
||||
|
||||
### 11.1 Install CLI
|
||||
|
||||
```bash
|
||||
curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | bash
|
||||
```
|
||||
|
||||
### 11.2 Useful commands
|
||||
|
||||
```bash
|
||||
gh aw version
|
||||
gh aw compile
|
||||
gh aw status
|
||||
gh aw run aw-pr-maintainer-review
|
||||
gh aw logs
|
||||
gh aw audit <run-id>
|
||||
```
|
||||
|
||||
### 11.3 VS Code MCP integration
|
||||
|
||||
A future optional improvement is adding `gh aw mcp-server` to local MCP configuration so workflow introspection tools are available in editor-based agent sessions.
|
||||
|
||||
---
|
||||
|
||||
## 12. Recommended First Deliverables
|
||||
|
||||
Start with these two workflows only:
|
||||
|
||||
1. `aw-pr-maintainer-review.md`
|
||||
2. `aw-release-preflight.md`
|
||||
|
||||
This gives the repository the highest-value upgrade with the lowest operational risk.
|
||||
|
||||
---
|
||||
|
||||
## 13. Success Criteria
|
||||
|
||||
Adoption is working if:
|
||||
|
||||
- PR review comments become more specific and repository-aware
|
||||
- release preparation catches missing docs or version sync earlier
|
||||
- CI failures produce actionable summaries faster
|
||||
- maintainers spend less time on repetitive policy review
|
||||
- deterministic workflows remain stable and unchanged in core behavior
|
||||
|
||||
---
|
||||
|
||||
## 14. Summary
|
||||
|
||||
For `openwebui-extensions`, `gh-aw` should be adopted as an intelligent maintenance layer.
|
||||
|
||||
- Keep current YAML workflows for execution.
|
||||
- Add agentic workflows for policy-aware review and diagnosis.
|
||||
- Start read-only.
|
||||
- Expand only after signal quality is proven.
|
||||
|
||||
This approach aligns with the repository's existing strengths: strong conventions, bilingual maintenance, plugin lifecycle complexity, and growing repository operations.
|
||||
424
docs/development/gh-aw-integration-plan.zh.md
Normal file
424
docs/development/gh-aw-integration-plan.zh.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# gh-aw 集成方案
|
||||
|
||||
> 本文档用于为 `openwebui-extensions` 仓库设计一套安全、渐进式的 GitHub Agentic Workflows (`gh-aw`) 接入方案。
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标
|
||||
|
||||
- 在不替换现有稳定 CI 的前提下,引入具备仓库理解能力的 AI 维护层。
|
||||
- 将 `gh-aw` 用于更适合自然语言推理的任务,而不是机械脚本执行。
|
||||
- 保留当前发布、部署、发布插件和统计工作流作为执行骨架。
|
||||
- 为仓库维护引入可观测性、自动诊断和长期记忆能力。
|
||||
|
||||
---
|
||||
|
||||
## 2. 为什么这个仓库适合 gh-aw
|
||||
|
||||
本仓库已经有一套很强的确定性自动化:
|
||||
|
||||
- `/.github/workflows/release.yml`
|
||||
- `/.github/workflows/plugin-version-check.yml`
|
||||
- `/.github/workflows/deploy.yml`
|
||||
- `/.github/workflows/publish_plugin.yml`
|
||||
- `/.github/workflows/community-stats.yml`
|
||||
|
||||
这些工作流擅长精确执行,但并不擅长理解仓库规范本身。
|
||||
|
||||
`gh-aw` 更适合以下任务:
|
||||
|
||||
- 联合阅读代码、文档和 PR 描述后再做判断
|
||||
- 带语义地应用仓库规范
|
||||
- 生成结构化的 review 评论
|
||||
- 自动分析失败的工作流运行
|
||||
- 在多次运行之间保存维护经验和模式
|
||||
|
||||
这与当前仓库的真实需求高度匹配:
|
||||
|
||||
- 双语文档同步
|
||||
- 插件代码、README 与 docs 一致性检查
|
||||
- 跨多个文件的发布前完整性核查
|
||||
- Issue 与 PR 的规模化维护
|
||||
|
||||
---
|
||||
|
||||
## 3. 非目标
|
||||
|
||||
第一阶段不建议让 `gh-aw`:
|
||||
|
||||
- 替换 `release.yml`
|
||||
- 替换 `publish_plugin.yml`
|
||||
- 替换 MkDocs 部署
|
||||
- 默认自动合并或自动推送代码
|
||||
- 一开始就拥有过宽的写权限
|
||||
|
||||
第一阶段应把它定位为 review、诊断和 preflight 层。
|
||||
|
||||
---
|
||||
|
||||
## 4. 接入原则
|
||||
|
||||
### 4.1 确定性执行继续由 YAML 工作流承担
|
||||
|
||||
现有 YAML workflow 继续负责:
|
||||
|
||||
- 创建 release
|
||||
- 发布插件
|
||||
- 部署文档
|
||||
- 提取和比较版本号
|
||||
- 生成社区统计
|
||||
|
||||
### 4.2 Agentic workflow 只负责判断和总结
|
||||
|
||||
`gh-aw` workflow 优先承担:
|
||||
|
||||
- 基于规范的语义审查
|
||||
- 发布前完整性检查
|
||||
- 文档漂移巡检
|
||||
- CI 失败原因分析
|
||||
- Issue 分流与回复草稿生成
|
||||
|
||||
### 4.3 默认只读
|
||||
|
||||
优先使用最小权限,并通过 safe outputs 进行受控评论或低风险输出。
|
||||
|
||||
### 4.4 逐步扩容
|
||||
|
||||
一次只上线一个 agentic workflow,验证质量后再扩大范围。
|
||||
|
||||
---
|
||||
|
||||
## 5. 建议的仓库结构
|
||||
|
||||
### 5.1 新增文件和目录
|
||||
|
||||
```text
|
||||
.github/
|
||||
├── workflows/
|
||||
│ ├── release.yml
|
||||
│ ├── plugin-version-check.yml
|
||||
│ ├── deploy.yml
|
||||
│ ├── publish_plugin.yml
|
||||
│ ├── community-stats.yml
|
||||
│ ├── aw-pr-maintainer-review.md
|
||||
│ ├── aw-pr-maintainer-review.lock.yml
|
||||
│ ├── aw-release-preflight.md
|
||||
│ ├── aw-release-preflight.lock.yml
|
||||
│ ├── aw-ci-audit.md
|
||||
│ ├── aw-ci-audit.lock.yml
|
||||
│ ├── aw-docs-drift-review.md
|
||||
│ └── aw-docs-drift-review.lock.yml
|
||||
├── gh-aw/
|
||||
│ ├── prompts/
|
||||
│ │ ├── pr-review-policy.md
|
||||
│ │ ├── release-preflight-policy.md
|
||||
│ │ ├── ci-audit-policy.md
|
||||
│ │ └── docs-drift-policy.md
|
||||
│ ├── schemas/
|
||||
│ │ └── review-output-example.json
|
||||
│ └── README.md
|
||||
└── copilot-instructions.md
|
||||
```
|
||||
|
||||
### 5.2 命名规范
|
||||
|
||||
所有 agentic workflow 源文件统一使用 `aw-` 前缀:
|
||||
|
||||
- `aw-pr-maintainer-review.md`
|
||||
- `aw-release-preflight.md`
|
||||
- `aw-ci-audit.md`
|
||||
- `aw-docs-drift-review.md`
|
||||
|
||||
这样做的原因:
|
||||
|
||||
- 可以和现有手写 YAML 工作流明确区分
|
||||
- 便于在仓库中快速搜索和定位
|
||||
- 方便调试和发布时识别来源
|
||||
|
||||
### 5.3 为什么不直接替换 `.yml`
|
||||
|
||||
当前 `.yml` 文件承担的是生产执行逻辑。第一阶段 `gh-aw` 的角色应该是补充,而不是接管。
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议优先建设的 workflow 组合
|
||||
|
||||
### 6.1 第一阶段:PR 维护者语义审查
|
||||
|
||||
**文件**: `/.github/workflows/aw-pr-maintainer-review.md`
|
||||
|
||||
**作用**:
|
||||
|
||||
- 审查涉及插件、文档或开发规范的 PR
|
||||
- 对缺失的仓库标准更新给出评论
|
||||
- 作为 `plugin-version-check.yml` 之上的语义层
|
||||
|
||||
**建议检查项**:
|
||||
|
||||
- 插件代码修改后是否更新版本号
|
||||
- 是否同时更新 `README.md` 和 `README_CN.md`
|
||||
- 是否同步更新 docs 镜像页
|
||||
- 是否需要更新根 README 的日期 badge
|
||||
- 插件代码是否遵守 i18n 与 helper 规范
|
||||
- PR 标题或正文是否符合 Conventional Commits 精神
|
||||
|
||||
**建议权限**:
|
||||
|
||||
```yaml
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
```
|
||||
|
||||
**建议工具**:
|
||||
|
||||
- 只读型 `github:` 工具
|
||||
- 只开放少量只读 `bash:` 命令
|
||||
- 第一阶段不开放 `edit:`
|
||||
- `agentic-workflows:` 可在后续成熟后再启用
|
||||
|
||||
### 6.2 第一阶段:发布前预检
|
||||
|
||||
**文件**: `/.github/workflows/aw-release-preflight.md`
|
||||
|
||||
**作用**:
|
||||
|
||||
- 在 release 前或手动触发时执行
|
||||
- 在 `release.yml` 打包和发布之前,先检查发布完整性
|
||||
|
||||
**建议检查项**:
|
||||
|
||||
- 代码版本号和文档版本号是否一致
|
||||
- 双语 README 是否完整更新
|
||||
- docs 插件镜像页是否存在并匹配当前发布目标
|
||||
- release notes 来源文件是否齐全
|
||||
- commit message 与 release 草案是否连贯
|
||||
|
||||
**输出方式**:
|
||||
|
||||
- 在 PR 或 issue 中写总结评论
|
||||
- 可附带 checklist artifact
|
||||
- 不直接执行正式发布
|
||||
|
||||
### 6.3 第二阶段:CI 失败自动审计
|
||||
|
||||
**文件**: `/.github/workflows/aw-ci-audit.md`
|
||||
|
||||
**作用**:
|
||||
|
||||
- 分析 `release.yml`、`publish_plugin.yml`、`community-stats.yml` 等关键 workflow 的失败运行
|
||||
- 输出根因判断和下一步修复建议
|
||||
|
||||
**适合 gh-aw 的原因**:
|
||||
|
||||
- 可以通过 `gh aw mcp-server` 使用 `logs`、`audit` 等能力
|
||||
- 原生支持对 workflow 执行痕迹进行事后分析
|
||||
|
||||
### 6.4 第二阶段:文档漂移巡检
|
||||
|
||||
**文件**: `/.github/workflows/aw-docs-drift-review.md`
|
||||
|
||||
**作用**:
|
||||
|
||||
- 定期检查插件代码、插件目录 README、本地 docs 镜像和根索引之间是否发生漂移
|
||||
|
||||
**建议检查项**:
|
||||
|
||||
- 是否缺少 `README_CN.md`
|
||||
- README 章节顺序是否偏离规范
|
||||
- 插件更新后 docs 页面是否缺失
|
||||
- 代码和文档中的版本号是否不一致
|
||||
|
||||
### 6.5 第三阶段:Issue 维护助手
|
||||
|
||||
**候选文件**: `/.github/workflows/aw-issue-maintainer.md`
|
||||
|
||||
**作用**:
|
||||
|
||||
- 汇总长期未回复的 issue
|
||||
- 生成英文或双语回复草稿
|
||||
- 按插件归类重复问题
|
||||
|
||||
这个阶段建议在前面的 review 和 audit 流程稳定后再上线。
|
||||
|
||||
---
|
||||
|
||||
## 7. 与现有 workflow 的职责映射
|
||||
|
||||
| 当前 Workflow | 是否保留 | gh-aw 搭档 | 职责划分 |
|
||||
|------|------|------|------|
|
||||
| `/.github/workflows/release.yml` | 保留 | `aw-release-preflight.md` | `release.yml` 负责执行,`gh-aw` 负责判断是否已准备好 |
|
||||
| `/.github/workflows/plugin-version-check.yml` | 保留 | `aw-pr-maintainer-review.md` | 硬性门禁 + 语义审查 |
|
||||
| `/.github/workflows/deploy.yml` | 保留 | 初期不加 | 确定性构建和部署 |
|
||||
| `/.github/workflows/publish_plugin.yml` | 保留 | `aw-ci-audit.md` | 确定性发布 + 失败诊断 |
|
||||
| `/.github/workflows/community-stats.yml` | 保留 | `aw-ci-audit.md` | 确定性统计 + 异常诊断 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 工具模型建议
|
||||
|
||||
### 8.1 第一阶段建议启用的内建工具
|
||||
|
||||
建议从窄权限工具集开始:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
github:
|
||||
toolsets: [default]
|
||||
bash:
|
||||
- echo
|
||||
- pwd
|
||||
- ls
|
||||
- cat
|
||||
- head
|
||||
- tail
|
||||
- grep
|
||||
- wc
|
||||
- git status
|
||||
- git diff
|
||||
```
|
||||
|
||||
第一阶段不要开放完全不受限的 shell。
|
||||
|
||||
### 8.2 MCP 使用策略
|
||||
|
||||
后续可通过 `gh aw mcp-server` 引入:
|
||||
|
||||
- workflow `status`
|
||||
- workflow `compile`
|
||||
- workflow `logs`
|
||||
- workflow `audit`
|
||||
- `mcp-inspect`
|
||||
|
||||
这对 `aw-ci-audit.md` 特别有价值。
|
||||
|
||||
### 8.3 Safe output 策略
|
||||
|
||||
第一阶段仅开放低风险 safe outputs:
|
||||
|
||||
- 给 PR 写评论
|
||||
- 给 issue 写评论
|
||||
- 在明确需要时创建低风险维护 issue
|
||||
|
||||
一开始不要让 agent 自动提交代码修改。
|
||||
|
||||
---
|
||||
|
||||
## 9. Repo Memory 策略
|
||||
|
||||
`gh-aw` 的 repo memory 很适合本仓库,但必须加限制。
|
||||
|
||||
### 9.1 第一批适合保存的内容
|
||||
|
||||
- 重复出现的 CI 失败模式
|
||||
- 常见文档同步遗漏
|
||||
- 高频 review 提醒项
|
||||
- 按插件聚类的 issue 模式
|
||||
|
||||
### 9.2 推荐配置思路
|
||||
|
||||
- 只允许 `.md` 和 `.json`
|
||||
- 限制 patch size
|
||||
- 按主题拆成多个 memory stream
|
||||
|
||||
建议的逻辑布局:
|
||||
|
||||
```text
|
||||
memory/review-notes/*.md
|
||||
memory/ci-patterns/*.md
|
||||
memory/issue-clusters/*.json
|
||||
```
|
||||
|
||||
### 9.3 重要提醒
|
||||
|
||||
不要把 secret、token 或未公开敏感信息写入 repo memory。
|
||||
|
||||
---
|
||||
|
||||
## 10. 分阶段落地顺序
|
||||
|
||||
### Phase 0: 准备阶段
|
||||
|
||||
- 维护者本地安装 `gh-aw`
|
||||
- 添加一个简短的 `/.github/gh-aw/README.md`
|
||||
- 写清楚 workflow 命名规范和 review 预期
|
||||
|
||||
### Phase 1: 只读语义审查
|
||||
|
||||
- 上线 `aw-pr-maintainer-review.md`
|
||||
- 上线 `aw-release-preflight.md`
|
||||
- 输出先限制为总结和评论
|
||||
|
||||
### Phase 2: 诊断与记忆
|
||||
|
||||
- 上线 `aw-ci-audit.md`
|
||||
- 在需要的地方启用 `agentic-workflows:`
|
||||
- 为重复失败模式加入受限 `repo-memory`
|
||||
|
||||
### Phase 3: 维护自动化
|
||||
|
||||
- 增加文档漂移巡检
|
||||
- 增加 issue 维护 workflow
|
||||
- 只有在信号质量足够稳定后,再考虑有限度的代码修改建议
|
||||
|
||||
---
|
||||
|
||||
## 11. 维护者本地使用建议
|
||||
|
||||
### 11.1 安装 CLI
|
||||
|
||||
```bash
|
||||
curl -sL https://raw.githubusercontent.com/github/gh-aw/main/install-gh-aw.sh | bash
|
||||
```
|
||||
|
||||
### 11.2 常用命令
|
||||
|
||||
```bash
|
||||
gh aw version
|
||||
gh aw compile
|
||||
gh aw status
|
||||
gh aw run aw-pr-maintainer-review
|
||||
gh aw logs
|
||||
gh aw audit <run-id>
|
||||
```
|
||||
|
||||
### 11.3 VS Code MCP 集成
|
||||
|
||||
后续可选增强项是把 `gh aw mcp-server` 加入本地 MCP 配置,这样编辑器内的 agent 会直接具备 workflow 自省能力。
|
||||
|
||||
---
|
||||
|
||||
## 12. 最小可行落地建议
|
||||
|
||||
建议第一步只做这两个 workflow:
|
||||
|
||||
1. `aw-pr-maintainer-review.md`
|
||||
2. `aw-release-preflight.md`
|
||||
|
||||
这样可以以最低风险获得最高价值的增强。
|
||||
|
||||
---
|
||||
|
||||
## 13. 成功标准
|
||||
|
||||
如果接入有效,应该看到这些结果:
|
||||
|
||||
- PR 评论更具体,更贴合仓库规范
|
||||
- 发布前能更早发现文档或版本同步遗漏
|
||||
- CI 失败后更快得到可执行的总结
|
||||
- 维护者花在重复性规范检查上的时间下降
|
||||
- 现有确定性 workflow 的核心行为保持稳定
|
||||
|
||||
---
|
||||
|
||||
## 14. 总结
|
||||
|
||||
对 `openwebui-extensions` 来说,`gh-aw` 最合适的定位是智能维护层。
|
||||
|
||||
- 现有 YAML workflow 继续负责执行。
|
||||
- agentic workflow 负责语义审查和诊断。
|
||||
- 第一阶段默认只读。
|
||||
- 等输出质量稳定后再逐步放权。
|
||||
|
||||
这条路径和仓库现状是匹配的:规范密度高、双语维护复杂、插件生命周期长,而且已经具备成熟的 AI 工程上下文。
|
||||
BIN
docs/development/image.png
Normal file
BIN
docs/development/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 406 KiB |
@@ -32,6 +32,14 @@ Learn how to develop plugins and contribute to OpenWebUI Extensions.
|
||||
|
||||
[:octicons-arrow-right-24: Read the Plan](copilot-engineering-plan.md)
|
||||
|
||||
- :material-source-branch:{ .lg .middle } **gh-aw Integration Plan**
|
||||
|
||||
---
|
||||
|
||||
Adoption plan for using GitHub Agentic Workflows as a semantic review and diagnostics layer in this repository.
|
||||
|
||||
[:octicons-arrow-right-24: Read the Plan](gh-aw-integration-plan.md)
|
||||
|
||||
- :material-github:{ .lg .middle } **Contributing**
|
||||
|
||||
---
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user