Compare commits

..

364 Commits

Author SHA1 Message Date
fujie
922ac03b80 feat: add star repo shortcut to installer dialog 2026-03-16 15:58:11 +08:00
fujie
36419ba627 fix: extend batch installer selection timeout 2026-03-16 15:49:18 +08:00
fujie
6dac042059 docs: feature batch installer on homepage 2026-03-16 15:29:40 +08:00
fujie
9bcbdabb63 docs: simplify batch installer quick start 2026-03-16 15:25:46 +08:00
fujie
498f1d0d98 refactor: simplify selection dialog header 2026-03-16 15:23:37 +08:00
fujie
de562cc627 feat: add repository filters to selection dialog 2026-03-16 15:17:01 +08:00
fujie
0da77be66c fix: clarify single-call multi-repo usage 2026-03-16 15:11:25 +08:00
fujie
ec225bf713 feat: add multi-repository batch install support 2026-03-16 15:03:15 +08:00
fujie
743c1503ce fix: sync search results with selected plugins 2026-03-16 14:46:42 +08:00
fujie
976f9e3d74 fix: sync type filter with selected plugins 2026-03-16 14:38:55 +08:00
fujie
5a7b1d5097 feat: add search and filtering to batch installer dialog 2026-03-16 14:33:06 +08:00
fujie
7a2ecee010 feat: improve batch installer selection dialog 2026-03-16 14:24:48 +08:00
fujie
00afae4a6d feat: add interactive selection dialog to batch installer 2026-03-16 14:17:51 +08:00
fujie
e992b8a3bd fix(github-copilot-sdk): improve HTML embed type default to richui
- Changed default HTML embed type from 'artifacts' to 'richui' for direct OpenWebUI chat display
- Updated system prompt guidance to recommend RichUI mode by default, with artifacts only on explicit user request
- Maintains backward compatibility with existing configurations
2026-03-16 06:44:07 +08:00
fujie
6dbbca8e55 Remove deprecated agent coordination files and scripts; update documentation and streamline agent protocols. 2026-03-16 04:09:29 +08:00
fujie
06735d3c7f feat(readme): update badge links for followers, points, contributions, posts, downloads, views, upvotes, and saves 2026-03-16 02:07:23 +08:00
fujie
5119add50c feat(stats): enhance summary badge values and delta calculations 2026-03-16 02:06:46 +08:00
fujie
1df328a304 feat(stats): enhance plugin contribution tracking and update statistics display 2026-03-16 01:54:05 +08:00
fujie
e92ad60e3f docs(readme): refine badge wording and order
- update plugin README badges to use Top <1% and a clearer contribution icon
- reorder badge rows across mirrored docs and templates

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-16 01:49:58 +08:00
fujie
93a6c41c05 docs(site): fix strict-build doc links
- replace broken mirrored README asset links with GitHub URLs
- keep mkdocs strict build passing after the README refresh

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-16 01:29:18 +08:00
fujie
64af4276a7 docs(readme): refresh plugin badge layout and mirrors
- update plugin README badge rows and mirrored docs
- sync README template and scaffolder guidance

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-16 01:21:11 +08:00
fujie
4feb1bdd80 feat(smart-mind-map): add GitHub star icon to header controls
- Add prominent star icon in download button group linking to repository
- Style with gold gradient color (#fbbf24) for visibility
- Hover effect with scale and glow for better UX
- Icon uses yellow color (#fbbf24) with transparent background
- Helps users easily discover and support the project

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-16 00:02:53 +08:00
github-actions[bot]
44debbab04 chore: update community stats - new plugin added (27 -> 28) 2026-03-15 11:10:43 +00:00
fujie
de10ba87ae docs(batch-install-plugins): restructure README with quick start examples
- Reorganize Quick Start section to showcase 6 popular repositories with copy-paste examples
- Remove duplicate 'Popular Public Repositories' section
- Consolidate Installation Workflow and Usage Examples for clarity
- Add suurt8ll/open_webui_functions to popular collection list
- Update both English and Chinese documentation with consistent formatting
- Sync documentation mirrors to docs/plugins/

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-15 18:48:27 +08:00
fujie
c818a2ac8d fix(batch-install-plugins): support CRLF community plugin metadata
- support CRLF docstrings and folded YAML metadata blocks
- detect community repo plugins such as iChristGit/OpenWebui-Tools correctly
- align README, mirrored docs, and announcement wording with actual behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-15 18:14:23 +08:00
fujie
cea31fed38 feat(batch-install-plugins): initial release v1.0.0
Add Batch Install Plugins from GitHub tool with:
- One-click installation of plugins from GitHub repositories
- Smart plugin discovery with metadata extraction and validation
- Confirmation dialog with plugin list preview
- Selective installation with keyword-based filtering
- Smart fallback: auto-retry with localhost:8080 on connection failure
- Enhanced debugging with frontend and backend logging
- 120-second confirmation timeout for user convenience
- Async httpx client for non-blocking I/O
- Complete i18n support across 11 languages
- Event emitter handling with fallback support
- Timeout guards on frontend JavaScript execution
- Filtered list consistency for confirmation and installation
- Auto-exclusion of tool itself from batch operations
- 6 regression tests with 100% pass rate

Documentation includes:
- English and Chinese READMEs with flow diagrams
- Popular repository examples (iChristGit, Haervwe, Classic298, suurt8ll)
- Mirrored docs for official documentation site
- Plugin index entries in both languages
- Comprehensive release notes (v1.0.0.md and v1.0.0_CN.md)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-15 17:45:42 +08:00
fujie
8f8147828b docs(async-context-compression): add community post drafts 2026-03-14 16:29:15 +08:00
github-actions[bot]
158792d82f chore: update community stats - plugin versions updated 2026-03-14 08:14:10 +00:00
fujie
858d048d81 feat(async-context-compression): release v1.5.0
- add external chat reference summaries and mixed-script token estimation
- tighten summary budgeting, fallback handling, and frontend error visibility
- sync READMEs, mirrored docs, indexes, and bilingual v1.5.0 release notes
2026-03-14 16:10:06 +08:00
github-actions[bot]
2f518d4c7a chore: update community stats - plugin versions updated 2026-03-13 07:24:32 +00:00
fujie
baae09a223 Merge remote changes, keeping local version improvements 2026-03-13 14:58:22 +08:00
fujie
903bd7b372 fix(async-context-compression): strengthen summary path robustness
- Add comprehensive error logging for LLM response validation failures
- Thread __request__ context through entire summary generation pipeline
- Load and merge previous_summary from DB when not in outlet payload
- Use real request object instead of minimal synthetic context
2026-03-13 14:57:25 +08:00
fujie
8c998ecc73 fix(async-context-compression): strengthen summary path robustness
- Add comprehensive error logging for LLM response validation failures
- Thread __request__ context through entire summary generation pipeline
- Load and merge previous_summary from DB when not in outlet payload
- Use real request object instead of minimal synthetic context
2026-03-13 14:16:19 +08:00
fujie
f11cf27404 feat: add new stats entry for March 2026 and update stats calculation logic
- Added a new stats entry for March 12, 2026, including total posts, downloads, views, upvotes, saves, followers, points, contributions, and detailed post statistics.
- Updated the stats calculation logic in `openwebui_stats.py` to only count views for posts with actual downloads, excluding post and review types.
- Introduced a new script `zed-ai-tabs.sh` for batch-launching and orchestrating multiple AI CLI tools as tabs, including a single-instance lock mechanism and automatic tool discovery.
2026-03-12 17:39:18 +08:00
fujie
41f271d2d8 fix(stats): exclude post and review types from statistics count 2026-03-12 17:27:57 +08:00
fujie
984d3061c7 fix(stats): refine logic to count only downloadable post types in statistics 2026-03-12 16:40:53 +08:00
fujie
ba11cdd157 feat: Add OpenWebUI Community API patterns documentation and enhance stats script to accurately count downloadable post types 2026-03-12 15:12:45 +08:00
github-actions[bot]
b1482b6083 chore: update community stats - plugin versions updated 2026-03-11 21:41:47 +00:00
fujie
0cc46e0188 refactor(stats): improve metadata extraction and workflow change detection
- Implemented robust plugin object extraction in openwebui_stats.py to handle tool/pipe/action types.
- Updated community-stats.yml to detect version changes and plugin removals.
- Fixed NameError in _resolve_post_type.
2026-03-12 05:39:55 +08:00
fujie
93a42cbe03 feat: Enhance community stats workflow to detect plugin version changes and robustly extract plugin data in the generation script. 2026-03-11 23:45:21 +08:00
fujie
fdf95a2825 feat: Implement configurable OpenWebUI base URL for deployment scripts and update documentation. 2026-03-11 23:32:00 +08:00
fujie
5fe66a5803 feat(async-context-compression): upgrade summary prompt to Working Memory architecture
- Redefine summary task as 'Working Memory' generation for higher density
- Add explicit instructions to extract facts from raw JSON tool outputs
- Implement 'Incremental Integration' rule to prevent recursive summary degradation
- Enforce strict Markdown state structure (Goal, Facts, Code, Pending)
2026-03-11 12:38:06 +08:00
fujie
cd95b5ff69 fix(async-context-compression): reverse-unfolding to prevent progress drift
- Reconstruct native tool-calling sequences using reverse-unfolding mechanism
- Strictly use atomic grouping for safe native tool output trimming
- Add comprehensive test coverage for unfolding logic and issue drafts
- READMEs and docs synced (v1.4.1)
2026-03-11 03:54:40 +08:00
fujie
3210262296 docs: update Deployment Guide links in multiple documents 2026-03-09 23:07:33 +08:00
fujie
37a130993a docs: improve baseURL configuration guidance in batch installation guides
- Add baseURL configuration examples in release-prep.agent.md (localhost, IP, domain)
- Update release-workflow.md with baseURL configuration options
- Update release-workflow.zh.md with baseURL configuration options
- Improve .env.example documentation with URL examples and better instructions
- Support various OpenWebUI instance locations: localhost, remote IP, or domain
2026-03-09 22:01:25 +08:00
fujie
b75fd96e4a docs: add batch plugin installation guide to release-prep agent
- Add 'Post-Release: Batch Plugin Installation' section to release-prep.agent.md
- Include quick start commands for users to install all plugins after release
- Direct users to deployment guide for detailed instructions
2026-03-09 21:59:41 +08:00
fujie
5dd9d6cc56 docs: add batch plugin installation guide to release workflow
- Add 'Installing All Plugins to Your Instance' section to release-workflow.md
- Add '批量安装所有插件到你的实例' section to release-workflow.zh.md
- Include quick start steps for installing all plugins after release
- Direct users to deployment guide for detailed instructions
2026-03-09 21:58:11 +08:00
fujie
d569dc3ec9 chore: remove file 2026-03-09 21:50:33 +08:00
fujie
e2426c74e1 docs: reorganize plugin and prompt installation instructions
- Move 'Using Plugins' section before 'Using Prompts' in all quick start guides
- Update plugin installation options with batch installation script
- Move Prompts section after Plugins in project contents (already correct structure)
- Update docs for English and Chinese versions (README.md, README_CN.md, docs/index.md, docs/index.zh.md)
- Simplify installation flow: Community > Quick Install All > Prompts
2026-03-09 21:48:33 +08:00
fujie
ae0fa1d39a chore: update default port from 3003 to 3000 and improve installation docs
- Change all default port references from 3003 to 3000 across scripts and documentation
- Add quick installation guide for batch plugin installation to main README (EN & CN)
- Simplify installation options by removing manual installation instructions
- Update deployment guides and examples to reflect new default port
2026-03-09 21:42:17 +08:00
fujie
62e78ace5c chore(workflow): optimize release notes formatting and link visibility
- Removed redundant H1 title from automated release generation
- Compacted README links in version change summary to same line
- Streamlined release notes by removing verbose commit logs and redundant guides
- Updated release-prep skill to enforce professional GitHub release standards
2026-03-09 20:52:43 +08:00
fujie
7efb64b16b feat(async-context-compression): release v1.4.0 with structure-aware grouping and session locking
- Introduced Atomic Message Grouping to prevent tool-calling corruption (Issue #56)
- Implemented Tail Boundary Alignment for deterministic context truncation
- Added per-chat asynchronous session locking to prevent duplicate background tasks
- Enhanced summarization traceability with message IDs and names
- Synchronized version and changelog across all documentation files
- Optimized release-prep skill to remove redundant H1 titles

Closes #56
2026-03-09 20:50:24 +08:00
fujie
2eee7c5d35 fix(markdown_normalizer): adopt safe-by-default strategy for escaping
- Set 'enable_escape_fix' to False by default to prevent accidental corruption
- Improve LaTeX display math identification using regex protection
- Update documentation to reflect opt-in recommendation for escape fixes
- Fix Issue #57 remaining aggressive escaping bugs
2026-03-09 01:05:13 +08:00
fujie
9bf31488ae fix(release): correct indentation in Python script for plugin metadata extraction 2026-03-08 20:03:16 +08:00
fujie
ef86a2c3c4 fix(ci): fix EOF here-doc indentation 2026-03-08 19:52:39 +08:00
fujie
b4c6d23dfb fix(ci): fix here-doc syntax error in release workflow 2026-03-08 19:49:50 +08:00
fujie
6102851e55 fix(markdown_normalizer): enhance reliability and code protection
- Fix error fallback mechanism to guarantee 100% rollback to original text on failure
- Improve escape character cleanup to protect inline code blocks from unwanted modification
- Fix 'enable_escape_fix_in_code_blocks' configuration to correctly apply to code blocks when enabled
- Change 'show_debug_log' default to False to reduce console noise and improve privacy
- Update READMEs and docs, bumped version to 1.2.8
2026-03-08 19:48:17 +08:00
fujie
79c1fde217 fix(release): enforce single plugin update per release and improve version tagging 2026-03-08 19:42:13 +08:00
fujie
d29c24ba4a feat(openwebui-skills-manager): enhance auto-discovery and structural refactoring
- Enable default overwrite installation policy for overlapping skills
- Support deep recursive GitHub trees discovery mechanism to resolve #58
- Refactor internal architecture to fully decouple stateless helper logic
- READMEs and docs synced (v0.3.0)
2026-03-08 18:21:21 +08:00
fujie
55a9c6ffb5 docs: include Copilot SDK + Excel Expert demonstration image file 2026-03-07 23:10:30 +08:00
fujie
f11affd3e6 docs: add Copilot SDK + Excel Expert demonstration image to homeboards 2026-03-07 23:06:33 +08:00
fujie
d57f9affd5 docs(skills): add 'publish-no-version-bump' skill for code-only marketplace updates 2026-03-07 22:16:42 +08:00
fujie
f4f7b65792 fix(copilot-sdk): implement dict-based isolated cache and optimize session config
- Fix model list flapping bug by utilizing dictionary-based '_discovery_cache' keyed by config hash instead of wiping a global list.

- Optimize performance by removing redundant disk IO 'config.json' syncing ('_sync_mcp_config' and '_sync_copilot_config'); SDK directly accepts params via 'SessionConfig'.

- Remove unused imports and variables based on flake8 lint rules.
2026-03-07 22:13:58 +08:00
fujie
a777112417 fix(ci): improve release naming and baseline [skip release]
- Derive release names from changed plugin titles instead of using only the version
- Compare releases against the previous published tag across detection and commit sections
- Keep generated release note headings aligned with plugin names in release bodies
2026-03-07 04:52:59 +08:00
fujie
530a6f9459 fix(ci): stop prepending plugin readme to release notes
- Remove the auto-injected Plugin README block from release.yml
- Keep release note files as the first visible content in GitHub releases
- Prevent future releases from surfacing an unnecessary link above the changelog
2026-03-07 04:34:20 +08:00
Fu-Jie
935fa0ccaa Update LICENSE file formatting 2026-03-07 04:31:25 +08:00
fujie
f5a983fb4a feat(github-copilot-sdk): release v0.10.0 with native prompt restoration and live todo widget
- Restore native Copilot CLI prompts for authentic Plan Mode behavior
- Add SQLite-backed session management for state persistence via system prompt
- Implement Adaptive Autonomy (Agent chooses planning vs direct execution)
- Fix OpenWebUI custom tool context injection for v0.8.x compatibility
- Add compact Live TODO widget synchronized with session.db
- Upgrade SDK to github-copilot-sdk==0.1.30
- Remove legacy mode switch RPC calls (moved to prompt-driven orchestration)
- Fix intent status localization and widget whitespace optimization
- Sync bilingual READMEs and all documentation mirrors to v0.10.0
2026-03-07 04:30:15 +08:00
github-actions[bot]
35dec491de chore: update community stats - new plugin added (26 -> 27) 2026-03-06 20:12:54 +00:00
fujie
67de7f1cfc refactor(github-copilot-sdk): expand _get_chat_context to handle session_id and message_id 2026-03-05 18:44:34 +08:00
fujie
b954fbca1d refactor(github-copilot-sdk): synchronize tool extra_params with OpenWebUI 0.8.x standards 2026-03-05 18:44:34 +08:00
fujie
c1411e731d fix(github-copilot-sdk): inject __messages__, __metadata__ and __event_emitter__ into tools 2026-03-05 18:44:34 +08:00
github-actions[bot]
df78f0454b chore: update community stats - new plugin added (25 -> 26) 2026-03-04 17:19:26 +00:00
fujie
d5931fbc5e docs(smart-mind-map-tool): restore fancy note format in READMEs 2026-03-04 23:53:48 +08:00
fujie
af59959ade docs(smart-mind-map-tool): clean up README note format for community posting 2026-03-04 23:42:36 +08:00
fujie
56a6ddd422 feat(smart-mind-map-tool): initial release v1.0.0 with adaptive Rich UI 2026-03-04 23:18:21 +08:00
fujie
eda495e55f refactor(feature-request): simplify template and add plugin dropdown
- Convert Plugin Name from text input to dropdown with all plugins
- Add Tool type option to match bug report template
- Merge Alternatives Considered into Additional Information section
- Combine Motivation fields into single Motivation & Use Case field
- Reduce from 7 to 5 key fields for better UX
- Keep all critical information for feature evaluation
- Consistent structure with bug report template
2026-03-04 05:03:54 +08:00
fujie
3642058292 refactor(bug-report): simplify template for better UX
- Reduce from 17 to 9 key fields
- Merge Expected/Actual Behavior into single Description field
- Combine environment and browser into Operating System & Container field
- Move screenshots to Additional Information section
- Keep core fields essential for bug reproduction (plugin, version, OS, steps)
- Add collapsible debug information guide with frontend/server log instructions
- Improve user experience by reducing form fatigue
- Maintain all critical debugging information
2026-03-04 05:02:04 +08:00
fujie
5b0464dcdd feat(bug-report): add plugin dropdown selector
- Convert Plugin Name from text input to dropdown menu
- Include all current plugins (Actions, Filters, Pipelines, Pipes, Tools)
- Add 'Other / Not Listed' option with fallback text field
- Reduces typos and improves issue categorization accuracy
- Easier plugin-specific issue tracking and statistics
2026-03-04 04:58:12 +08:00
fujie
2aff7f1bf4 fix(bug-report): correct plugin types and environment info
- Change 'Tool (Copilot SDK)' to 'Tool' (Copilot SDK is a Pipe plugin)
- Rename Environment Details field
- Include OS and container/deployment info (Docker, Docker Compose, native, etc)
- Update checklist to reflect container/deployment requirements
- Keep OpenWebUI version as required field
- Ensures proper environment context for issue reproduction
2026-03-04 04:57:24 +08:00
fujie
ba0d63930e refactor(bug-report): simplify to OS info only
- Change Environment Information to Operating System field
- Keep only OS details (Windows/macOS/Linux versions)
- Simplify checklist requirement from full environment to OS info
- Maintains essential debugging information without overhead
2026-03-04 04:55:18 +08:00
fujie
a1568de67b enhance(bug-report): improve issue template with tool type and better logging guidance
- Add Tool (Copilot SDK) as plugin type option
- Add Environment Information field (OS, hardware, deployment)
  - Platform, device type, GPU/hardware, Python version, Docker, deployment method
- Add detailed Debug Logs & Troubleshooting guide with:
  - Frontend console logs (with steps to enable Plugin Debug Output)
  - Server-side logs (docker logs or local terminal)
- Separate Frontend Console Logs field with debug output instructions
- Add Server-Side Logs field for backend error tracking
- Add Screenshots field with guidance on what to capture
- Enhanced Checklist with environment and logs requirements
- Improves issue triage and faster bug resolution
2026-03-04 04:54:53 +08:00
fujie
f4a38a7906 feat: add issue templates for bug reports and feature requests
- Add bug_report.yml template with plugin-specific fields
- Add feature_request.yml template for enhancement suggestions
- Add config.yml to customize issue creation experience
- Templates help standardize issue reporting and improve triage
2026-03-04 04:51:40 +08:00
fujie
2e6c61737f fix(workflow): only trigger release on actual version changes
- Remove doc-only change trigger to prevent unnecessary releases
- Release should only be created when plugin versions actually change
- Keeps manual workflow_dispatch and tag-based releases intact
2026-03-04 04:45:32 +08:00
fujie
c1e9aca5dc feat(pipes/github-copilot-sdk): add strict file link validation rules
- Add Strict Link Validity Rule (CRITICAL) forbidding fabricated URLs
- Implement Failure Handling for non-successful publish operations
- Establish Allowed Link Formats (Whitelist) with exact patterns
- Define Invalid Link Examples (Forbidden) including /c/... and relative paths
- Add Auto-Correction Rule requiring discard of non-whitelisted links
- Enhance URL Format guidance to emphasize verbatim copying without modification
- Add Workspace Visibility Hint (#10) for workspace file inspection context
2026-03-04 04:14:48 +08:00
Fu-Jie
6f700fe610 Fix capitalization in README description
Corrected capitalization of 'OpenWebUI' to 'open-webui'.
2026-03-04 04:11:16 +08:00
fujie
3927e384cc docs(skill): add open-terminal project to source-code-analyzer 2026-03-04 02:20:24 +08:00
fujie
e1dac2219e fix(stats): stabilize Top6 version badges and fix Excel version display [skip release]
- replace rank-based p{idx}_version usage with per-post static version badge generation

- set Export to Excel version badge to v0.3.7 in home README and README_CN
2026-03-04 01:59:31 +08:00
fujie
9436364b9a docs(readme): restore version badge for Copilot SDK; ci: add skip-release support and README link injection [skip release]
- add static v0.9.1 badge to Copilot SDK Star Features heading

- inject plugin README link before each embedded v*.md in release body

- skip release workflow when commit message contains [skip release]
2026-03-04 01:34:24 +08:00
fujie
e7b1ff4c54 docs(readme): clean up Star Features badges and fix Copilot SDK stats badge keys
- remove all Market badges from Star Features headings

- replace invalid p0_dl/p0_vw placeholders with correct per-post MD5-keyed Gist badges

- remove GitHub Copilot SDK row from Top 6 table (not in ranked stats yet)
2026-03-04 01:20:35 +08:00
fujie
c4ff4fea7e ci(release): reorder release body and improve commits format
- move v*.md release notes to top of release body

- commits now show subject (bold) + body lines per Conventional Commits best practice
2026-03-04 01:19:34 +08:00
fujie
32afc3286e ci(release): fix release notes format
- remove file path header (### plugins/...) from embedded release note content

- exclude _CN.md files to avoid Chinese/English mixed output

- remove Documentation Changes file list and Additional Documentation Files section
2026-03-04 01:06:54 +08:00
fujie
3e8b15af46 ci(release): include documentation content in release body
- embed changed v*.md release note content into generated GitHub release notes

- keep additional doc changes visible as file list in release output

- refine v0.9.1 EN/CN release notes to include only actual updated/fixed items
2026-03-04 00:57:18 +08:00
fujie
658f37baa6 ci(release): optimize plugin release workflow
- detect both version changes and plugin/docs release-note updates

- broaden push path filters and include documentation change summary in release notes

- harden worktree temp handling, remove duplicate extraction, and skip tag creation on tag-triggered runs
2026-03-04 00:52:07 +08:00
fujie
c65ba57553 chore(release): finalize github-copilot-sdk v0.9.1 prep
- sync bilingual plugin READMEs, docs mirrors, and root highlight sections for v0.9.1

- add comprehensive EN/CN release notes covering features, fixes, docs, and i18n updates

- enforce full-coverage release-note rule in release-prep skill for future releases
2026-03-04 00:47:48 +08:00
fujie
7c17dbbe23 style(pipes): unify entity name to 'Agent' across all languages
- Replaced 'Assistant' and its translations with 'Agent' in all translation dictionaries (EN, ZH, JA, KO, FR, DE, IT, ES, RU, VI, ID)
- Consistent with the previous change in Chinese locales.
2026-03-04 00:17:19 +08:00
fujie
c6279240b9 fix(pipes): fix mcp tool filtering and force-enable autonomous web search
- Fix issue where mcp tool filtering logic (function_name_filter_list) in admin backend caused all tools to be hidden due to ID prefix mismatch
- Force enable web_search tool for Copilot Agent regardless of UI toggles, providing full autonomy for search-related intents
- Updated README and version to v0.9.1
2026-03-04 00:11:28 +08:00
fujie
a8a324500a Refactor code structure for improved readability and maintainability 2026-03-03 19:36:53 +08:00
fujie
369e8c900c fix(stats): restore dynamic badges and update community statistics
- Recover dynamic Shields.io badges in README by restoring missing Gist ID 'db3d95687075a880af6f1fba76d679c6'.
- Add 'tool' to DOWNLOADABLE_TYPES and implement TYPE_ALIASES for normalization (mapping 'tools' to 'tool').
- Update community statistics and Ranking list (Top 6) based on latest marketplace data.
- Refactor openwebui_stats.py with 100% English comments and enhanced user ID auto-resolution.
- Verify Smart Mind Map (#1) and other top plugins maintain correct sorting.
2026-03-03 19:29:34 +08:00
fujie
83e317a335 docs(skills): align doc-mirror-sync docs-only guidance
- Add docs-only sync mode rules (no version bump, no release actions).

- Add EN-only and EN+ZH sync command examples.

- Keep .github and .gemini skill instructions in sync.
2026-02-28 23:24:26 +08:00
fujie
c28c3c837b docs(openwebui-skills-manager): prioritize official marketplace install
- Update bilingual plugin README to use official marketplace as default install path.

- Keep manual paste installation as fallback and sync docs mirrors.

- Keep version unchanged at 0.2.1.
2026-02-28 23:20:30 +08:00
fujie
701ea0b18f fix(openwebui-skills-manager): replace broken install example URLs
- Replace non-existent anthropics skills paths with valid xlsx/docx examples.

- Keep English and Chinese README examples synchronized.
2026-02-28 23:13:16 +08:00
fujie
eb79bc9633 fix(tools): release openwebui-skills-manager v0.2.1
- Add GitHub skills-directory auto-discovery for install_skill batch install from tree root URLs.

- Harden language detection with frontend-first fallback (__event_call__ + timeout), then headers/profile.

- Bump plugin/docs versions to 0.2.1 and sync bilingual README/docs/index entries.
2026-02-28 23:06:08 +08:00
fujie
0c7d427b93 chore: cleanup debug files and update plugin configuration 2026-02-28 16:39:41 +08:00
fujie
07bc5f027e feat(skills-manager): add openwebui_id and fix tool type sync bug 2026-02-28 16:14:38 +08:00
fujie
701fc3e906 docs(skills-manager): add skill installation examples for single and batch URLs 2026-02-28 15:53:04 +08:00
fujie
d392af66c9 chore: rename update_pipe.py to deploy_pipe.py to reflect its creation capabilities and update skills reference 2026-02-28 15:29:46 +08:00
fujie
67cf86fb26 fix(pipes): yield artifacts string directly to stream flow avoiding emitter replacement 2026-02-28 15:21:28 +08:00
fujie
fe98b0e007 fix(pipes): fallback artifacts mode to using direct view_url iframe to bypass openwebui srcdoc sandbox cdn crash 2026-02-28 14:58:56 +08:00
fujie
3236d19e28 fix(pipes): restore corrupted isinstance check + add frontend console debug tracing 2026-02-28 14:35:53 +08:00
fujie
354c1eee6b chore(pipes): add debug tracing for pending_embeds lifecycle 2026-02-28 14:30:38 +08:00
fujie
6b3eb8064b fix(pipes): align artifacts internal array type tracking with stream loops 2026-02-28 14:17:05 +08:00
fujie
f32e90e182 feat(pipes): automate artifacts html generation via emitter message append 2026-02-28 13:48:53 +08:00
fujie
8001ab18ee feat(pipes): update richui mode to send raw HTML content instead of an iframe tag 2026-02-28 13:11:03 +08:00
fujie
dcfde9c0dc fix(pipes): revert artifacts iframe to barebone structure to avoid OpenWebUI markdown parsing issues 2026-02-28 13:06:10 +08:00
fujie
dbcf7421ea feat(pipes): simplify richui iframe tag to give full styling control to openwebui emitter 2026-02-28 13:04:10 +08:00
fujie
1705baf976 feat(pipes): unrestrict richui iframe height and apply generous sandbox policies 2026-02-28 13:01:38 +08:00
fujie
8e8d478ece fix(pipes): inject explicit sandbox policies to artifacts iframe to mitigate client-side block 2026-02-28 12:57:22 +08:00
fujie
acc9cd7ff2 fix(pipes): clarify ANTI-INLINE rule to allow iframe output and hardcode iframe shadow 2026-02-28 12:37:49 +08:00
fujie
e4582c3197 feat(pipes): optimize richui vs artifacts selection and enforce fullscreen button 2026-02-28 12:23:10 +08:00
fujie
d0eb72467d feat(pipes): enforce ANTI-INLINE HTML generation rule 2026-02-28 12:16:19 +08:00
fujie
6b6e62398a docs: add skill demo GIF asset 2026-02-28 06:12:13 +08:00
fujie
fd22ed8fa0 docs: use .gif instead of .mov for Skill demo in README 2026-02-28 05:51:02 +08:00
fujie
4fccd1893e docs: use absolute raw GitHub URL for video embedding 2026-02-28 05:44:21 +08:00
fujie
a74e03fff8 docs: use HTML video tag for README video embedding compatibility 2026-02-28 05:41:38 +08:00
fujie
850838226d docs: add skill visual agent demo video to home README 2026-02-28 05:37:04 +08:00
fujie
a52ac34d59 refactor(pipes): add video (MOV/MP4) embedding support to instructions 2026-02-28 05:12:50 +08:00
fujie
3263ab9db6 docs: enhance GitHub Copilot SDK Pipe description in home READMEs
- highlight autonomous agent capabilities
- add v0.9.0 key leaps: Skills Revolution, Secure Isolation, Interactive Delivery
2026-02-28 05:10:39 +08:00
fujie
7c7daef30b refactor(pipes): optimize gif embedding and detection
- update BASE_GUIDELINES to explicitly allow direct GIF embedding
- update publish_file_from_workspace to support common image formats
2026-02-28 04:56:28 +08:00
fujie
64754ba26b refactor(pipes): optimize artifacts prompt for HTML embeds
- Explicitly instruct AI to wrap iframe in html code blocks in artifacts mode
- Clarify guidelines to distinguish between artifacts and richui delivery
2026-02-28 04:16:55 +08:00
github-actions[bot]
4188410d61 chore: update community stats - new plugin added (24 -> 25) 2026-02-27 20:12:34 +00:00
Fu-Jie
0c7201902c feat(github-copilot-sdk): add workspace skills support (v0.9.0) (#51)
* feat(github-copilot-sdk): add workspace skills support

- Introduce ENABLE_WORKSPACE_SKILLS valve to enable/disable workspace custom tools discovery
- Modify _build_session_config() to auto-load tools from .copilot-skills/ directory
- Add workspace_skills_example.py template with 3 working example tools
- Update README.md and README_CN.md with Workspace Skills guide and usage examples
- Create v0.9.0.md and v0.9.0_CN.md release notes
- Sync version to all docs files (index.md, index.zh.md, and main docs)
- Bump version from 0.8.0 to 0.9.0 across all 7+ locations

* docs: establish temp files handling policy (project-based, not /tmp)

- Add TEMP_FILES_POLICY.md guideline for all skills and workflows
- Update pr-submitter skill to use .temp/ directory instead of /tmp
- Update release-prep skill documentation with temp file convention
- Add .temp/ and .build/ entries to .gitignore
- Create internal policy memo in /memories/repo/

This policy ensures:
- All temporary files stay within project workspace (not system /tmp)
- Alignment with OpenWebUI workspace isolation principles
- Multi-user safety and cleanup traceability
- Consistent handling across all skills and development workflows

* fix(terminology): rename 'workspace skills' to 'workspace custom tools' for accuracy

The term 'Skills' in Anthropic context refers to instruction-based frameworks
(SKILL.md files with YAML frontmatter + markdown), not custom tool functions.

Our implementation uses @define_tool decorator to define custom tools that the
SDK auto-discovers from .copilot-skills/ directory. These are Tools, not Skills.

Changes:
- Rename ENABLE_WORKSPACE_SKILLS valve -> ENABLE_WORKSPACE_TOOLS
- Update all documentation (README, README_CN, docs, release notes)
- Fix section headings and descriptions throughout
- Ensure consistent terminology across all files

This is a terminology-only change; functionality remains identical.

* feat(pipes): release v0.9.0 of GitHub Copilot SDK Pipe

- Integrated OpenWebUI Skills Bridge and manage_skills tool
- Reinforced status bar stability with session_finalized logic
- Added persistent SDK config directory support

* docs(pipes): add comprehensive guides and v0.9.0 notes for Copilot SDK

- Added skill manager and best practices guides
- Added publishing tool documentation
- Included v0.9.0 release notes and deployment script
- Updated usage guides
2026-02-28 03:50:56 +08:00
Fu-Jie
f47c3f6354 Fix formatting for Open WebUI Prompt Plus entry
Updated README.md to improve formatting of the Open WebUI Prompt Plus section.
2026-02-26 13:15:49 +08:00
Copilot
272245d911 docs: add OOpenWebUI official newsletter featured recognition to Smart Mind Map, Markdown Normalizer, and Prompt Plus (#52)
* Initial plan

* docs: add OpenWebUI official newsletter featured recognition

- Add newsletter featured callout to Smart Mind Map README.md, README_CN.md, and docs
- Add newsletter featured callout to Markdown Normalizer README.md, README_CN.md, and docs
- Add newsletter featured badge to Prompt Plus in root README.md and README_CN.md
- Reference both newsletters: Jan 28, 2026 and Feb 3, 2026

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>

* docs: fix newsletter links to match actual featured issue per plugin

- Smart Mind Map: link only to Feb 3, 2026 (second newsletter)
- Markdown Normalizer: link only to Jan 28, 2026 (first newsletter)
- Prompt Plus (root READMEs): already correct, no change needed

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-26 13:12:13 +08:00
fujie
ce93464f47 chore(skills): sync all github copilot skills to gemini 2026-02-26 01:42:13 +08:00
fujie
c658e379c0 docs(skills): clarify community-publisher is for new posts only 2026-02-26 01:41:25 +08:00
fujie
ab28465dd5 feat(skills): add openwebui-community-publisher skill 2026-02-26 01:33:49 +08:00
github-actions[bot]
d22ba88f33 chore: update community stats - new plugin added (23 -> 24) 2026-02-25 17:28:32 +00:00
Fu-Jie
db33f44cbc feat(plugins): release Copilot SDK Pipe v0.8.0 and Files Filter v0.1.3 (#50)
* feat(plugins): release copilot sdk pipe v0.8.0 and files filter v0.1.3

- Add P1~P4 conditional tool filtering and admin/server gating behavior

- Fix artifact publishing reliability, strict /api file URLs, and HTML preview/download delivery

- Update bilingual README/docs, release notes, and filter matching/debug improvements

* fix(docs): remove duplicate code block in tool-filtering zh doc

- Remove incorrectly placed duplicate 'if not is_enabled: continue' block
  outside code fence on line 161-163 of copilot-sdk-tool-filtering.zh.md
- Addresses review comment from gemini-code-assist (#50)
2026-02-26 01:05:31 +08:00
fujie
5b6dddd517 docs(agent): sync source-code-analyzer skill to .github/skills 2026-02-24 23:08:18 +08:00
fujie
c8ba7c99af feat(agent): inject source-code-analyzer skill and update repo rules
- Add source-code-analyzer skill with global/plugin-specific paths\n- Update GEMINI.md with External Auth and Source Sensing rules\n- Explicitly authorize Antigravity to read core component source code
2026-02-24 23:07:44 +08:00
fujie
81279845e2 chore(skills): sync .gemini and .github skills and fix i18n validator 2026-02-24 22:19:48 +08:00
fujie
6b39531fbc feat(skills): add 6 generalized AI-driven development skills
- version-bumper: automated multi-file version synchronization
- plugin-scaffolder: standardized 12-language i18n template generation
- doc-mirror-sync: automated README to docs mirroring
- i18n-validator: dictionary key alignment analysis via AST
- gh-issue-replier: professional English reply with star-check logic
- gh-issue-scheduler: unanswered issue audit and action planning
2026-02-24 16:02:01 +08:00
fujie
377534e6c9 feat(project): sync engineering standards and finalize markdown-normalizer v1.2.7
- Update .github/copilot-instructions.md with latest i18n and naming standards
- Add docs/development/issue-reply-guide.md for professional community engagement
- Sync all documentation (MKDocs, READMEs, Docs) to v1.2.7
- Include CI/CD and Agent instruction templates for better automation
2026-02-24 15:13:52 +08:00
fujie
2da934dd92 feat(filters): upgrade markdown-normalizer to v1.2.7
- Fix Issue #49: resolve greedy regex matching in consecutive emphasis
- Add LaTeX formula protection to prevent corruption of \times, \nu, etc.
- Expand i18n support to 12 languages with strict alignment
- Fix NameError in Request import during testing
2026-02-24 15:05:25 +08:00
fujie
18ada2a177 docs: fix table header alignment and column count in READMEs 2026-02-23 14:43:28 +08:00
fujie
a5fbc8bed9 docs: add Actively Developed Projects section with GitHub Copilot SDK Pipe 2026-02-23 14:42:14 +08:00
github-actions[bot]
904eeb0ad0 chore: update community stats - new plugin added (22 -> 23) 2026-02-22 19:12:33 +00:00
fujie
9c70110e1d docs: refine wording in English v0.7.0.md (use UI instead of interface) 2026-02-23 02:42:58 +08:00
fujie
9af6a8c9bd docs: refine wording in v0.7.0_CN.md (UI instead of interface) 2026-02-23 02:42:10 +08:00
fujie
ac948023e3 docs: add Chinese version of v0.7.0 post 2026-02-23 02:41:19 +08:00
fujie
512b606827 docs: add emoji and subtitle to v0.7.0.md 2026-02-23 02:40:24 +08:00
fujie
fc9f1ccb43 feat(pipes): v0.7.0 final release with native tool UI and CLI integration
- Core: Adapt to OpenWebUI native tool call UI and thinking process visualization
- Infra: Bundle Copilot CLI via pip package (no more background curl installation)
- Fix: Resolve "Error getting file content" on OpenWebUI v0.8.0+ via absolute paths
- i18n: Add native localization for status messages in 11 languages
- UX: Optimize reasoning status display logic and cleanup legacy code
2026-02-23 02:33:59 +08:00
fujie
272b959a44 fix(actions): fix white background bleed in dark mode when viewport is narrow 2026-02-22 00:24:37 +08:00
fujie
0bde066088 fix: correct Top 6 plugin name-data mapping to match Gist badge order 2026-02-22 00:10:04 +08:00
fujie
6334660e8d docs: add root README update date sync rule to consistency maintenance 2026-02-22 00:06:43 +08:00
fujie
c29d84f97a docs: update Smart Mind Map release date in root readmes to 2026-02-22 2026-02-22 00:02:51 +08:00
fujie
aac2e89022 chore: update smart mind map plugin image. 2026-02-22 00:00:19 +08:00
fujie
fea812d4f4 ci: remove redundant release title from github release body 2026-02-21 23:49:36 +08:00
fujie
b570cbfcde docs(filters): fix broken link to workflow guide in mkdocs strict build 2026-02-21 23:47:48 +08:00
fujie
adc5e0a1f4 feat(filters): release v1.3.0 for async context compression
- Add native i18n support across 9 languages
- Implement non-blocking frontend log emission for zero TTFB delay
- Add token_usage_status_threshold to intelligently control status notifications
- Automatically detect and skip compression for copilot_sdk models
- Set debug_mode default to false for a quieter production environment
- Update documentation and remove legacy bilingual code
2026-02-21 23:44:12 +08:00
fujie
04b8108890 chore: ignore and stop tracking .git-worktrees 2026-02-21 21:50:35 +08:00
fujie
f1ba03e3bd Merge remote-tracking branch 'origin/main' into copilot/sub-pr-42
# Conflicts:
#	plugins/actions/smart-mind-map/README.md
#	plugins/actions/smart-mind-map/README_CN.md
#	plugins/actions/smart-mind-map/smart_mind_map.py
#	plugins/actions/smart-mind-map/smart_mind_map_cn.py
2026-02-21 18:04:48 +08:00
fujie
cdd9950973 docs: update pr submission guidelines to require gh tool 2026-02-21 17:54:09 +08:00
fujie
473012fa6f feat(actions): release Smart Mind Map v1.0.0 - a milestone with Native i18n & Direct Embed 2026-02-21 17:50:44 +08:00
fujie
1bbddb2222 feat(pipe): show Copilot CLI install progress during first run 2026-02-15 00:18:27 +08:00
copilot-swe-agent[bot]
dc66610cb2 docs: Align with copilot-instructions.md standards and update all repo references
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-13 03:36:30 +00:00
copilot-swe-agent[bot]
655b5311cf chore: Update repository references from awesome-openwebui to openwebui-extensions
Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-13 03:31:06 +00:00
copilot-swe-agent[bot]
4390ee2085 Initial plan 2026-02-13 03:29:45 +00:00
fujie
6bf3656d30 docs: rename Awesome OpenWebUI and OpenWebUI Extras to OpenWebUI Extensions 2026-02-13 11:10:48 +08:00
google-labs-jules[bot]
bfb2039095 feat: Add full i18n support, security fixes, and zh-TW to Smart Mind Map plugin
- Consolidated smart_mind_map.py and smart_mind_map_cn.py into a single file.
- Added TRANSLATIONS dictionary supporting 18 languages (including explicit zh-TW support).
- Implemented robust language detection with fallback to browser/local storage.
- Added localized date formatting for various locales.
- Added base language fallback (e.g., fr-BE -> fr-FR) and variant mapping.
- Fixed critical security vulnerabilities:
    - Prevented JS injection by safely escaping IDs with `json.dumps`.
    - Prevented XSS by sanitizing user input and language codes.
    - Prevented DoS crashes from curly braces in LLM output by replacing `.format()` with safe string replacement.
- Fixed regex regression by using standard strings with escaped backslashes.
- Restored clickable "Markmap" link in the footer.
- Verified all changes with comprehensive unit and security tests.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 21:05:45 +00:00
google-labs-jules[bot]
86091f77cf feat: Security and i18n improvements for Smart Mind Map plugin
- Fixed high-severity XSS and JS injection vulnerabilities by safely escaping IDs and user input using `json.dumps` and HTML entity encoding.
- Prevented potential DoS crashes caused by curly braces in LLM output by replacing `.format()` with safe string replacement.
- Refactored language resolution into a `_resolve_language` helper method, implementing base language fallback (e.g., `fr-BE` -> `fr-FR`).
- Refactored date formatting to use a cleaner, dictionary-based approach.
- Consolidated i18n logic into a single file with robust fallback handling.
- Verified all changes with comprehensive unit and security tests.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 17:41:52 +00:00
google-labs-jules[bot]
eb223e3e75 feat: Add full i18n support to Smart Mind Map plugin
- Consolidated smart_mind_map.py and smart_mind_map_cn.py into a single file.
- Added TRANSLATIONS dictionary supporting 18 languages (en-US, ko-KR, fr-FR, es-AR, en-CA, fr-CA, ja-JP, de-DE, zh-HK, it-IT, zh-CN, en-GB, es-MX, id-ID, es-ES, de-AT, en-AU, vi-VN, zh-TW).
- Implemented automatic language detection with fallback to browser/local storage.
- Added localized date formatting for various locales.
- Added explicit support for zh-TW (Traditional Chinese) with correct translations.
- Updated HTML/JS templates to use injected translations.
- Restored clickable "Markmap" link in the footer for all languages.
- Fixed SyntaxWarning in regex strings by properly escaping backslashes in standard strings.
- Implemented robust UI translation loading to prevent crashes on missing keys.
- Verified frontend rendering with Playwright and backend logic with unit tests.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 17:15:50 +00:00
google-labs-jules[bot]
d1bbbd9071 feat: Add full i18n support to Smart Mind Map plugin
- Consolidated smart_mind_map.py and smart_mind_map_cn.py into a single file.
- Added TRANSLATIONS dictionary supporting 18 languages (en-US, ko-KR, fr-FR, es-AR, en-CA, fr-CA, ja-JP, de-DE, zh-HK, it-IT, zh-CN, en-GB, es-MX, id-ID, es-ES, de-AT, en-AU, vi-VN, zh-TW).
- Implemented automatic language detection with fallback to browser/local storage.
- Added localized date formatting for various locales.
- Added explicit support for zh-TW (Traditional Chinese) with correct translations.
- Updated HTML/JS templates to use injected translations.
- Restored clickable "Markmap" link in the footer for all languages.
- Fixed SyntaxWarning in regex strings.
- Verified frontend rendering with Playwright.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 17:06:28 +00:00
google-labs-jules[bot]
840c77ea2f feat: Add full i18n support to Smart Mind Map plugin
- Consolidated smart_mind_map.py and smart_mind_map_cn.py into a single file.
- Added TRANSLATIONS dictionary supporting 18 languages (including explicit zh-TW support).
- Implemented automatic language detection with fallback to browser/local storage.
- Added localized date formatting for various locales.
- Added fallback mapping for regional variants (e.g., es-AR -> es-ES).
- Updated HTML/JS templates to use injected translations.
- Fixed SyntaxWarning in regex strings.
- Verified frontend rendering with Playwright and backend logic with unit tests.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 16:54:48 +00:00
google-labs-jules[bot]
91ba7df086 feat: Add full i18n support to Smart Mind Map plugin
- Consolidated smart_mind_map.py and smart_mind_map_cn.py into a single file.
- Added TRANSLATIONS dictionary supporting 17 languages (en-US, ko-KR, fr-FR, es-AR, en-CA, fr-CA, ja-JP, de-DE, zh-HK, it-IT, zh-CN, en-GB, es-MX, id-ID, es-ES, de-AT, en-AU, vi-VN).
- Implemented automatic language detection with fallback to browser/local storage.
- Added localized date formatting for various locales.
- Added fallback mapping for regional variants (e.g. zh-TW -> zh-HK, es-AR -> es-ES).
- Updated HTML/JS templates to use injected translations.
- Fixed SyntaxWarning in regex strings.
- Verified frontend rendering with Playwright.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 16:46:27 +00:00
google-labs-jules[bot]
fa636c7bc5 feat: Add full i18n support to Smart Mind Map plugin
- Consolidated smart_mind_map.py and smart_mind_map_cn.py into a single file.
- Added TRANSLATIONS dictionary supporting 17 languages (en-US, ko-KR, fr-FR, es-AR, en-CA, fr-CA, ja-JP, de-DE, zh-HK, it-IT, zh-CN, en-GB, es-MX, id-ID, es-ES, de-AT, en-AU, vi-VN).
- Implemented automatic language detection with fallback to browser/local storage.
- Added localized date formatting for various locales.
- Updated HTML/JS templates to use injected translations.
- Fixed SyntaxWarning in regex strings.
- Verified frontend rendering with Playwright.

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
2026-02-12 16:33:04 +00:00
fujie
a5ad295d38 ci: clean up unused variables in stats workflow 2026-02-11 14:19:28 +08:00
fujie
e1f70d52a5 ci: remove push trigger for merged feature branch 2026-02-11 14:15:58 +08:00
fujie
015c22063a ci: remove fetch-depth 0, history data already persisted in Gist 2026-02-11 14:14:55 +08:00
fujie
0ea95ceefa feat: 自动化统计系统重构 - 动态徽章 + Gist SVG 图表 + 历史数据恢复 2026-02-11 14:11:26 +08:00
fujie
1192c71453 fix: merge Gist+local history and rebuild from community-stats.json 2026-02-11 14:04:03 +08:00
fujie
0b5663636f chore: hydrate stats history with recovered data (38 days record) 2026-02-11 14:00:17 +08:00
fujie
1736a1bfbf feat: auto-rebuild stats history from git logs if local/gist data is missing 2026-02-11 13:53:55 +08:00
fujie
d7c25aa973 fix: relax history requirements for chart generation 2026-02-11 13:50:42 +08:00
fujie
d71b4a7351 chore: add logging to upload_chart_svg to debug silent failure 2026-02-11 13:49:08 +08:00
fujie
a05697df70 fix: correct vl_spec syntax and use POST for Kroki 2026-02-11 13:47:23 +08:00
fujie
b355c3f0c1 feat: implement SVG generation and Gist upload logic in stats script 2026-02-11 13:42:27 +08:00
fujie
30f2aed68a feat: switch to static Gist SVG for activity chart (no more daily README commits) 2026-02-11 13:41:41 +08:00
fujie
50c549b260 chore: apply dynamic version badges to README 2026-02-11 13:36:28 +08:00
fujie
2a75580831 style: apply colored badges to post type statistics in docs 2026-02-11 13:36:05 +08:00
fujie
4032746243 style: enhance stats docs with colored badges for post types 2026-02-11 13:34:14 +08:00
fujie
871e76b1df chore: manual stats update (latest history & chart) 2026-02-11 13:32:27 +08:00
fujie
954ebad8b2 feat: sync docs chart with README chart (Vega-Lite) 2026-02-11 13:31:14 +08:00
fujie
fa5d962152 feat: use dynamic badges for plugin versions, remove version changes as commit trigger 2026-02-11 13:28:19 +08:00
fujie
2ac8d4b14f ci: remove points and followers as commit triggers since they are now dynamic badges 2026-02-11 13:26:00 +08:00
fujie
c86b27a0c1 ci: add dedicated daily workflow for chart updates at 01:10 Beijing time 2026-02-11 13:24:17 +08:00
fujie
2381c5080e fix: revert chart to embedded data - Kroki server-side rendering cannot fetch external URLs 2026-02-11 13:23:05 +08:00
fujie
0394be7d16 chore: update READMEs and docs with stable Gist-based chart URL 2026-02-11 13:18:51 +08:00
fujie
7c9bf4082a feat: sync activity chart in docs with README configuration 2026-02-11 13:16:02 +08:00
fujie
8621d178ae feat: restore external Gist data source for stable chart URL 2026-02-11 13:11:54 +08:00
fujie
20a7d57b5b fix: revert to embedded activity chart data to resolve loading failures 2026-02-11 13:09:23 +08:00
fujie
8f72e25671 perf: use external Gist data source for trend chart to keep URL static 2026-02-11 13:04:36 +08:00
fujie
b7e62e63e0 docs: restore missing language switcher in README 2026-02-11 12:59:08 +08:00
fujie
bbccffa95b style: move activity chart to end of stats section and add updated badge to top6 table 2026-02-11 12:56:30 +08:00
fujie
b9104702ac fix: use dynamic badges for auto-updated timestamp to ensure real-time accuracy 2026-02-11 12:54:45 +08:00
fujie
015b0d98ec style: embed full-history activity chart into stats section and refine top 6 table 2026-02-11 12:52:14 +08:00
fujie
fc56ea7faa style: move activity chart to bottom and use vega-lite for better visuals 2026-02-11 12:46:24 +08:00
fujie
e1c2261537 fix: implement safe badge keys and add dynamic upvote/save badges 2026-02-11 12:41:16 +08:00
fujie
93e8e3bee2 fix: remove duplicate saves entry and restore comments entry formatting 2026-02-11 12:37:51 +08:00
fujie
1fb2cccd58 fix: resolve type error in gist sync and implement full English localization for charts 2026-02-11 12:35:45 +08:00
fujie
b34ce0b075 docs: finalize Zero-Commit dynamic reports with Kroki charts and dynamic badges 2026-02-11 12:29:39 +08:00
fujie
49efcb7e4d feat: implement Zero-Commit dynamic Mermaid charts via Kroki server-side rendering 2026-02-11 12:26:09 +08:00
fujie
8d334a48b9 feat: transition stats hosting to Gist-first model to minimize repository commits 2026-02-11 12:23:10 +08:00
fujie
16882bf9e5 data: finalize community stats with full historical data and dynamic badges 2026-02-11 12:21:56 +08:00
fujie
dc0366aab2 feat: enable live stats for community reports via Gist dynamic badges 2026-02-11 12:19:16 +08:00
fujie
6d080d3a28 data: reconstruct full stats history from git logs and update reports 2026-02-11 12:15:22 +08:00
fujie
e50a55ee11 feat: enhance Mermaid visualizations with multi-series trends, distribution pie, and impact analysis 2026-02-11 12:13:29 +08:00
fujie
edbd75e5dc fix: URL encode Gist raw endpoints for reliable Shields.io badge rendering 2026-02-11 12:12:37 +08:00
fujie
387ca8788b feat: use dynamic badges for Top 6 plugin statistics in README 2026-02-11 12:10:46 +08:00
fujie
cfb15808ef docs: finalize dynamic stats badges in READMEs 2026-02-11 12:09:11 +08:00
fujie
0424521380 feat: complete no-commit update system with dynamic badges and history sync 2026-02-11 12:08:05 +08:00
fujie
c2ea3b2479 feat: migrate stats display to dynamic Shields.io badges via Gist 2026-02-11 12:05:52 +08:00
fujie
a96a588141 style: reformat README stats section for better clarity and premium look 2026-02-11 12:01:54 +08:00
fujie
f34da0b263 feat: include per-post download stats in historical snapshots 2026-02-11 11:59:56 +08:00
fujie
80dce6e1de fix: compatibility with Python < 3.12 for f-strings with backslashes 2026-02-11 11:58:44 +08:00
fujie
080534d03b feat: implement Gist-based history tracking and enhanced stats categorization 2026-02-11 11:57:07 +08:00
fujie
a63d3e89ff feat: implement stats history, growth tracking, and mermaid trend charts 2026-02-11 11:41:12 +08:00
github-actions[bot]
0b9c242c0f chore: update community stats - points increased (270 -> 271) 2026-02-11 03:11:02 +00:00
github-actions[bot]
6f7ae4a304 chore: update community stats - points increased (269 -> 270) 2026-02-10 23:19:32 +00:00
github-actions[bot]
571adf33c5 chore: update community stats - points increased (268 -> 269), followers increased (219 -> 220) 2026-02-10 21:20:45 +00:00
github-actions[bot]
813e2b8320 chore: update community stats - followers increased (218 -> 219) 2026-02-10 20:19:43 +00:00
github-actions[bot]
21ec586c68 chore: update community stats - points increased (266 -> 268), followers increased (217 -> 218) 2026-02-10 15:32:07 +00:00
fujie
e95a786420 docs: add core practical examples (Star Prediction & Video Processing) to README 2026-02-10 23:07:44 +08:00
github-actions[bot]
7773723b18 chore: update community stats - new plugin added (21 -> 22), plugin version updated, points increased (262 -> 266) 2026-02-10 14:35:09 +00:00
fujie
c547c1cee5 docs: fix broken relative links in example cases to resolve mkdocs build warnings 2026-02-10 21:41:15 +08:00
fujie
b04112a261 docs: add GitHub Copilot SDK pipe masterclass cases and documentation updates 2026-02-10 21:38:54 +08:00
github-actions[bot]
df977a7ccc chore: update community stats - followers increased (216 -> 217) 2026-02-10 10:26:05 +00:00
fujie
3986eb854f docs: modernize file delivery protocol and update tutorials 2026-02-10 17:01:18 +08:00
fujie
fe170bedb9 chore: remove sample_sales_data.csv (accidentally committed) 2026-02-10 16:23:20 +08:00
fujie
3504313f15 docs(workflow): optimize release format to English-only changelog 2026-02-10 16:20:47 +08:00
github-actions[bot]
e5e0f4cbcc chore: update community stats - plugin version updated 2026-02-10 07:30:30 +00:00
fujie
a7b244602f feat(pipe): release v0.6.2 - full-lifecycle file agent support 2026-02-10 14:55:16 +08:00
github-actions[bot]
3343e73848 chore: update community stats - followers increased (215 -> 216) 2026-02-10 04:51:12 +00:00
github-actions[bot]
7ab3e51d6f chore: update community stats - followers increased (214 -> 215) 2026-02-10 03:11:20 +00:00
github-actions[bot]
303d21c73d chore: update community stats - followers increased (213 -> 214) 2026-02-09 21:18:32 +00:00
github-actions[bot]
054af87e6e chore: update community stats - points increased (261 -> 262), followers increased (212 -> 213) 2026-02-09 19:34:12 +00:00
github-actions[bot]
991570d025 chore: update community stats - plugin version updated 2026-02-09 17:24:09 +00:00
fujie
5a5261d184 chore(release): bump github-copilot-sdk to 0.6.1 and update READMEs/CHANGELOG 2026-02-10 01:04:13 +08:00
fujie
8cdc7723d2 docs(pipes): update github-copilot-sdk README version to 0.6.1 2026-02-10 01:04:02 +08:00
github-actions[bot]
a167f51026 chore: update community stats - followers increased (211 -> 212) 2026-02-09 15:25:46 +00:00
fujie
03ff69f9e0 docs: synchronize README_CN.md with the latest premium layout and market links 2026-02-09 22:12:21 +08:00
fujie
62c69a9a41 fix: restore <b> tags in summary for proper rendering on GitHub 2026-02-09 22:09:14 +08:00
fujie
9bf2a5d2a2 docs: link Star Features titles to OpenWebUI Community market 2026-02-09 22:07:56 +08:00
fujie
13aed46c05 docs: shorten community market badges to Get-Market for better visual balance 2026-02-09 22:06:37 +08:00
fujie
02a1668979 docs: add direct Community Market download badges to Star Features 2026-02-09 22:04:46 +08:00
fujie
9760ccb243 style: silence MD033 lint errors by wrapping with markdownlint-disable comments 2026-02-09 22:00:45 +08:00
fujie
e2c705fe15 style: reduce HTML elements in README.md collapsible sections and fix summary bold 2026-02-09 21:59:43 +08:00
fujie
37c7bf73c0 style: fix table formatting lint errors in README.md 2026-02-09 21:58:55 +08:00
fujie
447e791ab6 style: fix lint global errors and synchronize stats generator 2026-02-09 21:58:27 +08:00
fujie
cde685a364 docs: synchronize project contents with disk and add missing filters 2026-02-09 21:55:54 +08:00
fujie
b00206b063 docs: implement collapsible project content layout in home README 2026-02-09 21:53:47 +08:00
fujie
e0a838e512 docs: finalize home README with 5 star features and BYOK highlight (pure English) 2026-02-09 21:51:36 +08:00
fujie
b9f4f5f1d6 chore: update project README with star feature highlight (English only) 2026-02-09 21:47:54 +08:00
github-actions[bot]
c1afd1fa23 chore: update community stats - points increased (259 -> 261), followers increased (210 -> 211) 2026-02-09 13:37:24 +00:00
Jeff
eaeaadaf12 Merge pull request #39 from Fu-Jie/add-abaroni-contributor
chore: add @abaroni as contributor
2026-02-09 20:27:07 +08:00
fujie
ee70c6629e chore: add @abaroni as contributor (ideas) 2026-02-09 20:26:27 +08:00
github-actions[bot]
692971c93c chore: update community stats - new plugin added (20 -> 21), plugin version updated 2026-02-09 12:25:10 +00:00
fujie
e17818bf6c chore: re-trigger release for v0.6.0 2026-02-09 19:54:49 +08:00
fujie
c5c9fd9d57 fix(ci): fix shell script error when commit messages contain backticks 2026-02-09 19:53:23 +08:00
fujie
5c9875d390 feat: add openwebui_id to the GitHub Copilot SDK files filter plugin metadata. 2026-02-09 19:48:41 +08:00
fujie
9185f88d40 feat: release github-copilot-sdk v0.6.0 and files-filter v0.1.2 2026-02-09 19:45:23 +08:00
github-actions[bot]
1fcad993ea chore: update community stats - followers increased (208 -> 210) 2026-02-09 03:10:29 +00:00
github-actions[bot]
1594ea3a20 chore: update community stats - followers increased (207 -> 208) 2026-02-09 00:44:14 +00:00
github-actions[bot]
ee681ddad9 chore: update community stats - followers increased (206 -> 207) 2026-02-08 21:11:27 +00:00
github-actions[bot]
881597fd51 chore: update community stats - followers increased (205 -> 206) 2026-02-08 07:21:06 +00:00
github-actions[bot]
5772b1c65f chore: update community stats - plugin version updated, points increased (258 -> 259) 2026-02-08 00:53:22 +00:00
fujie
3d4b4b96e8 fix(docs): Repair broken valves table in README 2026-02-08 08:33:02 +08:00
fujie
409d2f663f feat(copilot): Release v0.5.1 - Smarter BYOK, Tool Caching & Refined Docs 2026-02-08 08:21:32 +08:00
github-actions[bot]
de9948a5b0 chore: update community stats - followers increased (204 -> 205) 2026-02-07 23:12:20 +00:00
github-actions[bot]
0a51b4cfca chore: update community stats - points increased (257 -> 258) 2026-02-07 18:13:00 +00:00
github-actions[bot]
f8eb096300 chore: update community stats - plugin version updated 2026-02-07 11:08:46 +00:00
fujie
f6369a1591 feat: release export-to-docx v0.4.4 w/ formatting & font fixes 2026-02-07 18:14:11 +08:00
github-actions[bot]
81634f57fa chore: update community stats - points increased (254 -> 257) 2026-02-07 09:12:46 +00:00
github-actions[bot]
70dc62aaab chore: update community stats - points increased (246 -> 254), followers increased (203 -> 204) 2026-02-07 06:19:35 +00:00
fujie
8762c05e04 docs: add explicit Copilot subscription requirement to README 2026-02-07 13:41:23 +08:00
github-actions[bot]
db52ac1041 chore: update community stats - plugin version updated 2026-02-07 05:23:23 +00:00
fujie
795ac34cd9 chore: archive development research artifacts and debug scripts 2026-02-07 12:49:42 +08:00
fujie
89a12a4fe8 docs: enforce English-only for commit messages and release notes 2026-02-07 12:38:46 +08:00
fujie
f882997337 feat(github-copilot-sdk): v0.3.0 - unified tool bridge & dynamic MCP discovery
Major enhancements:
- Zero-config OpenWebUI Tool Bridge: automatically converts WebUI Functions to Copilot-compatible tools
- Dynamic MCP Discovery: seamlessly reads MCP servers from Admin Settings -> Connections
- High-performance async engine with optimized event-driven streaming
- Robust interoperability via dynamic Pydantic model generation
- Simplified token acquisition (web-based PAT only, removed CLI method)
- Updated configuration valves (renamed, removed legacy parameters)
- Comprehensive bilingual documentation sync
2026-02-07 12:36:46 +08:00
github-actions[bot]
8e2c1b467e chore: update community stats - followers increased (202 -> 203) 2026-02-07 01:38:50 +00:00
github-actions[bot]
db2433afa1 chore: update community stats - points increased (245 -> 246) 2026-02-06 21:12:47 +00:00
github-actions[bot]
fd125c9dea chore: update community stats - followers increased (201 -> 202) 2026-02-06 17:20:41 +00:00
github-actions[bot]
0a726aacb6 chore: update community stats - followers increased (200 -> 201) 2026-02-06 14:21:48 +00:00
github-actions[bot]
bf82e093d4 chore: update community stats - points increased (244 -> 245), followers increased (199 -> 200) 2026-02-06 10:19:17 +00:00
github-actions[bot]
53ae7ef003 chore: update community stats - followers increased (197 -> 199) 2026-02-06 04:39:50 +00:00
github-actions[bot]
c2c7e3b2d3 chore: update community stats - followers increased (196 -> 197) 2026-02-06 01:39:25 +00:00
github-actions[bot]
26df5f5144 chore: update community stats - followers increased (195 -> 196) 2026-02-05 20:13:20 +00:00
github-actions[bot]
aebeb3677c chore: update community stats - followers increased (194 -> 195) 2026-02-05 17:22:50 +00:00
github-actions[bot]
076c1d62c6 chore: update community stats - points increased (243 -> 244) 2026-02-05 12:20:12 +00:00
github-actions[bot]
21cf6ecc1d chore: update community stats - followers increased (193 -> 194) 2026-02-05 11:18:53 +00:00
github-actions[bot]
e6bdab54c9 chore: update community stats - followers increased (192 -> 193) 2026-02-05 10:20:57 +00:00
github-actions[bot]
2232e5adb3 chore: update community stats - followers increased (191 -> 192) 2026-02-05 09:22:17 +00:00
github-actions[bot]
d17089972a chore: update community stats - followers increased (190 -> 191) 2026-02-05 07:27:09 +00:00
github-actions[bot]
a7991147be chore: update community stats - followers increased (189 -> 190) 2026-02-05 04:39:47 +00:00
github-actions[bot]
be6eb35567 chore: update community stats - followers increased (188 -> 189) 2026-02-05 00:43:05 +00:00
github-actions[bot]
90bc295871 chore: update community stats - followers increased (187 -> 188) 2026-02-04 18:22:31 +00:00
github-actions[bot]
310ad5d1d3 chore: update community stats - points increased (223 -> 243), followers increased (186 -> 187) 2026-02-04 07:23:53 +00:00
github-actions[bot]
00ce724430 chore: update community stats - points increased (204 -> 223), followers increased (184 -> 186) 2026-02-04 05:25:30 +00:00
github-actions[bot]
43b68b3ff0 chore: update community stats - points increased (202 -> 204), followers increased (183 -> 184) 2026-02-04 00:39:22 +00:00
github-actions[bot]
b6c1335335 chore: update community stats - points increased (200 -> 202) 2026-02-03 16:23:48 +00:00
github-actions[bot]
8b0b33015f chore: update community stats - followers increased (182 -> 183) 2026-02-03 10:19:31 +00:00
github-actions[bot]
11ee9086b2 chore: update community stats - followers increased (181 -> 182) 2026-02-03 08:17:37 +00:00
github-actions[bot]
3578ffc543 chore: update community stats - points increased (198 -> 200) 2026-02-02 23:11:34 +00:00
github-actions[bot]
b8531f1979 chore: update community stats - followers increased (180 -> 181) 2026-02-02 14:21:14 +00:00
github-actions[bot]
8607afd4c3 chore: update community stats - points increased (197 -> 198), followers increased (179 -> 180) 2026-02-02 12:19:30 +00:00
github-actions[bot]
41d9963d35 chore: update community stats - followers increased (178 -> 179) 2026-02-02 09:24:12 +00:00
github-actions[bot]
bd5f3d3f7c chore: update community stats - followers increased (177 -> 178) 2026-02-02 04:46:56 +00:00
github-actions[bot]
dda8262bc0 chore: update community stats - followers increased (176 -> 177) 2026-02-01 10:09:57 +00:00
github-actions[bot]
0271013ec2 chore: update community stats - points increased (196 -> 197) 2026-01-31 21:07:54 +00:00
github-actions[bot]
e1f210d600 chore: update community stats - followers increased (175 -> 176) 2026-01-31 10:08:48 +00:00
github-actions[bot]
eac8f6f355 chore: update community stats - points increased (195 -> 196) 2026-01-31 09:11:17 +00:00
github-actions[bot]
3998b93034 chore: update community stats - points increased (194 -> 195) 2026-01-31 04:36:15 +00:00
github-actions[bot]
ae04e95e13 chore: update community stats - points increased (193 -> 194) 2026-01-30 22:09:21 +00:00
github-actions[bot]
12d638e134 chore: update community stats - followers increased (173 -> 175) 2026-01-30 21:11:14 +00:00
github-actions[bot]
4a9eb8ed3d chore: update community stats - points increased (190 -> 193), followers increased (172 -> 173) 2026-01-30 19:16:44 +00:00
github-actions[bot]
af127bbfd5 chore: update community stats - points increased (189 -> 190) 2026-01-30 18:17:05 +00:00
github-actions[bot]
db7bb6250a chore: update community stats - points increased (188 -> 189) 2026-01-30 17:17:25 +00:00
github-actions[bot]
24b029e617 chore: update community stats - points increased (187 -> 188) 2026-01-30 15:15:33 +00:00
github-actions[bot]
ff63ab3118 chore: update community stats - points increased (186 -> 187) 2026-01-30 03:03:29 +00:00
github-actions[bot]
07e7e74fe1 chore: update community stats - followers increased (171 -> 172) 2026-01-30 00:41:11 +00:00
github-actions[bot]
55456775c1 chore: update community stats - points increased (185 -> 186), followers increased (170 -> 171) 2026-01-29 22:11:07 +00:00
github-actions[bot]
05bb2e4644 chore: update community stats - points increased (184 -> 185) 2026-01-29 21:11:30 +00:00
github-actions[bot]
83fa20ed08 chore: update community stats - points increased (183 -> 184) 2026-01-29 20:11:59 +00:00
fujie
ec69524357 feat: add Open WebUI Prompt Plus to extensions list and documentation 2026-01-30 02:16:38 +08:00
github-actions[bot]
829361da63 chore: update community stats - points increased (182 -> 183), followers increased (169 -> 170) 2026-01-29 17:17:44 +00:00
github-actions[bot]
af05ecec6a chore: update community stats - points increased (180 -> 182) 2026-01-29 16:18:22 +00:00
github-actions[bot]
1e08ae7d10 chore: update community stats - points increased (179 -> 180) 2026-01-29 14:20:30 +00:00
github-actions[bot]
b24233ee07 chore: update community stats - followers increased (168 -> 169) 2026-01-29 11:15:47 +00:00
github-actions[bot]
e5d1550986 chore: update community stats - points increased (170 -> 179), followers increased (167 -> 168) 2026-01-29 09:19:59 +00:00
fujie
7f5deb603e feat: 添加支持暂存插件源码更新的功能 2026-01-29 13:21:18 +08:00
fujie
55b2a28f79 fix: 移除标题中的图标,简化信息图插件的标题 2026-01-29 11:12:32 +08:00
fujie
db9bcb2c31 feat: 添加 README 文件同步工具到 OpenWebUI 社区 2026-01-29 10:58:40 +08:00
fujie
ad2773e8f1 Update plugin documentation for various filters and actions
- Updated README.md and README_CN.md for the infographic plugin to reflect new features and bug fixes in version 1.5.0, including context-aware generation and language synchronization.
- Revised README.md and README_CN.md for the smart mind map plugin to include support for user feedback and a changelog.
- Enhanced README.md and README_CN.md for the async context compression filter with critical fixes and improved compatibility details.
- Introduced initial release notes for the folder memory filter, detailing its core features and installation instructions.
- Updated markdown normalizer documentation to synchronize version numbers and improve clarity on configuration options.
- Revised GitHub Copilot SDK documentation to enhance installation instructions and troubleshooting sections, including a new changelog.
2026-01-29 03:22:21 +08:00
github-actions[bot]
7d4da3be8a chore: update community stats - followers increased (166 -> 167) 2026-01-28 18:14:59 +00:00
github-actions[bot]
28166728a4 chore: update community stats - points increased (169 -> 170) 2026-01-28 15:14:05 +00:00
github-actions[bot]
4dfca903c4 chore: update community stats - points increased (168 -> 169) 2026-01-28 10:11:40 +00:00
github-actions[bot]
b619d3f402 chore: update community stats - points increased (167 -> 168), followers increased (165 -> 166) 2026-01-28 06:14:04 +00:00
github-actions[bot]
1e68f985fb chore: update community stats - new plugin added (19 -> 20), plugin version updated 2026-01-28 05:13:56 +00:00
github-actions[bot]
596b571887 chore: update community stats - plugin version updated 2026-01-28 03:38:17 +00:00
fujie
c4d36c32a0 docs(pipes): fix copilot sdk tools link
Point tools usage link to GitHub source
2026-01-28 11:15:23 +08:00
fujie
6adbcd8d42 fix(scripts): resolve plugin scan NameError
Define metadata per file before use
2026-01-28 11:11:38 +08:00
fujie
89c039fe33 fix(actions): bump smart mind map to 0.9.2
Align mind map language rule with input text

Update plugin docs and README versions
2026-01-28 11:09:18 +08:00
github-actions[bot]
3a73ccfaa7 chore: update community stats - points increased (166 -> 167) 2026-01-28 01:37:45 +00:00
github-actions[bot]
7eff265e1c chore: update community stats - points increased (161 -> 166) 2026-01-27 21:07:14 +00:00
github-actions[bot]
989b45fc16 chore: update community stats - points increased (157 -> 161) 2026-01-27 20:09:28 +00:00
fujie
163d8ce8bd fix(scripts): exclude debug directory from release scanning 2026-01-28 02:30:38 +08:00
fujie
4e32e1a1da fix(scripts): normalize plugin paths in version extraction to prevent false positives in release diffs 2026-01-28 02:28:20 +08:00
github-actions[bot]
070e9f2456 chore: update community stats - plugin version updated 2026-01-27 18:15:04 +00:00
fujie
219ba83df3 feat(infographic): release v1.5.0 with smart language detection & organize debug tools 2026-01-28 02:14:30 +08:00
github-actions[bot]
e412aeb93d chore: update community stats - followers increased (164 -> 165) 2026-01-27 17:12:55 +00:00
github-actions[bot]
38102ca0c4 chore: update community stats - followers increased (163 -> 164) 2026-01-27 13:23:17 +00:00
github-actions[bot]
6ab69fba1c chore: update community stats - plugin version updated, followers increased (162 -> 163) 2026-01-26 21:09:49 +00:00
fujie
e0c0f69dc8 fix: update Git operations rules to allow direct pushes to main branch 2026-01-27 04:39:37 +08:00
fujie
7921b14dae fix: remove obsolete openwebui_id from SDK metadata 2026-01-27 04:32:22 +08:00
443 changed files with 59091 additions and 10825 deletions

View File

@@ -0,0 +1,46 @@
# `.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 |

View File

@@ -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.

View 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.

View 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>
```
关键改进:
- 规则 3Ruthless Denoising → 新增规则 4Error Verbatim + 规则 5Causal 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/ODB 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 一个锁
```
**设计**
- ValvesPydantic 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

View 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.

View 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.

View 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.

View 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`.

160
.agent/rules/antigravity.md Normal file
View File

@@ -0,0 +1,160 @@
---
description: >
Antigravity development mode rules. Apply when the user requests high-speed iteration,
a quick prototype, or says "反重力开发" / "antigravity mode".
globs: "plugins/**/*.py"
always_on: false
---
# Antigravity Development Mode
> High-speed delivery + strict reversibility. Every decision must keep both roll-forward and rollback feasible.
---
## Core Principles
1. **Small, isolated edits** — one logical change per operation; no mixing refactor + feature.
2. **Deterministic interfaces** — function signatures and return shapes must not change without an explicit contract update.
3. **Multi-level fallback** — every I/O path has a degraded alternative (e.g., S3 → local → DB).
4. **Reversible by default** — every file write, API call, or schema change must have an undo path recorded or be idempotent.
---
## Mandatory Safety Patterns
### 1. Timeout Guards on All Frontend Calls
Any `__event_call__` or `__event_emitter__` JS execution MUST be wrapped:
```python
import asyncio
try:
result = await asyncio.wait_for(
__event_call__({"type": "execute", "data": {"code": js_code}}),
timeout=2.0
)
except asyncio.TimeoutError:
logger.warning("Frontend JS execution timed out; falling back.")
result = fallback_value
except Exception as e:
logger.error(f"Frontend call failed: {e}", exc_info=True)
result = fallback_value
```
JS side must also guard internally:
```javascript
try {
return (localStorage.getItem('locale') || navigator.language || 'en-US');
} catch (e) {
return 'en-US';
}
```
### 2. Path Sandbox Validation
Resolve every workspace path and verify it stays inside the repo root:
```python
import os
def _validate_workspace_path(path: str, workspace_root: str) -> str:
resolved = os.path.realpath(os.path.abspath(path))
root = os.path.realpath(workspace_root)
if not resolved.startswith(root + os.sep) and resolved != root:
raise PermissionError(f"Path escape detected: {resolved} is outside {root}")
return resolved
```
### 3. Dual-Channel Upload Fallback
Always try API first; fall back to DB/local on failure:
```python
async def _upload_file(self, filename: str, content: bytes) -> str:
# Channel 1: API upload (S3-compatible)
try:
url = await self._api_upload(filename, content)
if url:
return url
except Exception as e:
logger.warning(f"API upload failed: {e}; falling back to local.")
# Channel 2: Local file + DB registration
return await self._local_db_upload(filename, content)
```
### 4. Progressive Status Reporting
For tasks > 3 seconds, emit staged updates:
```python
await self._emit_status(emitter, "正在分析内容...", done=False)
# ... phase 1 ...
await self._emit_status(emitter, "正在生成输出...", done=False)
# ... phase 2 ...
await self._emit_status(emitter, "完成", done=True)
```
Always emit `done=True` on completion and `notification(error)` on failure.
### 5. Emitter Guard
Check before every emit to prevent crashes on missing emitter:
```python
if emitter and self.valves.SHOW_STATUS:
await emitter({"type": "status", "data": {"description": msg, "done": done}})
```
### 6. Exception Surface Rule
Never swallow exceptions silently. Every `except` block must:
- Log to backend: `logger.error(f"...: {e}", exc_info=True)`
- Notify user: `await self._emit_notification(emitter, f"处理失败: {str(e)}", "error")`
---
## Edit Discipline
| ✅ DO | ❌ DO NOT |
|-------|-----------|
| One function / one Valve / one method per edit | Mix multiple unrelated changes in one operation |
| Validate input at the function boundary | Assume upstream data is well-formed |
| Return early on invalid state | Nest complex logic beyond 3 levels |
| Check fallback availability before primary path | Assume primary path always succeeds |
| Log before and after expensive I/O | Skip logging for "obvious" operations |
---
## Rollback Checklist
Before completing an antigravity operation, confirm:
- [ ] No global state mutated on `self` (filter singleton rule)
- [ ] File writes are atomic or can be recreated
- [ ] Database changes are idempotent (safe to re-run)
- [ ] Timeout guards are in place for all async calls to external systems
- [ ] The user can observe progress through status/notification events
- [ ] 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.
---
## References
- 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

View File

@@ -12,19 +12,22 @@ All plugins MUST follow the standard README template.
**Reference Template**: @docs/PLUGIN_README_TEMPLATE.md
### Language Requirements
- **English Version (`README.md`)**: The primary documentation source. Must follow the template strictly.
- **Chinese Version (`README_CN.md`)**: MUST be translated based on the English version (`README.md`) to ensure consistency in structure and content.
### Metadata Requirements
The metadata line must follow this format:
`**Author:** [Name](Link) | **Version:** [X.Y.Z] | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui) | **License:** MIT`
`**Author:** [Name](Link) | **Version:** [X.Y.Z] | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT`
### 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)
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)

View File

71
.agent/skills/README.md Normal file
View 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.

View 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.

View 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.

View 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()

View 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>`.

View File

@@ -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

View 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!"

View 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

View 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)

View 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

View 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.

View 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])

View 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

View 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.

View 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

View 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

View 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])

View 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

View 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

View 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

View 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``![updated](https://img.shields.io/badge/YYYY--MM--DD-gray?style=flat)`
- `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

View 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.

View File

@@ -0,0 +1,64 @@
---
name: test-copilot-pipe
description: Automotive deployment and testing of GitHub Copilot SDK Pipe plugin for frontend/backend status stability.
---
# 🤖 Skill: Test Copilot Pipe
This is a **universal testing framework** for publishing the latest `github_copilot_sdk.py` (Pipe) code to a local OpenWebUI instance and verifying it via an automated agent (`browser_subagent`).
## 🎯 Core Principles
- **Fixed Infrastructure**: The deployment script and the test entry URL are always static.
- **Dynamic Test Planning**: Specific test prompts and expectations (acceptance criteria) **must** be dynamically planned by you based on the code changes or specific user requests before execution.
---
## 🛠️ Static Environment Info
| Attribute | Fixed Value |
|------|--------|
| **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` |
---
## 📋 Standard Workflow
### Step 1: Analyze Changes & Plan Test (Plan)
Before triggering the test, you must define the purpose of this test turn.
Example: *Modified tool calling logic -> Test prompt should trigger a specific tool; observe if the tool executes and returns the correct result.*
### Step 2: Deploy Latest Code (Deploy)
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/deploy_pipe.py
```
> **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)
Use the `browser_subagent` tool. **You must fill in the `[Dynamic Content]` slots based on Step 1**:
```text
Task:
1. Access The Fixed URL: http://localhost:3003/?model=github_copilot_official_sdk_pipe.github_copilot_sdk-gpt-4.1
2. RELIABILITY WAIT: Wait until the page fully loads. Wait until the chat input text area (`#chat-input`) is present in the DOM.
3. ACTION - FAST INPUT: Use the `execute_browser_javascript` tool to instantly inject the query and submit it. Use exactly this script format to ensure stability:
`const input = document.getElementById('chat-input'); input.value = "[YOUR_DYNAMIC_TEST_PROMPT]"; input.dispatchEvent(new Event('input', { bubbles: true })); const e = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true }); input.dispatchEvent(e);`
4. WAITING: Wait patiently for the streaming response to stop completely. You should wait for the Stop button to disappear, or wait for the system to settle (approximately 10-15 seconds depending on the query).
5. CHECK THE OUTCOME: [List the phenomena you expect to see, e.g., status bar shows specific text, tool card appears, result contains specific keywords, etc.]
6. CAPTURE: Take a screenshot of the settled state to prove the outcome.
7. REPORT: Report the EXACT outcome matching the criteria from step 5.
```
### Step 4: Evaluate & Iterate (Evaluate)
- **PASS**: Screenshot and phenomena match expectations. Report success to the user.
- **FAIL**: Analyze the issue based on screenshots/logs (e.g., race condition reappeared, API error). Modify the code and **re-run the entire skill workflow**.

View 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>"
```

View 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])

View File

@@ -4,23 +4,25 @@ description: OpenWebUI Plugin Development & Release Workflow
# OpenWebUI Plugin Development Workflow
This workflow outlines the standard process for developing, documenting, and releasing plugins for OpenWebUI, ensuring compliance with project standards and CI/CD requirements.
This workflow outlines the standard process for developing, documenting, and releasing plugins for OpenWebUI. **Crucially, the default goal of this workflow is "Preparation" (updating all relevant files) rather than automatic "Submission" (git commit/push), unless a release is explicitly requested.**
## 1. Development Standards
Reference: `.github/copilot-instructions.md`
### Bilingual Requirement
Every plugin **MUST** have bilingual versions for both code and documentation:
- **Code**:
- English: `plugins/{type}/{name}/{name}.py`
- Chinese: `plugins/{type}/{name}/{name_cn}.py` (or `中文名.py`)
Every plugin **MUST** have a single internationalized code file and bilingual documentation:
- **Code (i18n)**:
- `plugins/{type}/{name}/{name}.py`
- The single `.py` file must implement internal i18n (e.g., using `navigator.language` or backend headers) to support multiple languages natively, rather than splitting into separate files.
- **README**:
- English: `plugins/{type}/{name}/README.md`
- Chinese: `plugins/{type}/{name}/README_CN.md`
### Code Structure
- **Docstring**: Must include `title`, `author`, `version`, `description`, etc.
- **Valves**: Use `pydantic` for configuration.
- **Database**: Re-use `open_webui.internal.db` shared connection.
@@ -32,8 +34,9 @@ Every plugin **MUST** have bilingual versions for both code and documentation:
- Use Chat Persistence API for database storage
- Always update both `messages[]` and `history.messages`
### Commit Messages
- **Language**: **English ONLY**. Do not use Chinese in commit messages.
### Commit Messages & Release Notes
- **Language**: **English ONLY**. Do not use Chinese in commit messages or release notes.
- **Format**: Conventional Commits (e.g., `feat:`, `fix:`, `docs:`).
## 2. Documentation Updates
@@ -41,10 +44,16 @@ Every plugin **MUST** have bilingual versions for both code and documentation:
When adding or updating a plugin, you **MUST** update the following documentation files to maintain consistency:
### Plugin Directory
- `README.md`: Update version, description, and usage. **Explicitly describe new features in a prominent position at the beginning.**
- `README_CN.md`: Update version, description, and usage. **Explicitly describe new features in a prominent position at the beginning.**
- `README.md`: Update version, description, and usage.
- **Key Capabilities**: **MUST** include ALL core functionalities and features. This is a cumulative section. Every release **MUST** verify that basic core descriptions are NOT lost or overwritten by new feature lists.
- **What's New**: Explicitly describe only the latest changes/updates in a prominent position at the beginning. This section is dynamic and changes with versions.
- `README_CN.md`: Update version, description, and usage.
- **核心功能 (Key Capabilities)**: **必须**包含所有核心功能和特性。这是一个累积性的部分,每次版本更新**必须**确认基础核心功能的描述没有丢失或被新功能列表覆盖。
- **最新更新 (What's New)**: 在开头显眼位置明确描述最新的更改/更新。此部分是动态的,随版本变化。
### Global Documentation (`docs/`)
- **Index Pages**:
- `docs/plugins/{type}/index.md`: Add/Update list item with **correct version**.
- `docs/plugins/{type}/index.zh.md`: Add/Update list item with **correct version**.
@@ -53,6 +62,7 @@ When adding or updating a plugin, you **MUST** update the following documentatio
- `docs/plugins/{type}/{name}.zh.md`: Ensure content matches README_CN.
### Root README
- `README.md`: Add to "Featured Plugins" if applicable.
- `README_CN.md`: Add to "Featured Plugins" if applicable.
@@ -61,40 +71,59 @@ When adding or updating a plugin, you **MUST** update the following documentatio
Reference: `.github/workflows/release.yml`
### Version Bumping
- **Rule**: Version bump is required **ONLY when the user explicitly requests a release**. Regular code changes do NOT require version bumps.
- **Format**: Semantic Versioning (e.g., `1.0.0` -> `1.0.1`).
- **When to Bump**: Only update the version when:
- User says "发布" / "release" / "bump version"
- User explicitly asks to prepare for release
- **Agent Initiative**: After completing significant changes (new features, bug fixes, or multiple code modifications), the agent **SHOULD proactively ask** the user if they want to release a new version. If confirmed, update all version-related files.
- **Agent Initiative**: After completing significant changes (new features, bug fixes, or multiple code modifications), the agent **SHOULD proactively ask** the user if they want to **prepare a new version** for release.
- **Release Information Compliance**: When a release is requested, the agent must generate a standard release summary (English commit title + bilingual bullet points) as defined in Section 3 & 5.
- **Default Action (Prepare Only)**: When performing a version bump or update, the agent should update all files locally but **STOP** before committing. Present the changes and the **proposed Release/Commit Message** to the user and wait for explicit confirmation to commit/push.
- **Consistency**: When bumping, update version in **ALL** locations:
1. English Code (`.py`)
2. Chinese Code (`.py`)
3. English README (`README.md`)
4. Chinese README (`README_CN.md`)
5. Docs Index (`docs/.../index.md`)
6. Docs Index CN (`docs/.../index.zh.md`)
7. Docs Detail (`docs/.../{name}.md`)
8. Docs Detail CN (`docs/.../{name}.zh.md`)
1. Code (`.py`)
2. English README (`README.md`)
3. Chinese README (`README_CN.md`)
4. Docs Index (`docs/.../index.md`)
5. Docs Index CN (`docs/.../index.zh.md`)
6. Docs Detail (`docs/.../{name}.md`)
7. Docs Detail CN (`docs/.../{name}.zh.md`)
### Automated Release Process
1. **Trigger**: Push to `main` branch with changes in `plugins/**/*.py`.
2. **Detection**: `scripts/extract_plugin_versions.py` detects changed plugins and compares versions.
3. **Release**:
1. **Trigger**: Push to `main` branch with changes in `plugins/**/*.py`.
2. **Detection**: `scripts/extract_plugin_versions.py` detects changed plugins and compares versions.
3. **Release**:
- Generates release notes based on changes.
- Creates a GitHub Release tag (e.g., `v2024.01.01-1`).
- Uploads individual `.py` files of **changed plugins only** as assets.
4. **Market Publishing**:
4. **Market Publishing**:
- Workflow: `.github/workflows/publish_plugin.yml`
- Trigger: Release published.
- Action: Automatically updates the plugin code and metadata on OpenWebUI.com using `scripts/publish_plugin.py`.
- **Auto-Sync**: If a local plugin has no ID but matches an existing published plugin by **Title**, the script will automatically fetch the ID, update the local file, and proceed with the update.
- Requirement: `OPENWEBUI_API_KEY` secret must be set.
- **README Link**: When announcing a release, always include the GitHub README URL for the plugin:
- Format: `https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/{type}/{name}/README.md`
- Example: `https://github.com/Fu-Jie/awesome-openwebui/blob/main/plugins/filters/folder-memory/README.md`
- Format: `https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/{type}/{name}/README.md`
- Example: `https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/filters/folder-memory/README.md`
### Release Content Standard
When the user confirms a release, the agent **MUST** follow these content standards:
1. **Commit Message**:
- **Language**: English ONLY.
- **Format**: `type(scope): description` (e.g., `feat(pipes): add streaming support for Copilot SDK`).
- **Body**: List 1-3 key changes in bullet points.
2. **Release Summary (for user review)**:
- Before committing, present a "Release Draft" containing:
- **Title**: e.g., `Release v0.1.1: [Plugin Name] - [Brief Summary]`
- **Changelog**: English-only list of commits since the last release, including hashes (e.g., `896de02 docs(config): reorder antigravity model alias example`).
- **Verification Status**: Confirm all 7+ files have been updated and synced.
3. **Internal Documentation**: Ensure "What's New" sections in READMEs and `docs/` match exactly the changes being released.
### Pull Request Check
- Workflow: `.github/workflows/plugin-version-check.yml`
- Checks if plugin files are modified.
- **Fails** if version number is not updated.
@@ -104,15 +133,27 @@ Reference: `.github/workflows/release.yml`
Before committing:
- [ ] Code is bilingual and functional?
- [ ] Code is internal i18n supported (`.py`) and fully functional?
- [ ] Docstrings have updated version?
- [ ] READMEs are updated and bilingual?
- [ ] **Key Capabilities** in READMEs still cover all legacy core features + new features?
- [ ] `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)
Strictly follow the rules defined in `.github/copilot-instructions.md`**Git Operations (Agent Rules)** section.
1. **Prepare-on-Demand**: Focus on file modifications and local verification first.
2. **No Auto-Commit**: Never `git commit`, `git push`, or `create_pull_request` automatically after file updates unless the user explicitly says "commit this" or "release now".
3. **Draft Mode**: If available, use PRs as drafts first.
4. **Reference**: Strictly follow the rules defined in `.github/copilot-instructions.md`**Git Operations (Agent Rules)** section.
## 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`.

View File

@@ -45,12 +45,21 @@
"contributions": [
"ideas"
]
},
{
"login": "abaroni",
"name": "Alessandro Baroni",
"avatar_url": "https://avatars.githubusercontent.com/u/21365486?v=4",
"profile": "https://github.com/abaroni",
"contributions": [
"ideas"
]
}
],
"contributorsPerLine": 7,
"skipCi": true,
"repoType": "github",
"repoHost": "https://github.com",
"projectName": "awesome-openwebui",
"projectName": "openwebui-extensions",
"projectOwner": "Fu-Jie"
}
}

8
.cursorrules Normal file
View 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`.

71
.gemini/skills/README.md Normal file
View 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.

View 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.

View 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.

View 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()

View 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>`.

View File

@@ -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

View 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!"

View 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

View 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)

View 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

View 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.

View 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])

View File

@@ -0,0 +1,59 @@
---
name: openwebui-community-publisher
description: Automatically publishes plugin update posts to openwebui.com.
---
# OpenWebUI Community Publisher
## Overview
This skill automates the process of creating **new** plugin release notes and announcements directly on the OpenWebUI Community (openwebui.com).
**Note**: This skill is exclusively for **new post creation**. Do NOT use this for updating existing posts, as updates are managed separately via dedicated scripts.
## Prerequisites
- User must be logged into [openwebui.com](https://openwebui.com) in the browser session.
- The content must be prepared in Markdown format (typically following the structure of the plugin's changelog or a dedicated release `.md` file).
## Execution Workflow
### 1. Verification
- Use `browser_subagent` to navigate to `https://openwebui.com`.
- Verify the logged-in user status (look for profile icons or "@Fu-Jie").
### 2. Post Creation
- Navigate to `https://openwebui.com/post`.
- **Post Type Selection**:
- Choose the appropriate tab based on content:
- **Text**: General announcements and documentation.
- **Tool**: Standalone tool plugins.
- **Function**: Pipes, Filters, or Actions.
- **Prompt**: Chat prompt templates.
- **Model**: GGUF/Ollama model files.
- Unless otherwise specified, default to **Text** for general release introductions.
- **Community Selection**:
- For general OpenWebUI related posts, select **o/openwebui**.
- For specialized topics, select the relevant community (e.g., **o/ollama** for models).
- **Metadata Mapping**:
- **Title**: Use the main header from the source file.
- **Content/Description**: Paste the Markdown body.
- **Source Code (for Function/Pipe)**: If publishing a `Function`, retrieve the corresponding `.py` file content and paste it into the code area.
- **Tags**: Leave empty by default unless relevant keywords are explicitly provided.
- **Media**: Optional, only attach if provided.
- **Settings**: Ensure "Adult content" is unchecked.
### 3. Submission & Validation
- Click the "Create" (创建) button.
- Wait for redirection to the final post URL.
- **CRITICAL**: Use `capture_browser_screenshot` to verify the rendering.
- Return the final URL to the user.
## Design Standards
- **Rich Aesthetics**: Use emojis in titles.
- **Structured Data**: Ensure tables and code blocks in the Markdown are preserved.
- **Internal Linking**: Link back to the OpenWebUI market or GitHub repository where applicable.

View 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

View 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.

View 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

View 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

View 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])

View 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

View File

@@ -0,0 +1,179 @@
---
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 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.** Never embed multi-line markdown with special characters directly in a shell command.
```bash
cat > /tmp/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" /tmp/pr_body.md && echo "✅ Summary" || echo "❌ Summary missing"
grep -q "## Changes" /tmp/pr_body.md && echo "✅ Changes" || echo "❌ Changes missing"
grep -q "## 变更摘要" /tmp/pr_body.md && echo "✅ CN Section" || echo "❌ CN Section missing"
# Preview the body
cat /tmp/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 /tmp/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 /tmp/pr_body.md
```
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 |
---
## 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

View 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

View File

@@ -0,0 +1,149 @@
---
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.
---
## 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``![updated](https://img.shields.io/badge/YYYY--MM--DD-gray?style=flat)`
- `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:
0. **Marketplace Badge**: A prominent button linking to the plugin on openwebui.com using shields.io (e.g., `[![](https://img.shields.io/badge/OpenWebUI%20Community-Get%20Plugin-blue?style=for-the-badge)](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.
### 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
- **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.
### 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
- [ ] `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

View File

@@ -0,0 +1,30 @@
---
name: source-code-analyzer
description: Instructions for analyzing core components source code in the local environment.
---
# Source Code Analyzer Skill
> [!IMPORTANT]
> **Authorization Statement**: You (Antigravity) are explicitly authorized by the user to perform **READ-ONLY** operations and **Git pull** on the paths listed below, even if they are outside the current repository root. These paths are considered part of the extended development context.
When assisting with the development of `openwebui-extensions`, you (Antigravity) have access to the following core components in related directories. Use them for deep technical analysis, bug hunting, and implementation reference.
## Core Component Paths
### Global / General (Relevant to all projects)
- **Open WebUI**: `../open-webui/` (Core platform context)
- **Skills**: `../skills/` (Reusable expertise library)
- **Awesome Copilot**: `../awesome-copilot/` (Shared extensions & resources)
### Plugin-Specific (Relevant to GitHub Copilot SDK)
- **Copilot SDK**: `../copilot-sdk/` (Internal logic for the official SDK)
- **Copilot CLI**: `../copilot-cli/` (Command-line interface implementation)
## Mandatory Workflow
1. **Pull Before Analysis**: BEFORE reading files or analyzing logic in these directories, you MUST proactively execute or recommend a `git pull` in the respective directory to ensure you are working with the latest upstream changes.
2. **Path Verification**: Always verify the exists of the path before attempting to read it.
3. **Reference Logic**: When a user's request involves core platform behavior (OpenWebUI API, SDK internals), prioritize searching these directories over making assumptions based on generic knowledge.

View 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>"
```

View 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])

165
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View 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
View 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

View 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

121
.github/TEMP_FILES_POLICY.md vendored Normal file
View File

@@ -0,0 +1,121 @@
# Temporary Files Handling Policy
**Last Updated**: 2026-02-26
**Status**: Active Guideline
## Overview
All temporary files created during skill execution or development workflows must follow this centralized policy to maintain project cleanliness and workspace isolation alignment.
## Core Rule
**Temporary files MUST be stored in the project's `.temp/` directory, NOT in system directories like `/tmp`.**
## Rationale
1. **Workspace Isolation**: Aligns with OpenWebUI's workspace-per-user model
2. **Project Cohesion**: All project artifacts (temporary or permanent) stay within project boundaries
3. **Multi-User Safety**: Avoids conflicts between multiple developers using the same system
4. **Cleanup Traceability**: Easy to verify all temp files are cleaned up via single `.temp/` directory
5. **Debugging**: Inspectable before deletion if issues occur
## Usage Pattern
### Creating Temp File
```bash
# Step 1: Ensure temp directory exists
mkdir -p .temp
# Step 2: Write temp file
cat > .temp/my_temp_file.md << 'EOF'
...content...
EOF
# Step 3: Use the file in your workflow
# (e.g., pass to gh CLI, process with script, etc.)
```
### Cleanup After Use
```bash
# Remove individual temp files
rm -f .temp/my_temp_file.md
# Or full cleanup of entire temp directory
rm -rf .temp/
```
## Skills Affected
| Skill | Implementation | Status |
|-------|----------------|--------|
| `pr-submitter` | PR body file (`.temp/pr_body.md`) | ✅ Updated |
| `release-prep` | Draft notes (if any) | ✅ Policy Added |
| `version-bumper` | Backup files (if any) | Check needed |
| Future skills | TBD | 📋 Must follow policy |
## .gitignore Configuration
The following entry in `.gitignore` ensures temp files are never committed:
```
# Temporary files
.temp/
.build/
```
## Examples
### Example 1: PR Submitter Skill
```bash
# Create PR body in temp directory
mkdir -p .temp
cat > .temp/pr_body.md << 'EOF'
## Summary
New feature implementation
EOF
# Use with gh CLI
gh pr create --body-file .temp/pr_body.md --title "feat: new feature"
# Cleanup
rm -f .temp/pr_body.md
```
### Example 2: Release Prepare Workflow
```bash
# Create draft changelog
mkdir -p .temp
cat > .temp/changelog_draft.md << 'EOF'
# v1.0.0 Release Notes
EOF
# Edit, validate, then integrate into real files
# ...
# Cleanup
rm -f .temp/changelog_draft.md
```
## Anti-Patterns (❌ Don't Do This)
- ❌ Writing temp files to `/tmp` — will be lost/orphaned
- ❌ Writing to root directory or `plugins/` — pollutes repo
- ❌ Not cleaning up temp files — accumulates clutter
- ❌ Committing `.temp/` files to git — defeats the purpose
- ❌ Using absolute paths — breaks workflow portability
## Enforcement
1. **Code Review**: PRs should verify no `/tmp` references in scripts
2. **CI/CD**: Setup can validate `.temp/` cleanup via git status before commit
3. **Documentation**: All skill docs must reference this policy (link to this file)
4. **Automated**: Consider adding pre-commit hook to ensure `.temp/` is not staged
## Questions / Clarifications
For questions about this policy, refer to:
- `.github/skills/pr-submitter/SKILL.md` — Practical example
- `.github/skills/release-prep/SKILL.md` — Policy integration
- `/memories/repo/temp-file-handling-convention.md` — Internal notes

View File

@@ -0,0 +1,67 @@
---
name: Plugin Implementer
description: Implement OpenWebUI plugin and docs updates with strict project standards
argument-hint: Provide approved plan or feature request to implement
tools: ['execute/getTerminalOutput', 'execute/runInTerminal', 'read/readFile', 'read/terminalSelection', 'read/terminalLastCommand', 'edit/createFile', 'edit/editFiles', 'search', 'web', 'web/fetch', 'web/githubRepo', 'agent']
infer: true
handoffs:
- label: Run Review
agent: Plugin Reviewer
prompt: Review the implementation for i18n, safety, and consistency issues.
send: false
---
You are the **implementation specialist** for the `openwebui-extensions` repository.
## Execution Rules
1. **Minimal diffs**: Change only what the approved plan specifies.
2. **Single-file i18n**: Every plugin is one `.py` file with built-in `TRANSLATIONS` dict. Never create `_cn.py` split files.
3. **Context helpers**: Always use `_get_user_context(__user__)` and `_get_chat_context(body, __metadata__)` — never access dict keys directly.
4. **Emitter guards**: Every `await emitter(...)` must be guarded by `if emitter:`.
5. **Logging**: Use `logging.getLogger(__name__)` — no bare `print()` in production code.
6. **Async safety**: Wrap all `__event_call__` with `asyncio.wait_for(..., timeout=2.0)` + inner JS `try { ... } catch(e) { return fallback; }`.
## Required Plugin Pattern
```python
# Docstring: title, author, author_url, funding_url, version, description
# icon_url is REQUIRED for Action plugins (Lucide SVG, base64)
class Action: # or Filter / Pipe
class Valves(BaseModel):
SHOW_STATUS: bool = Field(default=True, description="...")
# All fields UPPER_SNAKE_CASE
def __init__(self):
self.valves = self.Valves()
def _get_user_context(self, __user__): ... # always implement
def _get_chat_context(self, body, __metadata__=None): ... # always implement
async def _emit_status(self, emitter, description, done=False): ...
async def _emit_notification(self, emitter, content, ntype="info"): ...
```
## Known Split-File Plugins (Legacy — Do NOT Add More)
These still have `_cn.py` files. When touching any of them, migrate CN content into `TRANSLATIONS` dict:
- `plugins/actions/deep-dive/deep_dive_cn.py`
- `plugins/actions/export_to_docx/export_to_word_cn.py`
- `plugins/actions/export_to_excel/export_to_excel_cn.py`
- `plugins/actions/flash-card/flash_card_cn.py`
- `plugins/actions/infographic/infographic_cn.py`
- `plugins/filters/folder-memory/folder_memory_cn.py`
## Version Bump Rule
Only bump version when user explicitly says "发布" / "release" / "bump version".
When bumping, update ALL 7+ files (code docstring + 2× README + 2× doc detail + 2× doc index + 2× root README date badge).
## Git Policy
- Never run `git commit`, `git push`, or create PRs automatically.
- After all edits, list what changed and why, then stop.
## 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
- Suggested handoff to **Plugin Reviewer**

78
.github/agents/plugin-planner.agent.md vendored Normal file
View File

@@ -0,0 +1,78 @@
---
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']
handoffs:
- label: Start Implementation
agent: Plugin Implementer
prompt: Implement the approved plan step by step with minimal diffs.
send: false
---
You are the **planning specialist** for the `openwebui-extensions` repository.
## Your Responsibilities
1. Read existing plugin code and docs **before** proposing any change.
2. Produce a **small, reversible** plan (one logical change per file per step).
3. Clearly list all impacted files including the docs sync chain.
4. Flag risks: breaking changes, release implications, version bumps needed.
## Hard Rules
- Never propose `git commit`, `git push`, or PR creation.
- Every plan must end with an acceptance checklist for the user to approve before handing off.
- Reference `.github/copilot-instructions.md` as the authoritative spec.
- Browse `.agent/learnings/` **first** to reuse existing knowledge before researching anything.
## Repository Plugin Inventory
### Actions (`plugins/actions/`)
| Dir | Main file | Version | i18n status |
|-----|-----------|---------|-------------|
| `deep-dive` | `deep_dive.py` | 1.0.0 | ⚠️ has `deep_dive_cn.py` split |
| `export_to_docx` | `export_to_word.py` | 0.4.4 | ⚠️ has `export_to_word_cn.py` split |
| `export_to_excel` | `export_to_excel.py` | 0.3.7 | ⚠️ has `export_to_excel_cn.py` split |
| `flash-card` | `flash_card.py` | 0.2.4 | ⚠️ has `flash_card_cn.py` split |
| `infographic` | `infographic.py` | 1.5.0 | ⚠️ has `infographic_cn.py` split |
| `smart-mind-map` | `smart_mind_map.py` | 1.0.0 | ✅ single file |
| `smart-mermaid` | _(empty stub)_ | — | — |
### Filters (`plugins/filters/`)
| Dir | Main file | Version | i18n status |
|-----|-----------|---------|-------------|
| `async-context-compression` | `async_context_compression.py` | 1.3.0 | ✅ |
| `context_enhancement_filter` | `context_enhancement_filter.py` | 0.3 | ⚠️ non-SemVer version |
| `copilot_files_preprocessor` | _(empty stub)_ | — | — |
| `folder-memory` | `folder_memory.py` | 0.1.0 | ⚠️ has `folder_memory_cn.py` split |
| `github_copilot_sdk_files_filter` | `github_copilot_sdk_files_filter.py` | 0.1.2 | ✅ |
| `markdown_normalizer` | `markdown_normalizer.py` | 1.2.4 | ✅ |
| `web_gemini_multimodel_filter` | `web_gemini_multimodel.py` | 0.3.2 | ✅ |
### Pipes / Pipelines / Tools
| Path | Main file | Version |
|------|-----------|---------|
| `pipes/github-copilot-sdk` | `github_copilot_sdk.py` | 0.7.0 |
| `pipelines/moe_prompt_refiner` | `moe_prompt_refiner.py` | — |
| `tools/workspace-file-manager` | `workspace_file_manager.py` | 0.2.0 |
## Naming Conventions (Actual Mix)
- Action dirs: some use **dashes** (`deep-dive`, `flash-card`, `smart-mind-map`), some **underscores** (`export_to_docx`, `export_to_excel`, `infographic`)
- Filter dirs: similarly mixed — prefer underscores for new plugins
- Main `.py` filenames always use **underscores**
## Docs Sync Chain (for every plugin change)
For `plugins/{type}/{name}/`, these 7+ files must stay in sync:
1. `plugins/{type}/{name}/{name}.py` — version in docstring
2. `plugins/{type}/{name}/README.md` — version + What's New
3. `plugins/{type}/{name}/README_CN.md` — version + 最新更新
4. `docs/plugins/{type}/{name}.md`
5. `docs/plugins/{type}/{name}.zh.md`
6. `docs/plugins/{type}/index.md` — version badge
7. `docs/plugins/{type}/index.zh.md` — version badge
8. Root `README.md` / `README_CN.md` — date badge
## Output Format
- **Scope summary**
- **Affected files** (full relative paths)
- **Step-by-step plan** (numbered, ≤10 steps)
- **Risk flags** (version bump? breaking change? split-file migration needed?)
- **Acceptance checklist** → user must approve before handoff to Implementer

75
.github/agents/plugin-reviewer.agent.md vendored Normal file
View File

@@ -0,0 +1,75 @@
---
name: Plugin Reviewer
description: Perform strict repository-aligned code review for OpenWebUI plugin changes
argument-hint: Share changed files or branch diff to review
tools: ['search', 'read/readFile', 'web', 'web/fetch', 'web/githubRepo', 'execute/getTerminalOutput', 'read/terminalLastCommand', 'read/terminalSelection']
infer: true
handoffs:
- label: Prepare Release Draft
agent: Release Prep
prompt: Create a bilingual release draft and commit message based on reviewed changes.
send: false
---
You are the **review specialist** for the `openwebui-extensions` repository.
Full review rules are in .github/instructions/code-review.instructions.md.
## Review Checklist
### 🔴 Blocking (must fix before release)
**1. Single-file i18n Architecture**
- [ ] No new `_cn.py` split files created.
- [ ] All user-visible strings go through `TRANSLATIONS[lang].get(key, fallback)`.
- [ ] `FALLBACK_MAP` covers at least `zh → zh-CN` and `en → en-US`.
- [ ] `format(**kwargs)` on translations wrapped in `try/except KeyError`.
**2. Context Helpers**
- [ ] Uses `_get_user_context(__user__)` (not `__user__["name"]` directly).
- [ ] Uses `_get_chat_context(body, __metadata__)` (not ad-hoc `body.get("chat_id")`).
**3. Antigravity Safety**
- [ ] Every `__event_call__` wrapped: `asyncio.wait_for(..., timeout=2.0)`.
- [ ] JS code passed to `__event_call__` has `try { ... } catch(e) { return fallback; }`.
- [ ] File path operations validated against workspace root (no traversal).
- [ ] Upload paths have dual-channel fallback (API → DB/local).
**4. Emitter Guards**
- [ ] Every `await emitter(...)` guarded by `if emitter:`.
- [ ] `_emit_status(done=False)` on start, `done=True` on success, `_emit_notification("error")` on failure.
- [ ] No bare `print()` — use `logging.getLogger(__name__)`.
**5. Filter Singleton Safety**
- [ ] No mutable per-request state stored on `self` in Filter plugins.
**6. Streaming Compatibility (OpenWebUI 0.8.x)**
- [ ] `</think>` tag closed before any normal text or tool cards.
- [ ] `<details type="tool_calls" ...>` attributes escape `"` as `&quot;`.
- [ ] `<details ...>` block has newline immediately after `>`.
**7. Version & Docs Sync**
- [ ] Version bumped in docstring (if release).
- [ ] `README.md` + `README_CN.md` updated (What's New + version).
- [ ] `docs/plugins/{type}/{name}.md` and `.zh.md` match README.
- [ ] `docs/plugins/{type}/index.md` and `.zh.md` version badges updated.
- [ ] Root `README.md` / `README_CN.md` date badge updated.
**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.
- `icon_url` present for Action plugins (Lucide SVG, base64).
## Known Pre-existing Issues (Don't block on unless the PR introduces new ones)
- `_cn.py` splits in: `deep-dive`, `export_to_docx`, `export_to_excel`, `flash-card`, `infographic`, `folder-memory` — legacy, not new.
- `context_enhancement_filter` version is `0.3` (non-SemVer) — pre-existing.
- `copilot_files_preprocessor` and `smart-mermaid` are empty stubs — pre-existing.
## Review Output
- **Blocking issues** (file:line references)
- **Non-blocking suggestions**
- **Pass / Fail verdict**
- **Knowledge captured?** (`.agent/learnings/` updated if any discoveries were made)
- **Next step**: Pass → handoff to Release Prep; Fail → return to Implementer with fix list

105
.github/agents/release-prep.agent.md vendored Normal file
View File

@@ -0,0 +1,105 @@
---
name: Release Prep
description: Prepare release-ready summaries and Conventional Commit drafts without pushing
argument-hint: Provide final change list and target version (optional)
tools: ['search', 'read/readFile', 'web', 'web/fetch', 'web/githubRepo', 'execute/getTerminalOutput', 'read/terminalLastCommand', 'read/terminalSelection']
infer: true
---
You are the **release preparation specialist** for the `openwebui-extensions` repository.
Full commit message rules: .github/instructions/commit-message.instructions.md
Full release workflow: .agent/workflows/plugin-development.md
## Responsibilities
1. Generate a Conventional Commit message (English only).
2. Draft bilingual release notes (EN + 中文).
3. Verify ALL file sync locations are updated.
4. **Stop before any commit or push** — wait for explicit user confirmation.
## Commit Message Format
```text
type(scope): brief imperative description
- Key change 1
- Key change 2 (include migration note if needed)
```
- `type`: `feat` / `fix` / `docs` / `refactor` / `chore`
- `scope`: plugin folder name (e.g., `smart-mind-map`, `github-copilot-sdk`, `folder-memory`)
- Title ≤ 72 chars, imperative mood, no trailing period, no capital first letter
## 9-File Sync Checklist (fill in for each changed plugin)
```text
Plugin: {type}/{name} → v{new_version}
[ ] 1. plugins/{type}/{name}/{name}.py → version in docstring
[ ] 2. plugins/{type}/{name}/README.md → version + What's New
[ ] 3. plugins/{type}/{name}/README_CN.md → version + 最新更新
[ ] 4. docs/plugins/{type}/{name}.md → mirrors README
[ ] 5. docs/plugins/{type}/{name}.zh.md → mirrors README_CN
[ ] 6. docs/plugins/{type}/index.md → version badge updated
[ ] 7. docs/plugins/{type}/index.zh.md → version badge updated
[ ] 8. README.md (root) → date badge updated
[ ] 9. README_CN.md (root) → date badge updated
```
## Current Plugin Versions (as of last audit — 2026-02-23)
| Plugin | Type | Version | Note |
|--------|------|---------|------|
| deep-dive | action | 1.0.0 | has `_cn.py` split |
| export_to_docx | action | 0.4.4 | has `_cn.py` split |
| export_to_excel | action | 0.3.7 | has `_cn.py` split |
| flash-card | action | 0.2.4 | has `_cn.py` split |
| infographic | action | 1.5.0 | has `_cn.py` split |
| smart-mind-map | action | 1.0.0 | ✅ |
| async-context-compression | filter | 1.3.0 | ✅ |
| context_enhancement_filter | filter | 0.3 | ⚠️ non-SemVer |
| folder-memory | filter | 0.1.0 | has `_cn.py` split |
| github_copilot_sdk_files_filter | filter | 0.1.2 | ✅ |
| markdown_normalizer | filter | 1.2.4 | ✅ |
| web_gemini_multimodel_filter | filter | 0.3.2 | ✅ |
| github-copilot-sdk | pipe | 0.7.0 | ✅ |
| workspace-file-manager | tool | 0.2.0 | ✅ |
## Output Template
### Commit Message
```text
{type}({scope}): {description}
- {change 1}
- {change 2}
```
### Change Summary (EN)
- {bullet list of user-visible changes}
### 变更摘要(中文)
- {中文要点列表}
### Verification Status
{filled-in 9-file checklist for each changed plugin}
## 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.**

View File

@@ -1,4 +1,4 @@
# Copilot Instructions for awesome-openwebui
# Copilot Instructions for openwebui-extensions
本文档定义了 OpenWebUI 插件开发的标准规范和最佳实践。Copilot 在生成代码或文档时应遵循这些准则。
@@ -8,45 +8,57 @@ This document defines the standard conventions and best practices for OpenWebUI
## 🏗️ 项目结构与命名 (Project Structure & Naming)
### 1. 双语版本要求 (Bilingual Version Requirements)
### 1. 语言与代码规范 (Language & Code Requirements)
#### 插件代码 (Plugin Code)
每个插件必须提供两个版本:
每个插件**必须**采用单文件国际化 (i18n) 设计。严禁为不同语言创建独立的源代码文件(如 `_cn.py`)。
1. **英文版本**: `plugin_name.py` - 英文界面、提示词和注释
2. **中文版本**: `plugin_name_cn.py` - 中文界面、提示词和注释
1. **单代码文件**: `plugins/{type}/{name}/{name}.py`
2. **内置 i18n**: 必须在代码中根据前端传来的用户语言(如 `__user__` 中的 `language` 或通过 `get_user_language` 脚本读取)动态切换界面显示、提示词和状态日志。
示例:
示例目录结构
```
plugins/actions/export_to_docx/
├── export_to_word.py # English version
├── export_to_word_cn.py # Chinese version
── README.md # English documentation
└── README_CN.md # Chinese documentation
├── export_to_word.py # 单个代码文件,内置多语言支持
├── README.md # 英文文档 (English documentation)
── README_CN.md # 中文文档
```
#### 文档 (Documentation)
每个插件目录必须包含双语 README 文件:
尽管代码是合一的,但为了市场展示和 SEO每个插件目录仍**必须**包含双语 README 文件:
- `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 必须遵循以下统一结构顺序:
1. **标题 (Title)**: 插件名称,带 Emoji 图标
2. **元数据 (Metadata)**: 作者、版本、项目链接 (一行显示)
- 格式: `**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** x.x.x | **Project:** [Awesome OpenWebUI](https://github.com/Fu-Jie/awesome-openwebui)`
- 格式: `**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** x.x.x | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions)`
- **注意**: Author 和 Project 为固定值,仅需更新 Version 版本号
3. **描述 (Description)**: 一句话功能介绍
4. **最新更新 (What's New)**: **必须**放在描述之后,显著展示最新版本的变更点 (仅展示最近 3 次更新)
4. **最新更新 (What's New)**: **必须**放在描述之后,仅展示**最近 1**更新
5. **核心特性 (Key Features)**: 使用 Emoji + 粗体标题 + 描述格式
6. **使用方法 (How to Use)**: 按步骤说明
7. **配置参数 (Configuration/Valves)**: 使用表格格式,包含参数名、默认值、描述
8. **其他 (Others)**: 支持的模板类型、语法示例、故障排除
8. **支持 (Support)**: **必须**包含,放在配置参数之后、故障排除之前
- 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.`
- 中文: `如果这个插件对你有帮助,欢迎到 [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) 点个 Star这将是我持续改进的动力感谢支持。`
9. **其他 (Others)**: 支持的模板类型、语法示例、故障排除等
- **Changelog**: 统一指向 GitHub 项目历史,不在 README 中列出具体变更
### 2. 插件目录结构 (Plugin Directory Structure)
@@ -54,26 +66,47 @@ plugins/actions/export_to_docx/
plugins/
├── actions/ # Action 插件 (用户触发的功能)
│ ├── my_action/
│ │ ├── my_action.py # English version
│ │ ├── 我的动作.py # Chinese version
│ │ ├── my_action.py # 单文件,内置 i18n
│ │ ├── README.md # English documentation
│ │ └── README_CN.md # Chinese documentation
│ ├── ACTION_PLUGIN_TEMPLATE.py # English template
│ ├── ACTION_PLUGIN_TEMPLATE_CN.py # Chinese template
│ ├── ACTION_PLUGIN_TEMPLATE.py # 通用 i18n 模板
│ └── README.md
├── filters/ # Filter 插件 (输入处理)
── my_filter/
│ │ ├── my_filter.py
│ │ ├── 我的过滤器.py
│ │ ├── README.md
│ │ └── README_CN.md
│ └── README.md
── ...
├── pipes/ # Pipe 插件 (输出处理)
│ └── ...
── pipelines/ # Pipeline 插件
── pipelines/ # Pipeline 插件
└── ...
├── debug/ # 调试与开发工具 (Debug & Development Tools)
│ ├── my_debug_tool/
│ │ ├── debug_script.py
│ │ └── notes.md
│ └── ...
```
#### 调试目录规范 (Debug Directory Standards)
`plugins/debug/` 目录用于存放调试用的脚本、临时验证代码或开发笔记。
**目录结构 (Directory Structure)**:
应根据调试工具所属的插件或功能模块进行子目录分类,而非将文件散落在根目录。
```
plugins/debug/
├── my_plugin_name/ # 特定插件的调试文件 (Debug files for specific plugin)
│ ├── debug_script.py
│ └── guides/
├── common_tools/ # 通用调试工具 (General debug tools)
│ └── ...
└── ...
```
**规范说明 (Guidelines)**:
- **不强制要求 README**: 该目录下的子项目不需要包含 `README.md`
- **发布豁免**: 该目录下的内容**绝不会**被发布脚本处理。
- **内容灵活性**: 可以包含 Python 脚本、Markdown 文档、JSON 数据等。
- **分类存放**: 任何调试产物(如 `test_*.py`, `inspect_*.py`)都不应直接存放在项目根目录,必须移动到此目录下相应的子文件夹中。
### 3. 文档字符串规范 (Docstring Standard)
每个插件文件必须以标准化的文档字符串开头:
@@ -82,7 +115,7 @@ plugins/
"""
title: 插件名称 (Plugin Name)
author: Fu-Jie
author_url: https://github.com/Fu-Jie/awesome-openwebui
author_url: https://github.com/Fu-Jie/openwebui-extensions
funding_url: https://github.com/open-webui
version: 0.1.0
icon_url: data:image/svg+xml;base64,<base64-encoded-svg>
@@ -97,7 +130,7 @@ description: 插件功能的简短描述。Brief description of plugin functiona
|--------------|---------------------|----------------|
| `title` | 插件显示名称 | `Export to Word` / `导出为 Word` |
| `author` | 作者名称 | `Fu-Jie` |
| `author_url` | 作者主页链接 | `https://github.com/Fu-Jie/awesome-openwebui` |
| `author_url` | 作者主页链接 | `https://github.com/Fu-Jie/openwebui-extensions` |
| `funding_url` | 赞助/项目链接 | `https://github.com/open-webui` |
| `version` | 语义化版本号 | `0.1.0`, `1.2.3` |
| `icon_url` | 图标 (Base64 编码的 SVG) | 仅 Action 插件**必须**提供。其他类型可选。 |
@@ -181,19 +214,56 @@ class Action:
#### 用户上下文 (User Context)
```python
def _get_user_context(self, __user__: Optional[Dict[str, Any]]) -> Dict[str, str]:
"""安全提取用户上下文信息。"""
if isinstance(__user__, (list, tuple)):
user_data = __user__[0] if __user__ else {}
elif isinstance(__user__, dict):
user_data = __user__
else:
user_data = {}
async def _get_user_context(
self,
__user__: Optional[dict],
__event_call__: Optional[callable] = None,
__request__: Optional[Request] = None,
) -> dict:
"""
Robust extraction of user context with multi-level fallback for language detection.
Priority: localStorage (via JS) > HTTP headers > User profile > en-US
"""
user_data = __user__ if isinstance(__user__, dict) else {}
user_id = user_data.get("id", "unknown_user")
user_name = user_data.get("name", "User")
user_language = user_data.get("language", "en-US")
# 1. Fallback: HTTP Accept-Language header
if __request__ and hasattr(__request__, "headers"):
accept_lang = __request__.headers.get("accept-language", "")
if accept_lang:
user_language = accept_lang.split(",")[0].split(";")[0]
# 2. Priority: Frontend localStorage via JS (requires timeout protection)
if __event_call__:
try:
js_code = """
try {
return (
document.documentElement.lang ||
localStorage.getItem('locale') ||
navigator.language ||
'en-US'
);
} catch (e) {
return 'en-US';
}
"""
# MUST use wait_for with timeout (e.g., 2.0s) to prevent backend deadlock
frontend_lang = await asyncio.wait_for(
__event_call__({"type": "execute", "data": {"code": js_code}}),
timeout=2.0
)
if frontend_lang and isinstance(frontend_lang, str):
user_language = frontend_lang
except Exception:
pass # Fallback to existing language
return {
"user_id": user_data.get("id", "unknown_user"),
"user_name": user_data.get("name", "User"),
"user_language": user_data.get("language", "en-US"),
"user_id": user_id,
"user_name": user_name,
"user_language": user_language,
}
```
@@ -409,6 +479,277 @@ async def long_running_task_with_notification(self, event_emitter, ...):
return task_future.result()
```
### 7. 前端数据获取与交互规范 (Frontend Data Access & Interaction)
#### 获取前端信息 (Retrieving Frontend Info)
当需要获取用户浏览器的上下文信息如语言、时区、LocalStorage**必须**使用 `__event_call__``execute` 类型,而不是通过文件上传或复杂的 API 请求。
```python
async def _get_frontend_value(self, js_code: str) -> str:
"""Helper to execute JS and get return value."""
try:
response = await __event_call__(
{
"type": "execute",
"data": {
"code": js_code,
},
}
)
return str(response)
except Exception as e:
logger.error(f"Failed to execute JS: {e}")
return ""
# 示例:获取界面语言 (Get UI Language)
async def get_user_language(self):
js_code = """
return (
localStorage.getItem('locale') ||
localStorage.getItem('language') ||
navigator.language ||
'en-US'
);
"""
return await self._get_frontend_value(js_code)
```
#### 适用场景与引导 (Usage Guidelines)
- **语言适配**: 动态获取界面语言 (`ru-RU`, `zh-CN`) 自动切换输出语言和 UI 翻译。这对于单文件 i18n 插件至关重要。
- **时区处理**: 获取 `Intl.DateTimeFormat().resolvedOptions().timeZone` 处理时间。
- **客户端存储**: 读取 `localStorage` 中的用户偏好设置。
- **硬件能力**: 获取 `navigator.clipboard``navigator.geolocation` (需授权)。
**注意**: 即使插件有 `Valves` 配置,也应优先尝试自动探测,提升用户体验。
### 8. 国际化 (i18n) 适配规范 (Internationalization Standards)
开发供全球用户使用的插件时,必须预置多语言支持(如中文、英文等)。
#### i18n 字典定义
在文件顶部定义 `TRANSLATIONS` 字典存储多语言字符串:
```python
TRANSLATIONS = {
"en-US": {
"status_starting": "Smart Mind Map is starting...",
},
"zh-CN": {
"status_starting": "智能思维导图正在启动...",
},
# ... 其他语言
}
# 语言回退映射 (Fallback Map)
FALLBACK_MAP = {
"zh": "zh-CN",
"zh-TW": "zh-CN",
"zh-HK": "zh-CN",
"en": "en-US",
"en-GB": "en-US"
}
```
#### 获取当前用户真实语言 (Robust Language Detection)
Open WebUI 的前端localStorage并未自动同步语言设置到后端数据库或通过标准 API 参数传递。为了获取精准的用户偏好语言,**必须**使用多层级回退机制Multi-level Fallback
`JS 动态探测 (localStorage)` > `HTTP 浏览器头 (Accept-Language)` > `用户 Profile 默认设置` > `en-US`
> **注意!防卡死指南 (Anti-Deadlock Guide)**
> 在通过 `__event_call__` 执行前端 JS 脚本时,如果前端脚本不慎抛出异常 (`Exception`) 会导致回调函数 `cb()` 永不执行,这会让后端的 `asyncio` 永远阻塞并卡死整个请求队列!
> **必须**做两重防护:
> 1. JS 内部包裹 `try...catch` 保证必须有 `return`。
> 2. 后端使用 `asyncio.wait_for` 设置强制超时(建议 2 秒)。
```python
import asyncio
from fastapi import Request
async def _get_user_context(
self,
__user__: Optional[dict],
__event_call__: Optional[callable] = None,
__request__: Optional[Request] = None,
) -> dict:
user_language = __user__.get("language", "en-US") if __user__ else "en-US"
# 1st Fallback: HTTP Accept-Language header
if __request__ and hasattr(__request__, "headers") and "accept-language" in __request__.headers:
raw_lang = __request__.headers.get("accept-language", "")
if raw_lang:
user_language = raw_lang.split(",")[0].split(";")[0]
# 2nd Fallback (Best): Execute JS in frontend to read localStorage
if __event_call__:
try:
js_code = """
try {
return (
document.documentElement.lang ||
localStorage.getItem('locale') ||
navigator.language ||
'en-US'
);
} catch (e) {
return 'en-US';
}
"""
# 【致命!】必须设置 wait_for 防止前端无响应卡死后端
frontend_lang = await asyncio.wait_for(
__event_call__({"type": "execute", "data": {"code": js_code}}),
timeout=2.0
)
if frontend_lang and isinstance(frontend_lang, str):
user_language = frontend_lang
except Exception as e:
pass # fallback to accept-language or en-US
return {
"user_language": user_language,
# ... user_name, user_id etc.
}
```
#### 实际使用 (Usage in Action/Filter)
```python
async def action(self, body: dict, __user__: Optional[dict] = None, __event_call__: Optional[callable] = None, ...):
user_ctx = await self._get_user_context(__user__, __event_call__)
lang = user_ctx["user_language"]
# Use helper to get localized string with optional formatting
msg = self._get_translation(lang, "status_starting", name=user_ctx["user_name"])
await self._emit_status(emitter, msg)
```
#### 提示词中的语言一致性 (Language Consistency in Prompts)
在为 LLM 生成系统提示词时,必须包含“输出语言与输入保持一致”的指令,以确保 i18n 逻辑在 AI 生成环节也不断裂。
**标准指令示例**:
- `Language`: All output must be in the exact same language as the input text provided by the user.
- `Format Consistency`: Even if this system prompt is in English, if the user input is in Chinese, your output must be in Chinese.
#### CJK 脚本的特殊考量 (CJK Script Considerations)
当涉及字符长度限制(如思维导图标题、卡片摘要)时,应区分 CJK中日韩和拉丁脚本。
- **CJK (zh, ja, ko)**: 通常应设置更小的字符数限制(如 10 字以内)。
- **Latin (en, es, fr)**: 可设置较长的字符限制(如 5-8 个词或 35 字符)。
### 9. 智能代理文件交付规范 (Agent File Delivery Standards)
在开发具备文件生成能力的智能代理插件(如 GitHub Copilot SDK 集成)时,必须遵循以下标准流程,以确保文件在不同存储后端(本地/S3下的可用性并绕过不必要的 RAG 处理。
#### 核心协议:三步交付法 (The 3-Step Delivery Protocol)
1. **本地写入 (Write Local)**:
- 代理必须在当前执行目录 (`.`) 下创建文件。
- **严禁**使用系统临时目录(如 `/tmp`)存放待发布的文件,因为这些路径在隔离的工作空间外不可见。
2. **显式发布 (Publish)**:
- 必须调用内建工具 `publish_file_from_workspace(filename='name.ext')`
- 该工具负责将文件迁移至 Open WebUI 正式存储(自动适配 S3并注入 `skip_rag` 元数据以防止触发向量化流程RAG Bypass
3. **呈现链接 (Display Link)**:
- 获取工具返回的 `download_url`(正确格式为 `/api/v1/files/{id}/content`)。
- **必须**以 Markdown 链接形式(如 `[点击下载报告](url)`)展示给用户。
#### 路径语义 (Path Semantics)
- 代理应始终将“当前目录”视为其受保护所在的私有工作空间。
- `publish_file_from_workspace` 的参数 `filename` 仅需传入相对于当前目录的文件名。
### 10. Copilot SDK 插件工具定义规范 (Copilot SDK Tool Definition Standards)
在为 GitHub Copilot SDK 开发自定义工具时,为了确保大模型能正确识别参数(避免生成空的 `properties` Schema必须遵循以下定义模式
#### 显式参数模型 (Explicit Parameter Schema)
**禁止**仅依赖函数签名和类型提示。**必须**定义一个继承自 `pydantic.BaseModel` 的类来描述参数,并在 `define_tool` 中通过 `params_type` 显式引用。
```python
from pydantic import BaseModel, Field
from copilot import define_tool
# 1. 定义参数模型
class MyToolParams(BaseModel):
query: str = Field(..., description="搜索关键词")
limit: int = Field(default=10, description="返回结果数量限制")
# 2. 实现工具逻辑
async def my_custom_search(query: str, limit: int) -> dict:
# ... 逻辑实现 ...
return {"results": []}
# 3. 注册工具(关键:使用 params_type
my_tool = define_tool(
name="my_custom_search",
description="在特定数据源中执行搜索",
params_type=MyToolParams, # 显式传递参数模型以生成正确的 JSON Schema
)(my_custom_search)
```
#### 关键要点 (Key Requirements)
1. **params_type**: 必须在 `define_tool` 中使用此参数。这是防止大模型幻觉认为工具“无参数”的唯一可靠方法。
2. **Field 描述**: 在 `BaseModel` 中使用 `Field(..., description="...")` 为每个参数提供详细的描述信息。
3. **Required vs Optional**: 明确标注必填项(无默认值)和可选项(带 `default`)。
### 11. Copilot SDK 流式渲染与工具卡片规范 (Streaming & Tool Card Standards)
在处理大模型的思维链Reasoning输出和工具调用Tool Calls为了确保能完美兼容 OpenWebUI 0.8.x 前端的 Markdown 解析器及原生折叠 UI 组件,必须遵循以下极度严格的输出格式规范。
#### 思维链流式渲染 (Reasoning Streaming)
为了让前端能够正确显示“Thinking...”的折叠框和 Spinner 动画,**必须**使用原生的 `<think>` 标签。
- **正确的标签包裹**:
```html
<think>
这里是思考过程...
</think>
```
- **关键细节**:
- **标签闭合检测**: 必须在代码内部维护状态(如 `state["thinking_started"]`。当1正文内容即将开始输出2工具调用触发 (`tool.execution_start`) 时,**必须优先输出 `\n</think>\n` 强制闭合标签**。如果不闭合,后续的正文或工具面板会被全部吞进思考框内,导致页面完全崩坏!
- **不要手动拼装**: 严禁通过手动输出 `<details type="reasoning">` 等大段 HTML 来模拟思考过程,这种方式极易在流式片段发送中破坏前端 DOM 树并导致错位。
#### 工具调用原生卡片 (Native Tool Calls Block)
为了在对话界面中生成标准、原生的下拉折叠“工具调用”卡片,当 `event_type == "tool.execution_complete"` 时,必须向队列输出如下严格格式的 HTML
```python
# 必须转义属性中的双引号为 &quot;
args_for_attr = args_json_str.replace('"', "&quot;")
result_for_attr = result_content.replace('"', "&quot;")
tool_block = (
f'\\n<details type="tool_calls"'
f' id="{tool_call_id}"'
f' name="{tool_name}"'
f' arguments="{args_for_attr}"'
f' result="{result_for_attr}"'
f' done="true">\\n'
f"<summary>Tool Executed</summary>\\n"
f"</details>\\n\\n"
)
queue.put_nowait(tool_block)
```
- **致命避坑点 (Critical Pitfalls)**:
1. **属性转义 (Extremely Important)**: `<details>` 内的 `arguments` 和 `result` 属性**必须**将内部的所有双引号 `"` 替换为 `&quot;`。因为 OpenWebUI 前端提取这些数据的 Regex 是严格的 `="([^"]*)"`,一旦内容中出现原生双引号,就会被瞬间截断,导致参数被渲染为空并引发解析错误!
2. **换行符要求**: `<details ...>` 尖括号闭合后紧接着的内容**必须换行**(即 `>\\n`),否则 Markdown 扩展引擎无法将其识别为独立的 UI Block。
3. **去除冗余通知**: 不要在 `tool.execution_start` 事件中提前向对话流输出普通的 `🔧 Executing...` 纯文本块,这会导致最终页面上同时出现两块工具提示(一个文本,一个折叠卡片)。
#### Debug 信息的解耦 (Decoupling Debug Logs)
对于连接建立、运行环境、缓存加载等属于 *脚本自身运行状态* 的 Debug 信息:
- **禁止**: 不要将这些内容 yield 到最终的回答数据流(或塞进 `<think>` 标签内),这会污染回答的纯粹性。
- **推荐**: 统一使用 OpenWebUI 顶部的原生状态反馈气泡Status Events
```python
await __event_emitter__({
"type": "status",
"data": {"description": "连接建立,正在等待响应...", "done": True}
})
```
---
## ⚡ Action 插件规范 (Action Plugin Standards)
@@ -806,8 +1147,7 @@ Filter 实例是**单例 (Singleton)**。
### 1. ✅ 开发检查清单 (Development Checklist)
- [ ] 创建英文版插件代码 (`plugin_name.py`)
- [ ] 创建中文版插件代码 (`plugin_name_cn.py`)
- [ ] 代码实现了内置 i18n 逻辑 (`.py`)
- [ ] 编写英文 README (`README.md`)
- [ ] 编写中文 README (`README_CN.md`)
- [ ] 包含标准化文档字符串
@@ -815,15 +1155,21 @@ Filter 实例是**单例 (Singleton)**。
- [ ] 使用 Lucide 图标
- [ ] 实现 Valves 配置
- [ ] 使用 logging 而非 print
- [ ] 测试双语界面
- [ ] 测试 i18n 界面适配
- [ ] **一致性检查**: 确保文档、代码、README 同步
- [ ] **README 结构**:
- **Key Capabilities** (英文) / **核心功能** (中文): 必须包含所有核心功能
- **What's New** (英文) / **最新更新** (中文): 仅包含最新版本的变更信息
- [ ] **知识沉淀**: 开发过程中发现的非显而易见的规律、踩坑或内部 API 合约,必须记录到 `.agent/learnings/{topic}.md`
### 2. 🔄 一致性维护 (Consistency Maintenance)
任何插件的**新增、修改或移除**,必须同时更新:
1. **插件代码** (version)
2. **项目文档** (`docs/`)
3. **自述文件** (`README.md`)
2. **插件自述文件** (`plugins/{type}/{name}/README.md` & `README_CN.md`)
3. **项目文档** (`docs/plugins/{type}/{name}.md` & `.zh.md`)
4. **项目文档索引** (`docs/plugins/{type}/index.md` & `index.zh.md` — 版本号)
5. **项目根 README** (`README.md` & `README_CN.md` — 更新日期徽章 `![updated](https://img.shields.io/badge/YYYY--MM--DD-gray?style=flat)` 必须同步为发布当天日期)
### 3. 发布工作流 (Release Workflow)
@@ -853,21 +1199,45 @@ Filter 实例是**单例 (Singleton)**。
- Update README/README_CN to include What's New section
- Migration: default TITLE_SOURCE changed to chat_title
### 4. 🤖 Git Operations (Agent Rules)
#### 发布信息生成准则 (Release Summary Generation)
当准备提交时,必须向用户展示以下格式的“发布草案”:
1. **Commit Message**: 符合 Conventional Commits 的英文标题及摘要。
2. **变更列表 (Bilingual Changes)**:
- 英文: Clear descriptions of technical/functional changes.
- 中文: 清晰描述用户可见的功能改进或修复。
3. **核查状态 (Verification)**: 确认版本号已在相关 7+ 处位置同步更新1 个代码文件 + 2 个 README + 4 个 Docs 文件)。
- **允许**: 创建功能分支 (`feature/xxx`),推送到功能分支。
- **禁止**: 直接推送到 `main`,自动合并到 `main`
### 4. 🤖 Git 提交与推送规范 (Git Operations & Push Rules)
- **核心原则**: 默认仅进行**本地文件准备**更新代码、READMEs、Docs、版本号**严禁**在未获用户明确许可的情况下自动执行 `git commit` 或 `git push`。
- **允许 (需确认)**: 只有在用户明确表示“发布”、“Commit it”、“Release”或“提交”后才允许直接推送到 `main` 分支或创建 PR。
- **功能分支**: 推荐在进行大规模重构或实验性功能开发时,创建功能分支 (`feature/xxx`) 进行隔离。
- **PR 提交**: 必须使用 GitHub CLI (`gh`) 创建 Pull Request。示例`gh pr create --title "feat: ..." --body "..."`。
### 5. 🤝 贡献者认可规范 (Contributor Recognition)
使用 `@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)
- [Action 插件模板 (英文)](plugins/actions/ACTION_PLUGIN_TEMPLATE.py)
- [Action 插件模板 (中文)](plugins/actions/ACTION_PLUGIN_TEMPLATE_CN.py)
- [Action 插件模板](plugins/actions/ACTION_PLUGIN_TEMPLATE.py)
- [插件开发指南](plugins/actions/PLUGIN_DEVELOPMENT_GUIDE.md)
- [Lucide Icons](https://lucide.dev/icons/)
- [OpenWebUI 文档](https://docs.openwebui.com/)
@@ -877,8 +1247,9 @@ Filter 实例是**单例 (Singleton)**。
## Author
Fu-Jie
GitHub: [Fu-Jie/awesome-openwebui](https://github.com/Fu-Jie/awesome-openwebui)
GitHub: [Fu-Jie/openwebui-extensions](https://github.com/Fu-Jie/openwebui-extensions)
## License
MIT License
```

21
.github/gh-aw/README.md vendored Normal file
View 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.

View 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`

View 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 源文件

View 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`

View File

@@ -0,0 +1,54 @@
---
name: Plugin Code Review
description: Comprehensive OpenWebUI plugin review checklist covering i18n, context helpers, antigravity safety, and streaming compatibility
applyTo: "plugins/**/*.py"
---
# Code Review Instructions — OpenWebUI Plugins
You are an expert Senior Software Engineer reviewing OpenWebUI plugins for the `openwebui-extensions` repository.
When reviewing plugin code, you MUST verify each point below to ensure the code meets the strict repository standards.
## 1. Single-file i18n Pattern (CRITICAL)
- **One File Rule**: One `.py` file per plugin. No `_cn.py` or language-split files.
- **Translations**: All user-visible strings (status, notification, UI text) MUST go through a `TRANSLATIONS` dictionary and a `FALLBACK_MAP`.
- **Safety**: `format(**kwargs)` calls on translated strings MUST be wrapped in `try/except KeyError` to prevent crashes if a translation is missing a placeholder.
## 2. Context Helpers (CRITICAL)
- **User Context**: MUST use `_get_user_context(__user__)` instead of direct `__user__["name"]` access. `__user__` can be a list, dict, or None.
- **Chat Context**: MUST use `_get_chat_context(body, __metadata__)` instead of ad-hoc `body.get("chat_id")` calls.
## 3. Event & Logging
- **No Print**: No bare `print()` in production code. Use `logging.getLogger(__name__)`.
- **Emitter Safety**: Every `await emitter(...)` call MUST be guarded by `if emitter:` (or equivalent).
- **Status Lifecycle**:
- `_emit_status(done=False)` at task start.
- `_emit_status(done=True)` on completion.
- `_emit_notification("error")` on failure.
## 4. Antigravity Safety (CRITICAL)
- **Timeout Guards**: All `__event_call__` JS executions MUST be wrapped with `asyncio.wait_for(..., timeout=2.0)`. Failure to do this can hang the entire backend.
- **JS Fallbacks**: JS code executed via `__event_call__` MUST have an internal `try { ... } catch (e) { return fallback; }` block.
- **Path Sandboxing**: File path operations MUST be validated against the workspace root (no directory traversal vulnerabilities).
- **Upload Fallbacks**: Upload paths MUST have a dual-channel fallback (API → local/DB).
## 5. Filter Singleton Safety
- **No Mutable State**: Filter plugins are singletons. There MUST be NO request-scoped mutable state stored on `self` (e.g., `self.current_user = ...`).
- **Statelessness**: Per-request values MUST be computed from `body` and context helpers on each call.
## 6. Copilot SDK Tools
- **Pydantic Models**: Tool parameters MUST be defined as a `pydantic.BaseModel` subclass.
- **Explicit Params**: `define_tool(...)` MUST include `params_type=MyParams`.
- **Naming**: Tool names MUST match `^[a-zA-Z0-9_-]+$` (ASCII only).
## 7. Streaming Compatibility (OpenWebUI 0.8.x)
- **Thinking Tags**: The `</think>` tag MUST be closed before any normal content or tool cards are emitted.
- **Attribute Escaping**: Tool card `arguments` and `result` attributes MUST escape `"` as `&quot;`.
- **Newline Requirement**: The `<details type="tool_calls" ...>` block MUST be followed by a newline immediately after `>`.
## 8. Performance & Memory
- **Streaming**: Large files or responses MUST be streamed, not loaded entirely into memory.
- **Database Connections**: Plugins MUST reuse the OpenWebUI internal database connection (`owui_engine`, `owui_Session`) rather than creating new ones.
## 9. HTML Injection (Action Plugins)
- **Wrapper Template**: HTML output MUST use the standard `<!-- OPENWEBUI_PLUGIN_OUTPUT -->` wrapper.
- **Idempotency**: The plugin MUST implement `_remove_existing_html` to ensure multiple runs do not duplicate the HTML output.

View File

@@ -0,0 +1,90 @@
---
name: Commit Message
description: Comprehensive Conventional Commits guidelines for openwebui-extensions
---
# Commit Message Instructions
You are an expert developer generating commit messages for the `openwebui-extensions` repository.
Always adhere to the following strict guidelines based on the Conventional Commits specification.
## 1. General Rules
- **Language**: **English ONLY**. Never use Chinese or other languages in the commit title or body.
- **Structure**:
```text
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
## 2. Type (`<type>`)
Must be one of the following:
- `feat`: A new feature or a new plugin.
- `fix`: A bug fix.
- `docs`: Documentation only changes (e.g., README, MkDocs).
- `refactor`: A code change that neither fixes a bug nor adds a feature.
- `perf`: A code change that improves performance.
- `test`: Adding missing tests or correcting existing tests.
- `chore`: Changes to the build process, CI/CD, or auxiliary tools/scripts.
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, etc.).
## 3. Scope (`<scope>`)
The scope should indicate the affected component or plugin.
- **For Plugins**: Use the plugin's folder name or category (e.g., `actions`, `filters`, `pipes`, `export-to-docx`, `github-copilot-sdk`).
- **For Docs**: Use `docs` or the specific doc section (e.g., `guide`, `readme`).
- **For Infra**: Use `ci`, `scripts`, `deps`.
- *Note*: Omit the scope if the change is global or spans too many components.
## 4. Subject Line (`<subject>`)
- **Length**: Keep it under 50-72 characters.
- **Mood**: Use the imperative, present tense: "change" not "changed" nor "changes" (e.g., "add feature" instead of "added feature").
- **Formatting**: Do not capitalize the first letter. Do not place a period `.` at the end.
- **Clarity**: State exactly *what* changed. Avoid vague terms like "update code" or "fix bug".
## 5. Body (`<body>`)
- **When to use**: Highly recommended for `feat`, `fix`, and `refactor`.
- **Content**: Explain *what* and *why* (motivation), not just *how* (the code diff shows the how).
- **Format**: Use a bulleted list (1-3 points) for readability.
- **Repo Specifics**: If the commit involves a plugin version bump, explicitly mention that the READMEs and docs were synced.
## 6. Footer / Breaking Changes (`<footer>`)
- If the commit introduces a breaking change (e.g., changing a Valve configuration key, altering a plugin's output format), append `!` after the scope/type: `feat(pipes)!: ...`
- Add a `BREAKING CHANGE:` block in the footer explaining the migration path.
## 7. Examples
**Example 1: Feature with Body**
```text
feat(github-copilot-sdk): add antigravity timeout guards
- Wrap all __event_call__ JS executions with asyncio.wait_for(timeout=2.0)
- Add dual-channel upload fallback (API → local/DB)
- Emit staged status events for tasks > 3 seconds
```
**Example 2: Bug Fix**
```text
fix(export-to-docx): resolve missing title fallback
- Fallback to user_name + date when chat_title is empty
- Prevent crash when metadata variables are missing
```
**Example 3: Documentation Sync**
```text
docs(plugins): sync bilingual READMEs for v1.2.0 release
- Update What's New section for folder-memory plugin
- Sync docs/plugins/filters/folder-memory.md
```
**Example 4: Breaking Change**
```text
refactor(core)!: rename global configuration valves
- Standardize all valve keys to UPPER_SNAKE_CASE
- Remove deprecated legacy_api_key field
BREAKING CHANGE: Users must reconfigure their API keys in the UI as the old `api_key` field is no longer read.
```

View 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) |`
`| :--- | ---: |`
`| ![followers](...) | ![points](...) | ![top](...) | ![contributions](...) | ![downloads](...) | ![saves](...) | ![views](...) |`
`| :---: | :---: | :---: | :---: | :---: | :---: | :---: |`
Chinese example:
`| 作者:[Fu-Jie](https://github.com/Fu-Jie) · vx.y.z | [⭐ 点个 Star 支持项目](https://github.com/Fu-Jie/openwebui-extensions) |`
`| :--- | ---: |`
`| ![followers](...) | ![points](...) | ![top](...) | ![contributions](...) | ![downloads](...) | ![saves](...) | ![views](...) |`
`| :---: | :---: | :---: | :---: | :---: | :---: | :---: |`
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

View File

@@ -0,0 +1,54 @@
---
name: Test Generation
description: Comprehensive Pytest conventions, mocking strategies, and model usage rules for OpenWebUI plugins
applyTo: "plugins/debug/**,tests/**"
---
# Test Generation Instructions
You are an expert SDET (Software Development Engineer in Test) writing tests for the `openwebui-extensions` repository.
Follow these comprehensive guidelines to ensure robust, reliable, and cost-effective testing.
## 1. Test Structure & Placement
- **Unit Tests**: Place in the `tests/` directory at the root of the repository. Name files `test_<module>.py`.
- **Integration/Debug Scripts**: Place in `plugins/debug/<plugin_name>/`. Name files `debug_<feature>.py` or `inspect_<feature>.py`.
- **Fixtures**: Use `conftest.py` for shared fixtures (e.g., mock users, mock emitters, mock database sessions).
## 2. Model Usage & Cost Control (CRITICAL)
When writing tests or debug scripts that actually invoke an LLM:
- **Allowed Models**: You MUST use low-cost models: `gpt-5-mini` (Preferred) or `gpt-4.1`.
- **Forbidden**: NEVER use expensive models (like `gpt-4-turbo`, `claude-3-opus`) in automated tests unless explicitly requested by the user.
- **API Keys**: Never hardcode API keys. Always read from environment variables (`os.getenv("OPENAI_API_KEY")`) or a `.env` file.
## 3. Mocking OpenWebUI Internals
OpenWebUI plugins rely heavily on injected runtime variables. Your tests must mock these accurately:
- **`__user__`**: Mock as a dictionary. Always test both with a full user object and an empty/None object to ensure fallback logic works.
```python
mock_user_en = {"id": "u1", "name": "Alice", "language": "en-US"}
mock_user_zh = {"id": "u2", "name": "Bob", "language": "zh-CN"}
mock_user_none = None
```
- **`__event_emitter__`**: Mock as an async callable that records emitted events for assertion.
```python
async def mock_emitter(event: dict):
emitted_events.append(event)
```
- **`__event_call__`**: Mock as an async callable. To test Antigravity timeout guards, you must occasionally mock this to sleep longer than the timeout (e.g., `await asyncio.sleep(3.0)`) to ensure `asyncio.wait_for` catches it.
## 4. Testing Async Code
- All OpenWebUI plugin entry points (`action`, `inlet`, `outlet`) are asynchronous.
- Use `@pytest.mark.asyncio` for all test functions.
- Ensure you `await` all plugin method calls.
## 5. i18n (Internationalization) Testing
Since all plugins must be single-file i18n:
- **Mandatory**: Write parameterized tests to verify output in both English (`en-US`) and Chinese (`zh-CN`).
- Verify that if an unsupported language is passed (e.g., `fr-FR`), the system correctly falls back to the default (usually `en-US`).
## 6. Antigravity & Safety Testing
- **Timeout Guards**: Explicitly test that frontend JS executions (`__event_call__`) do not hang the backend. Assert that a `TimeoutError` is caught and handled gracefully.
- **State Leakage**: For `Filter` plugins (which are singletons), write tests that simulate concurrent requests from different users to ensure no state leaks across `self`.
## 7. Assertions & Best Practices
- Assert on **behavior and output**, not internal implementation details.
- For HTML/Markdown generation plugins, use Regex or BeautifulSoup to assert the presence of required tags (e.g., `<!-- OPENWEBUI_PLUGIN_OUTPUT -->`) rather than exact string matching.
- Keep tests isolated. Do not rely on the execution order of tests.

71
.github/skills/README.md vendored Normal file
View 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.

View 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
.github/skills/doc-mirror-sync/SKILL.md vendored Normal file
View 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.

View 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()

View 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>`.

View File

@@ -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

View 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!"

View 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

View 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)

View 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
.github/skills/i18n-validator/SKILL.md vendored Normal file
View 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.

View 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])

View File

@@ -0,0 +1,20 @@
---
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
- 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

View File

@@ -0,0 +1,38 @@
# {{TITLE}}
| By [Fu-Jie](https://github.com/Fu-Jie) · v0.1.0 | [⭐ Star this repo](https://github.com/Fu-Jie/openwebui-extensions) |
| :--- | ---: |
| ![followers](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_followers.json&label=%F0%9F%91%A5&style=flat) | ![points](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_points.json&label=%E2%AD%90&style=flat) | ![top](https://img.shields.io/badge/%F0%9F%8F%86-Top%20%3C1%25-10b981?style=flat) | ![contributions](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_contributions.json&label=%F0%9F%93%A6&style=flat) | ![downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_downloads.json&label=%E2%AC%87%EF%B8%8F&style=flat) | ![saves](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_saves.json&label=%F0%9F%92%BE&style=flat) | ![views](https://img.shields.io/endpoint?url=https%3A%2F%2Fgist.githubusercontent.com%2FFu-Jie%2Fdb3d95687075a880af6f1fba76d679c6%2Fraw%2Fbadge_views.json&label=%F0%9F%91%81%EF%B8%8F&style=flat) |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
{{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.

View 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

View 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

View 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
.github/skills/pr-reviewer/SKILL.md vendored Normal file
View 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
.github/skills/pr-submitter/SKILL.md vendored Normal file
View 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

Some files were not shown because too many files have changed in this diff Show More