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
This commit is contained in:
Fu-Jie
2026-02-28 03:50:56 +08:00
committed by GitHub
parent f47c3f6354
commit 0c7201902c
26 changed files with 4564 additions and 441 deletions

View File

@@ -0,0 +1,76 @@
# 📤 `publish_file_from_workspace` Tool Guide
This document explains the recommended usage contract of the built-in `publish_file_from_workspace` tool in the GitHub Copilot SDK Pipe.
## Tool Purpose
Use this tool when the agent has generated a file in the current workspace and needs to:
- Save the file into OpenWebUI file storage.
- Return stable links for preview and download.
- Keep rendering behavior consistent across local disk and object storage backends.
## Required Input
- `filename`: Relative filename under current workspace.
- ✅ Example: `report.xlsx`
- ✅ Example: `output/summary.html`
- ❌ Avoid temporary paths outside workspace (e.g. `/tmp/...`).
## Output Contract
The tool typically returns structured fields used by the pipe to build user-facing links:
- `filename`
- `download_url`
- `preview_url` (if preview is available)
- metadata used by renderer (including optional `html_embed` for HTML previews)
## Embed Modes
### 1) `artifacts` (default)
- Message should include `[Preview]` + `[Download]` links.
- For HTML-capable content, `html_embed` may be rendered in a ```html block.
- Best for inline interactive previews in chat.
### 2) `richui`
- Message should include `[Preview]` + `[Download]` links.
- Integrated preview is emitted by Rich UI renderer automatically.
- Do not output iframe/html preview block in chat body.
## PDF Safety Rule (Mandatory)
For PDF files, always output markdown links only:
- `[Preview](...)`
- `[Download](...)` (if available)
Do NOT embed PDFs with iframe or raw HTML blocks.
## Recommended Workflow
1. Generate file in workspace.
2. Call `publish_file_from_workspace(filename=...)`.
3. Return links according to selected embed mode.
4. Follow PDF safety rule for any `.pdf` output.
## Practical Example
### Example A: HTML report (artifacts)
- Publish `analysis.html`.
- Return links.
- Allow `html_embed` block rendering for direct preview.
### Example B: PDF report
- Publish `audit.pdf`.
- Return links only.
- Skip iframe/html embedding entirely.
## Related Docs
- [Skills Manager Guide](./SKILLS_MANAGER.md)
- [Skills Best Practices](./SKILLS_BEST_PRACTICES.md)

View File

@@ -0,0 +1,76 @@
# 📤 `publish_file_from_workspace` 工具指南
本文档说明 GitHub Copilot SDK Pipe 内置工具 `publish_file_from_workspace` 的推荐使用规范。
## 工具用途
当 Agent 在当前工作区生成文件后,使用此工具可实现:
- 将文件发布到 OpenWebUI 文件存储。
- 返回稳定可用的预览/下载链接。
- 在本地磁盘与对象存储后端保持一致交付行为。
## 必填参数
- `filename`:工作区内的相对路径文件名。
- ✅ 示例:`report.xlsx`
- ✅ 示例:`output/summary.html`
- ❌ 避免工作区外临时路径(如 `/tmp/...`)。
## 返回结构(常见字段)
该工具通常返回用于构建前端链接与渲染的数据:
- `filename`
- `download_url`
- `preview_url`(如可预览)
- 渲染元数据HTML 场景可含 `html_embed`
## 发布模式
### 1) `artifacts`(默认)
- 消息中返回 `[Preview]` + `[Download]`
- 对于 HTML 可预览内容,可在 ```html 代码块中渲染 `html_embed`。
- 适用于聊天内联交互式预览。
### 2) `richui`
- 消息中返回 `[Preview]` + `[Download]`
- 由 Rich UI 渲染器自动输出集成预览。
- 聊天正文中不输出 iframe/html 预览块。
## PDF 安全规则(强制)
针对 PDF 文件,必须只输出 Markdown 链接:
- `[Preview](...)`
- `[Download](...)`(可用时)
禁止使用 iframe 或 HTML 代码块嵌入 PDF。
## 推荐流程
1. 在工作区生成文件。
2. 调用 `publish_file_from_workspace(filename=...)`
3. 按模式返回链接。
4. 若为 `.pdf`,严格执行“仅链接”规则。
## 示例
### 示例 AHTML 报告artifacts
- 发布 `analysis.html`
- 返回链接。
- 允许渲染 `html_embed` 进行直接预览。
### 示例 BPDF 报告
- 发布 `audit.pdf`
- 仅返回链接。
- 完全跳过 iframe/html 嵌入。
## 相关文档
- [manage_skills 工具指南](./SKILLS_MANAGER_CN.md)
- [Skills 最佳实践](./SKILLS_BEST_PRACTICES_CN.md)

View File

@@ -1,6 +1,6 @@
# GitHub Copilot SDK Pipe for OpenWebUI
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 0.8.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
**Author:** [Fu-Jie](https://github.com/Fu-Jie) | **Version:** 0.9.0 | **Project:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **License:** MIT
This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/open-webui) that integrates the official [GitHub Copilot SDK](https://github.com/github/copilot-sdk). It enables you to use **GitHub Copilot models** (e.g., `gpt-5.2-codex`, `claude-sonnet-4.5`,`gemini-3-pro`, `gpt-5-mini`) **AND** your own models via **BYOK** (OpenAI, Anthropic) directly within OpenWebUI, providing a unified agentic experience with **strict User & Chat-level Workspace Isolation**.
@@ -14,37 +14,33 @@ This is an advanced Pipe function for [OpenWebUI](https://github.com/open-webui/
---
## ✨ v0.8.0 Updates (What's New)
## ✨ v0.9.0: The Skills Revolution & Stability Update
- **🎛️ Conditional Tool Filtering (P1~P4)**: Four-priority tool permission system. **Default ON**: If no tools are selected in Chat UI (P4), all enabled tools are active. **Whitelist Mode**: Once specific tools are checked, the whitelist strictly filters both OpenWebUI tools and MCP servers. Admin-level `config.enable` (P2) allows global server disabling. (v0.8.0)
- **🔧 File Publish Reliability**: Fixed `Error getting file content` across all storage backends (local/S3/GCS/Azure) by using `Storage.upload_file()` directly in the fallback path. HTML files are no longer blocked by `ALLOWED_FILE_EXTENSIONS` (`?process=false` always applied). (v0.8.0)
- **🌐 HTML Direct Access Link**: When `publish_file_from_workspace` publishes an HTML file, the plugin also provides a directly accessible HTML link for instant in-chat preview/opening. (v0.8.0)
- **🔒 Strict File URL Format**: Published file links must be relative paths starting with `/api/v1/files/` (e.g., `/api/v1/files/{id}/content/html`). Do not use `api/...` and do not prepend any domain. (v0.8.0)
- **🛠️ CLI Built-in Tools Always Available**: `available_tools` is now always `None`, ensuring Copilot CLI built-ins (e.g. `bash`, `create_file`) are never silently blocked regardless of MCP configuration. (v0.8.0)
- **📌 Publish Tool Always Injected**: `publish_file_from_workspace` is no longer lost when `ENABLE_OPENWEBUI_TOOLS` is disabled. (v0.8.0)
- ** Code Interpreter Limitation**: The `code_interpreter` tool runs in a remote, ephemeral environment. A system prompt warning now clarifies that it cannot access local files or persist changes. (v0.8.0)
### 🐞 Bug Fixes in v0.8.0
- Fixed `{"detail":"[ERROR: Error getting file content]"}` when publishing files under object storage backends by replacing fallback manual copy/DB writes with `Storage.upload_file()`.
- Fixed HTML artifact upload being rejected by `ALLOWED_FILE_EXTENSIONS` by always appending `?process=false` on file upload API calls.
- Fixed invalid artifact links generated as `api/...` or domain-prefixed absolute URLs; links are now constrained to `/api/v1/files/...` relative paths.
- Fixed Copilot CLI built-ins being silently unavailable when no server tools were configured/loaded (which resulted in `available_tools=[]`); now `available_tools` remains `None`.
- Fixed `publish_file_from_workspace` disappearing when `ENABLE_OPENWEBUI_TOOLS` was disabled.
- **🧩 Copilot SDK Skills Support**: Native support for Copilot SDK skill directories (`SKILL.md` + resources). Skills can now be loaded as first-class runtime context.
- **🔄 OpenWebUI Skills Bridge**: Full bidirectional sync between OpenWebUI **Workspace > Skills** and SDK skill directories.
- **🛠️ Deterministic `manage_skills` Tool**: Expert tool for stable install/create/list/edit/delete skill operations.
- **🌊 Reinforced Status Bar**: Multi-layered locking mechanism (`session_finalized` guard) and atomic async delivery to prevent "stuck" indicators.
- **⚡ Asynchronous Integrity**: Refactored status emission to route all updates through a centralized helper, ensuring atomic delivery and preventing race conditions in parallel execution streams.
- **💓 Pulse-Lock Refresh**: Implemented a hardware-inspired "pulse" logic that forces a final UI state refresh at the end of each session, ensuring the status bar settling on "Task completed."
- **🗂 Persistent Config Directory**: Added `COPILOTSDK_CONFIG_DIR` for stable session-state persistence across container restarts.
---
## ✨ Key Capabilities
- **🔑 Flexible Auth & BYOK**: Official Copilot subscriptions (PAT) or Bring Your Own Key (OpenAI/Anthropic).
- **🔌 Universal Tool Protocol**: Native support for **MCP (Model Context Protocol)**, OpenAPI, and OpenWebUI built-in tools.
- **🛡️ Sandbox Workspace Isolation**: Strict per-session sandboxing for data privacy and security.
- **♾️ Infinite Session Management**: Smart context window management with automatic compaction for indefinite conversation capability.
- **🧠 Deep Database Integration**: Real-time persistence of TOD·O lists for long-running workflows.
- **🌊 Advanced Streaming**: Full support for thinking process/Chain of Thought visualization.
- **🖼️ Intelligent Multimodal**: Vision capabilities and raw file analysis support (bypasses RAG for direct binary access).
- **📤 Workspace Artifacts (`publish_file_from_workspace`)**: Agents can generate files (Excel, CSV, HTML reports, etc.) and provide **persistent download links** directly in the chat. For HTML files, a direct-access HTML link is also provided.
- **🖼️ Interactive Artifacts**: Automatically renders HTML/JS apps generated by the agent directly in the chat interface.
- **🔑 Unified Intelligence (Official + BYOK)**: Seamlessly switch between official GitHub Copilot models (o1, GPT-4o, Claude 3.5 Sonnet, Gemini 2.0 Flash) and your own models (OpenAI, Anthropic) via **Bring Your Own Key** mode.
- **🛡️ Physical Workspace Isolation**: Every session runs in its own isolated directory sandbox. This ensures absolute data privacy and prevents cross-chat file contamination while allowing the Agent full filesystem access.
- **🔌 Universal Tool Protocol**:
- **Native MCP**: Direct, high-performance connection to Model Context Protocol servers.
- **OpenAPI Bridge**: Connect to any external REST API as an Agent tool.
- **OpenWebUI Native**: Zero-config bridge to your existing OpenWebUI tools and built-ins (Web Search, Memory, etc.).
- **🧩 OpenWebUI Skills Bridge**: Transforms simple OpenWebUI Markdown instructions into powerful SDK skill folders complete with supporting scripts, templates, and data.
- **♾️ Infinite Session Management**: Advanced context window management with automatic "Compaction" (summarization + list persistence). Carry out weeks-long projects without losing the core thread.
- **📊 Interactive Artifacts & Publishing**:
- **Live HTML/JS**: Instantly render and interact with apps, dashboards, or reports generated by the Agent.
- **Persistent Publishing**: Agents can "publish" generated files (Excel, CSV, docs) to OpenWebUI's file storage, providing permanent download links.
- **🌊 UX-First Streaming**: Full support for "Thinking" processes (Chain of Thought), status indicators, and real-time progress bars for long-running tasks.
- **🧠 Deep Database Integration**: Real-time persistence of TOD·O lists and session metadata ensures your workflow state is always visible in the UI.
---
@@ -69,9 +65,14 @@ Administrators define the default behavior for all users in the function setting
| Valve | Default | Description |
| :--- | :--- | :--- |
| `GH_TOKEN` | `""` | Global GitHub Token (Requires 'Copilot Requests' permission). |
| `COPILOTSDK_CONFIG_DIR` | `""` | Persistent directory for SDK config and session state (e.g., `/app/backend/data/.copilot`). |
| `ENABLE_OPENWEBUI_TOOLS` | `True` | Enable OpenWebUI Tools (includes defined Tools and Built-in Tools). |
| `ENABLE_OPENAPI_SERVER` | `True` | Enable OpenAPI Tool Server connection. |
| `ENABLE_MCP_SERVER` | `True` | Enable Direct MCP Client connection (Recommended). |
| `ENABLE_OPENWEBUI_SKILLS` | `True` | Enable bidirectional sync with OpenWebUI Workspace > Skills. |
| `OPENWEBUI_SKILLS_SHARED_DIR` | `/app/backend/data/cache/copilot-openwebui-skills` | Shared cache directory for skills. |
| `GITHUB_SKILLS_SOURCE_URL` | `""` | Optional GitHub tree URL for batch skill import (e.g., anthropic/skills). |
| `DISABLED_SKILLS` | `""` | Comma-separated skill names to disable in SDK session. |
| `REASONING_EFFORT` | `medium` | Reasoning effort level: low, medium, high. |
| `SHOW_THINKING` | `True` | Show model reasoning/thinking process. |
| `INFINITE_SESSION` | `True` | Enable Infinite Sessions (automatic context compaction). |
@@ -95,10 +96,64 @@ Standard users can override these settings in their individual Profile/Function
| `SHOW_THINKING` | Show model reasoning/thinking process. |
| `MAX_MULTIPLIER` | Maximum allowed billing multiplier override. |
| `EXCLUDE_KEYWORDS` | Exclude models containing these keywords. |
| `ENABLE_OPENWEBUI_SKILLS` | Enable loading all active OpenWebUI skills readable by you into SDK `SKILL.md` directories. |
| `GITHUB_SKILLS_SOURCE_URL` | Optional GitHub tree URL for batch skill import in your own session. |
| `DISABLED_SKILLS` | Comma-separated skill names to disable for your own session. |
| `BYOK_API_KEY` | Use your personal OpenAI/Anthropic API Key. |
---
### 📤 Enhanced Publishing & Interactive Components
The `publish_file_from_workspace` tool now uses a clearer delivery contract for production use:
- **Artifacts mode (`artifacts`, default)**: Agent returns `[Preview]` + `[Download]` and may output `html_embed` in a ```html block for direct chat rendering.
- **Rich UI mode (`richui`)**: Agent returns `[Preview]` + `[Download]` only; integrated preview is rendered automatically via emitter (no iframe block in message).
- **📄 PDF delivery safety rule**: Always output Markdown links only (`[Preview]` + `[Download]` when available). **Do not embed PDF via iframe/html blocks.**
- **⚡ Stable dual-channel publishing**: Keeps interactive viewing and persistent file download aligned across local/object-storage backends.
- **✅ Status integration**: Emits real-time publishing progress and completion feedback to the OpenWebUI status bar.
- **📘 Publishing Tool Guide (GitHub)**: [publish_file_from_workspace Guide](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/PUBLISH_FILE_FROM_WORKSPACE.md)
---
### 🧩 OpenWebUI Skills Bridge & `manage_skills` Tool
The SDK now features a bidirectional bridge with the OpenWebUI **Workspace > Skills** page:
- **🔄 Automatic Sync**: Skills created or updated in the OpenWebUI UI are automatically downloaded as `SKILL.md` folders into the SDK's shared cache on every request.
- **🛠️ `manage_skills` Tool**: The Agent can deterministically manage skills using this tool.
- `list`: List all installed skills and their descriptions.
- `install`: Install a skill from a GitHub URL (auto-normalized to archive link) or a direct `.zip`/`.tar.gz`.
- `create`: Create a new skill directory from context, writing `SKILL.md` and any extra resource files (scripts, templates).
- `edit`: Update an existing skill folder.
- `delete`: Atomically delete both the local directory and the linked OpenWebUI DB entry.
- **📁 Full Folder Support**: Unlike the single-markdown storage in OpenWebUI DB, the SDK loads the **entire folder** for each skill. This allows skills to carry binary scripts, data files, or complex templates alongside the core instructions.
- **🌐 Shared Persistent Cache**: Skills are stored in `OPENWEBUI_SKILLS_SHARED_DIR/shared/`, which is persistent across sessions and container restarts.
- **📚 Full Skill Docs (GitHub)**: [manage_skills Tool Guide](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/SKILLS_MANAGER.md) | [Skills Best Practices](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/SKILLS_BEST_PRACTICES.md)
---
### 🌊 Fluid UX & Granular Status Feedback
Say goodbye to the "stuck" feeling during complex processing:
- **🔄 Real-Time Status Bubbles**: Maps internal SDK events (`turn_start`, `compaction`, `subagent_started`) directly to the OpenWebUI status bar.
- **🧭 Richer Stage Descriptions**: Status text now explicitly reflects phases such as processing, skill invocation, tool execution, tool completion/failure, publishing, and final completion.
- **⏱️ Long-Task Heartbeat**: During long waits, the status bar emits periodic "still processing" updates (elapsed-time style) to avoid silent stalls.
- **📈 Tool Progress Tracking**: Long-running tool executions provide live progress percentages and descriptive sub-task updates in the status bar.
- **⚡ Immediate Feedback**: Response starts with an instant "Assistant is processing" status, eliminating idle wait time before the first token.
---
### 🛡️ Smart Version Compatibility
The plugin automatically adapts its feature set based on your OpenWebUI version:
- **v0.8.0+**: Rich UI, live status bubbles, and integrated HTML preview.
- **Older**: Automatic fallback to standard Markdown blocks for maximum stability.
---
## 🎯 Use Cases (What can you do?)
- **📁 Fully Autonomous DevOps**: Agent analyzes code, runs tests, and applies patches within its isolated sandbox.
@@ -141,7 +196,7 @@ If neither is configured, the model list will not appear.
## 📋 Troubleshooting & Dependencies
- **Agent ignores files?**: Ensure the Files Filter is enabled, otherwise RAG will interfere with raw binaries.
- **No progress bar?**: The bar only appears when the Agent uses the `update_todo` tool.
- **No status updates?**: Status bubbles are emitted for processing/tool phases; TODO progress bars specifically appear when the Agent uses `update_todo`.
- **Dependencies**: This Pipe automatically manages `github-copilot-sdk` (Python) and utilizes the bundled binary CLI. No manual install required.
---

View File

@@ -1,50 +1,43 @@
# GitHub Copilot SDK 官方管道
**作者:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **版本:** 0.8.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
**作者:** [Fu-Jie](https://github.com/Fu-Jie/openwebui-extensions) | **版本:** 0.9.0 | **项目:** [OpenWebUI Extensions](https://github.com/Fu-Jie/openwebui-extensions) | **许可证:** MIT
这是一个用于 [OpenWebUI](https://github.com/open-webui/open-webui) 的高级 Pipe 函数,深度集成了 **GitHub Copilot SDK**。它不仅支持 **GitHub Copilot 官方模型**(如 `gpt-5.2-codex`, `claude-sonnet-4.5`, `gemini-3-pro`, `gpt-5-mini`),还支持 **BYOK (自带 Key)** 模式对接自定义服务商OpenAI, Anthropic并具备**严格的用户与会话级工作区隔离**能力,提供统一且安全的 Agent 交互体验。
> [!IMPORTANT]
> **核心伴侣组件**
> 如需启用文件处理与数据分析能力,请务必安装 [GitHub Copilot SDK Files Filter](https://openwebui.com/posts/403a62ee-a596-45e7-be65-fab9cc249dd6)。
> [!TIP]
> **BYOK 模式无需订阅**
> 如果您使用自带的 API Key (BYOK 模式对接 OpenAI/Anthropic)**您不需要 GitHub Copilot 官方订阅**。只有在访问 GitHub 官方模型时才需要订阅。
---
## ✨ 0.8.0 更新内容 (What's New)
## ✨ 0.9.0 核心更新:技能革命与稳定性加固
- **🎛️ 条件工具过滤 (P1~P4)**: 四优先级工具权限体系。**默认全开**: 若未在 Chat UI (P4) 勾选任何工具,则默认启用所有工具;**白名单模式**: 一旦勾选特定工具,即刻进入严格过滤模式,且 MCP server 同步受控;管理员亦可通过 `config.enable` (P2) 全局禁用工具服务器。(v0.8.0)
- **🔧 文件发布全面修复**: 通过在回退路径直接调用 `Storage.upload_file()`彻底修复了所有存储后端local/S3/GCS/Azure下的 `Error getting file content` 问题;同时上传时自动携带 `?process=false`HTML 文件不再被 `ALLOWED_FILE_EXTENSIONS` 拦截。(v0.8.0)
- **🌐 HTML 直达链接**: 当 `publish_file_from_workspace` 发布的是 HTML 文件时,插件会额外提供可直接访问的 HTML 链接,便于在聊天中即时预览/打开。(v0.8.0)
- **🔒 文件链接格式严格约束**: 发布链接必须是以 `/api/v1/files/` 开头的相对路径(例如 `/api/v1/files/{id}/content/html`)。禁止使用 `api/...`,也禁止拼接任何域名。(v0.8.0)
- **🛠 CLI 内置工具始终可用**: `available_tools` 统一设为 `None`Copilot CLI 内置工具(如 `bash``create_file`)无论 MCP 配置如何都不会被静默屏蔽。(v0.8.0)
- **📌 发布工具始终注入**: 即使 `ENABLE_OPENWEBUI_TOOLS` 关闭,`publish_file_from_workspace` 工具也不再丢失。(v0.8.0)
- **⚠️ 代码解释器限制**: `code_interpreter` 工具运行在远程临时环境中。系统提示词现已包含警告,明确指出该工具无法访问本地文件或持久化更改。(v0.8.0)
### 🐞 v0.8.0 Bug 修复说明
- 修复了对象存储后端发布文件时出现的 `{"detail":"[ERROR: Error getting file content]"}`,回退路径从手动复制/写库改为 `Storage.upload_file()`
- 修复了 HTML 产物被 `ALLOWED_FILE_EXTENSIONS` 拦截的问题,上传接口统一追加 `?process=false`
- 修复了产物链接偶发被生成成 `api/...` 或带域名绝对 URL 的问题,现统一限制为 `/api/v1/files/...` 相对路径。
- 修复了在未配置/未加载任何 server 工具时(最终出现 `available_tools=[]`Copilot CLI 内置工具被静默禁用的问题,现统一保持 `available_tools=None`
- 修复了 `ENABLE_OPENWEBUI_TOOLS` 关闭时 `publish_file_from_workspace` 工具丢失的问题。
- **🧩 Copilot SDK Skills 原生支持**: 技能可作为一等上下文能力被加载和使用。
- **🔄 OpenWebUI Skills 桥接**: 实现 OpenWebUI **工作区 > Skills** 与 SDK 技能目录的深度双向同步。
- **🛠️ 确定性 `manage_skills` 工具**: 通过稳定工具契约完成技能的生命周期管理。
- **🌊 状态栏逻辑加固**: 引入 `session_finalized` 多层锁定机制,彻底解决任务完成后状态栏回弹或卡死的问题。
- **🗂 环境目录持久化**: 增强 `COPILOTSDK_CONFIG_DIR` 逻辑,确保会话状态跨容器重启稳定存在。
---
## ✨ 核心能力 (Key Capabilities)
- **🔑 灵活鉴权与 BYOK**: 支持 GitHub Copilot 官方订阅 (PAT) 或自带 Key (OpenAI/Anthropic)
- **🔌 通用工具协议**: 原生支持 **MCP (Model Context Protocol)**、OpenAPI 以及 OpenWebUI 内置工具
- **🛡️ 物理级工作区隔离**: 强制执行严格的用户特定沙箱,确保数据隐私与文件安全。
- **♾️ 无限会话管理**: 智能上下文窗口管理与自动压缩算法,支持无限时长的对话交互
- **🧠 深度数据库集成**: 实时持久化 TOD·O 列表到 UI 进度条
- **🌊 深度推理展示**: 完整支持模型思考过程 (Thinking Process) 的流式渲染
- **🖼️ 智能多模态**: 完整支持图像识别与附件上传分析(绕过 RAG 直接访问原始二进制内容)
- **📤 工作区产物工具 (`publish_file_from_workspace`)**: Agent 可生成文件Excel、CSV、HTML 报告等)并直接在聊天中提供**持久化下载链接**。若为 HTML 文件,还会额外提供可直接访问的 HTML 链接
- **🖼️ 交互式伪影 (Artifacts)**: 自动渲染 Agent 生成的 HTML/JS 应用程序,直接在聊天界面交互。
- **🔑 统一智能体验 (官方 + BYOK)**: 自由切换官方模型o1, GPT-4o, Claude 3.5 Sonnet, Gemini 2.0 Flash与自定义服务商OpenAI, Anthropic),支持 **BYOK (自带 Key)** 模式
- **🛡️ 物理级工作区隔离**: 每个会话在独立的沙箱目录中运行。确保绝对的数据隐私,防止不同聊天间的文件污染,同时给予 Agent 完整的文件系统操作权限
- **🔌 通用工具协议**:
- **原生 MCP**: 高性能直连 Model Context Protocol 服务器
- **OpenAPI 桥接**: 将任何外部 REST API 一键转换为 Agent 可调用的工具
- **OpenWebUI 原生桥接**: 零配置接入现有的 OpenWebUI 工具及内置功能(网页搜索、记忆等)
- **🧩 OpenWebUI Skills 桥接**: 将简单的 OpenWebUI Markdown 指令转化为包含脚本、模板和数据的强大 SDK 技能文件夹
- **♾️ 无限会话管理**: 先进的上下文窗口管理,支持自动“压缩”(摘要提取 + TODO 列表持久化)。支持长达数周的项目跟踪而不会丢失核心上下文
- **📊 交互式产物与发布**:
- **实时 HTML/JS**: 瞬间渲染并交互 Agent 生成的应用程序、可视化看板或报告。
- **持久化发布**: Agent 可将生成的产物Excel, CSV, 文档)发布至 OpenWebUI 文件存储,并在聊天中提供永久下载链接。
- **🌊 极致交互体验**: 完整支持深度思考过程 (Thinking Process) 流式渲染、状态指示器以及长任务实时进度条。
- **🧠 深度数据库集成**: TOD·O 列表与会话元数据的实时持久化,确保任务执行状态在 UI 上清晰可见。
---
@@ -69,9 +62,14 @@
| 参数 | 默认值 | 说明 |
| :--- | :--- | :--- |
| `GH_TOKEN` | `""` | 全局 GitHub Token (需具备 'Copilot Requests' 权限)。 |
| `COPILOTSDK_CONFIG_DIR` | `""` | SDK 配置与会话状态持久化目录 (例如: `/app/backend/data/.copilot`)。 |
| `ENABLE_OPENWEBUI_TOOLS` | `True` | 启用 OpenWebUI 工具 (包括定义工具和内置工具)。 |
| `ENABLE_OPENAPI_SERVER` | `True` | 启用 OpenAPI 工具服务器连接。 |
| `ENABLE_MCP_SERVER` | `True` | 启用直接 MCP 客户端连接 (推荐)。 |
| `ENABLE_OPENWEBUI_SKILLS` | `True` | 开启与 OpenWebUI **工作区 > Skills** 的双向同步桥接。 |
| `OPENWEBUI_SKILLS_SHARED_DIR` | `/app/backend/data/cache/copilot-openwebui-skills` | OpenWebUI skills 转换后的共享缓存目录。 |
| `GITHUB_SKILLS_SOURCE_URL` | `""` | 可选 GitHub tree 地址,用于批量导入 skills例如 anthropic/skills。 |
| `DISABLED_SKILLS` | `""` | 逗号分隔的 skill 名称黑名单(如 `docs-writer,webapp-testing`)。 |
| `REASONING_EFFORT` | `medium` | 推理强度low, medium, high。 |
| `SHOW_THINKING` | `True` | 显示模型推理/思考过程。 |
| `INFINITE_SESSION` | `True` | 启用无限会话 (自动上下文压缩)。 |
@@ -91,14 +89,38 @@
| 参数 | 说明 |
| :--- | :--- |
| `GH_TOKEN` | 使用个人的 GitHub Token。 |
| `REASONING_EFFORT`| 个人偏好的推理强度。 |
| `REASONING_EFFORT` | 个人偏好的推理强度。 |
| `SHOW_THINKING` | 显示模型推理/思考过程。 |
| `MAX_MULTIPLIER` | 最大允许的模型计费倍率覆盖。 |
| `EXCLUDE_KEYWORDS` | 排除包含这些关键字的模型。 |
| `ENABLE_OPENWEBUI_SKILLS` | 启用将当前用户可读的全部已启用 OpenWebUI skills 转换并加载为 SDK `SKILL.md` 目录。 |
| `GITHUB_SKILLS_SOURCE_URL` | 为当前用户会话设置可选 GitHub tree 地址以批量导入 skills。 |
| `DISABLED_SKILLS` | 为当前用户会话禁用指定 skills逗号分隔。 |
| `BYOK_API_KEY` | 使用个人的 OpenAI/Anthropic API Key。 |
---
### 🌊 细粒度反馈与流畅体验 (Fluid UX)
彻底告别复杂任务执行过程中的“卡顿”感:
- **🔄 实时状态气泡**: 将 SDK 内部事件(如 `turn_start`, `compaction`, `subagent_started`)直接映射为 OpenWebUI 的状态栏信息。
- **🧭 分阶段状态描述增强**: 状态栏会明确显示处理阶段(处理中、技能触发、工具执行、工具完成/失败、发布中、任务完成)。
- **⏱️ 长任务心跳提示**: 长时间处理中会周期性显示“仍在处理中(已耗时 X 秒)”,避免用户误判为卡死。
- **📈 工具执行进度追踪**: 长耗时工具(如代码分析)会在状态栏实时显示进度百分比及当前子任务描述。
- **⚡ 即时响应反馈**: 从响应开始第一秒即显示“助手正在处理您的请求...”,减少等待空窗感。
---
### 🛡️ 智能版本兼容
插件会自动根据您的 OpenWebUI 版本调整功能集:
- **v0.8.0+**: 开启 Rich UI、实时状态气泡及集成 HTML 预览。
- **旧版本**: 自动回退至标准 Markdown 代码块模式,确保最大稳定性。
---
## 🎯 典型应用场景 (Use Cases)
- **📁 全自主仓库维护**: Agent 在隔离工作区内自动分析代码、运行测试并应用补丁。
@@ -142,10 +164,40 @@
---
### 📤 增强型发布工具与交互式组件
`publish_file_from_workspace` 现采用更清晰、可落地的交付规范:
- **Artifacts 模式(`artifacts`,默认)**:返回 `[Preview]` + `[Download]`,并可附带 `html_embed`,在 ```html 代码块中直接渲染。
- **Rich UI 模式(`richui`**:仅返回 `[Preview]` + `[Download]`,由发射器自动触发集成式预览(消息中不输出 iframe 代码块)。
- **📄 PDF 安全交付规则**:仅输出 Markdown 链接(可用时为 `[Preview]` + `[Download]`)。**禁止通过 iframe/html 方式嵌入 PDF。**
- **⚡ 稳定双通道发布**:在本地与对象存储后端下,保持交互预览与持久下载链接一致可用。
- **✅ 状态集成**:通过 OpenWebUI 状态栏实时反馈发布进度与完成状态。
- **📘 发布工具指南GitHub**[publish_file_from_workspace 工具指南(中文)](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/PUBLISH_FILE_FROM_WORKSPACE_CN.md)
---
### 🧩 OpenWebUI Skills 桥接与 `manage_skills` 工具
SDK 现在具备与 OpenWebUI **工作区 > Skills** 的双向同步能力:
- **🔄 自动同步**: 每次请求时,前端定义的技能会自动作为 `SKILL.md` 文件夹同步至 SDK 共享缓存Agent 可直接调用。
- **🛠️ `manage_skills` 工具**: 内置专业工具,赋予 Agent (或用户) 绝对的技能管理权。
- `list`: 列出所有已安装技能及描述。
- `install`: 从 GitHub URL (自动转换归档链接) 或直接从 `.zip`/`.tar.gz` 安装。
- `create`: 从当前会话内容创建新技能目录,支持写入 `SKILL.md` 及辅助资源文件 (脚本、模板)。
- `edit`: 更新现有技能文件夹。
- `delete`: 原子化删除本地目录及关联的数据库条目,防止僵尸技能复活。
- **📁 完整的文件夹支持**: 不同于数据库中单文件存储SDK 会加载技能的**整个目录**。这使得技能可以携带二进制脚本、数据文件或复杂模板。
- **🌐 持久化共享缓存**: 技能存储在 `OPENWEBUI_SKILLS_SHARED_DIR/shared/`,跨会话及容器重启持久存在。
- **📚 技能完整文档GitHub**: [manage_skills 工具指南(中文)](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/SKILLS_MANAGER_CN.md) | [Skills Best Practices中文](https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/SKILLS_BEST_PRACTICES_CN.md)
---
## 📋 常见问题与依赖 (Troubleshooting)
- **Agent 无法识别文件?**: 请确保已安装并启用了 Files Filter 插件,否则原始文件会被 RAG 干扰。
- **看不到 TODO 进度条?**: 进度条仅在 Agent 使用 `update_todo` 工具(通常是处理复杂任务)时出现。
- **看不到状态更新或 TODO 进度条?**: 状态气泡会覆盖处理/工具阶段;而 TODO 进度条仅在 Agent 使用 `update_todo` 工具(通常是复杂任务)时出现。
- **依赖安装**: 本管道会自动管理 `github-copilot-sdk` (Python 包) 并优先直接使用内置的二进制 CLI无需手动干预。
---

View File

@@ -0,0 +1,209 @@
# Skills Best Practices
A concise guide to writing, organizing, and maintaining Copilot SDK skills effectively.
---
## Understanding How Skills Work
Skills are **not command-line tools**. They are context-injected instruction sets:
1. The Copilot SDK daemon reads every `SKILL.md` file from your `skill_directories`
2. It extracts the YAML `description` field from each skill
3. When the user sends a message, the SDK compares intent against all descriptions
4. If a match is found, the SDK fires `skill.invoked` and **injects the full SKILL.md body** into the conversation as instructions
5. The agent reads those instructions and executes them using `bash`, `create_file`, `view_file`, etc.
**Key implication**: never run a skill's name as a bash command (e.g., `finance-reporting`). The skill IS the instructions, not an executable.
---
## Writing a Good `description` Field
The `description` in `SKILL.md` frontmatter is the **primary trigger mechanism**. The SDK uses it like a semantic router.
### Do ✅
- Start with a verb: "Manage…", "Generate…", "Analyze…"
- Include explicit "Use when:" scenarios — this is the most reliable trigger signal
- Cover all the intent variations a user might express
```yaml
description: Generate a PowerPoint presentation from an outline or topic.
Use when: creating slides, building a deck, making a presentation, exporting to PPTX.
```
### Don't ❌
- Vague descriptions: "A useful skill for various things"
- Overlapping descriptions with other skills (causes misfires)
- Omitting "Use when:" examples (reduces trigger reliability significantly)
### Rule of Thumb
If two people would phrase the same request differently (e.g., "make slides" vs. "create a deck"), both phrasings should appear somewhere in the description.
---
## Structure: What Goes Where
```
skill-name/
├── SKILL.md ← Required. Frontmatter + core instructions
├── .owui_id ← Auto-generated. DO NOT edit or delete
├── references/ ← Optional. Supplementary docs, loaded on demand
│ └── advanced.md
├── scripts/ ← Optional. Helper shell/Python scripts
└── assets/ ← Optional. Templates, sample files, static data
```
### When to Use `references/`
Put content in `references/` when it is:
- Only needed for edge cases or advanced usage
- Too long to read every time (> ~100 lines)
- Reference material (API specs, format docs, examples)
Use progressive disclosure: the agent reads `SKILL.md` first, then loads a specific reference file only when the task requires it.
```markdown
## Advanced Export Options
See [references/export-options.md](references/export-options.md) for the full list.
```
### When to Inline in `SKILL.md`
Keep content in `SKILL.md` when it is:
- Needed for every run of the skill
- Short enough not to slow down context injection (< ~150 lines total)
- Core to the skill's main workflow
---
## Naming Conventions
| Item | Convention | Example |
|---|---|---|
| Skill directory name | `kebab-case` | `export-to-pptx` |
| `name` field in frontmatter | `kebab-case`, matches dir name | `export-to-pptx` |
| Script filenames | `snake_case.py` or `snake_case.sh` | `build_slide.py` |
| Reference filenames | `kebab-case.md` | `advanced-options.md` |
Avoid spaces and uppercase in skill directory names — the SDK uses the directory name as the skill identifier.
---
## Writing Effective SKILL.md Instructions
### Open With a Role Statement
Tell the agent who it is in this skill context:
```markdown
# Export to PowerPoint
You are a presentation builder. Your job is to convert the user's content into a well-structured PPTX file using the scripts in this skill directory.
```
### Use Imperative Steps
Write instructions as numbered steps, not prose:
```markdown
1. Ask the user for the outline if not provided.
2. Run `python3 {scripts_dir}/build_slide.py --title "..." --output "{cwd}/output.pptx"`
3. Confirm success by checking the file exists.
4. Provide the user with the download path.
```
### Handle Errors Explicitly
Tell the agent what to do when things go wrong:
```markdown
If the script exits with a non-zero code, show the user the stderr output and ask how to proceed.
```
### End With a Closing Instruction
```markdown
After completing the task, summarize what was created and remind the user where to find the file.
```
---
## Skill Scope
Each skill should do **one thing well**. Signs a skill is too broad:
- The description has more than 45 "Use when:" entries covering unrelated domains
- The SKILL.md is > 300 lines
- You've added more than 3 reference files
When a skill grows too large, split it: one parent skill for routing + separate child skills per major function.
---
## Managing the `shared/` Directory
The `shared/` directory is **bidirectionally synced** with the OpenWebUI database:
- Skills created via the OpenWebUI UI are automatically imported into `shared/`
- Skills created by the agent in `shared/` are exported back to OpenWebUI at session start
### Safe operations
| Operation | Method |
|---|---|
| Install from URL | `python3 {scripts_dir}/install_skill.py --url <url> --dest {shared_dir}` |
| Create new skill | `mkdir -p {shared_dir}/<name>/ && create SKILL.md` |
| Edit skill | Read → modify → write `SKILL.md` |
| Delete skill | `rm -rf {shared_dir}/<name>/` (does NOT delete from OpenWebUI UI — do that separately) |
| List skills | `python3 {scripts_dir}/list_skills.py --path {shared_dir}` |
### The `.owui_id` file
Every skill synced with OpenWebUI has a `.owui_id` file containing the database UUID. **Never edit or delete this file** — it is the link between the filesystem and OpenWebUI DB. If deleted, the skill will be treated as new on next sync and may create a duplicate.
---
## Session Lifecycle Awareness
Skills are loaded **once at session start**. Changes made during a session take effect in the **next session**.
| When | What happens |
|---|---|
| Session starts | SDK daemon reads all `SKILL.md` files; `_sync_openwebui_skills` runs bidirectional DB↔file sync |
| During a session | New/edited/deleted skill files exist on disk but are NOT yet loaded by the daemon |
| After user starts new session | New skills become available; edited descriptions take effect |
**Always tell the user** after any create/edit/delete: "This change will take effect when you start a new session."
---
## Anti-Patterns to Avoid
| Anti-pattern | Why it's bad | Fix |
|---|---|---|
| Running `<skill-name>` as a bash command | Skills are not executables | Read the SKILL.md instructions and act with standard tools |
| Editing `.owui_id` | Breaks DB sync | Never touch it |
| Storing per-session state in `SKILL.md` | SKILL.md is static instructions, not a state file | Use separate workspace files for session state |
| Ultra-broad skill descriptions | Causes false positives on every message | Narrow to specific intent with "Use when:" |
| Putting all logic in one 500-line SKILL.md | Slow context injection, hard to maintain | Split into SKILL.md + `references/*.md` |
| Creating skills in `/tmp` | Not persisted, not found by SDK | Always create in `{shared_dir}/` |
---
## Quick Checklist for a New Skill
- [ ] Directory name is `kebab-case` and matches the `name` field
- [ ] `description` starts with a verb and has "Use when:" examples
- [ ] SKILL.md opens with a role statement for the agent
- [ ] Instructions use imperative numbered steps
- [ ] Long reference content moved to `references/`
- [ ] Scripts placed in `scripts/`
- [ ] Confirmed: skill does NOT overlap in description with other loaded skills
- [ ] User informed: "new skill takes effect next session"

View File

@@ -0,0 +1,209 @@
# Skills 使用最佳实践
编写、组织和维护 Copilot SDK Skills 的简明指南。
---
## 理解 Skills 的工作机制
Skills **不是命令行工具**,而是**上下文注入的指令集**
1. Copilot SDK 守护进程读取 `skill_directories` 中每个 `SKILL.md` 文件
2. 提取每个 skill 的 YAML `description` 字段
3. 用户发消息时SDK 将用户意图与所有 description 进行语义匹配
4. 匹配成功后SDK 触发 `skill.invoked` 事件,将完整的 **SKILL.md 正文注入对话上下文**
5. Agent 读取这些指令,使用 `bash``create_file``view_file` 等工具来执行
**关键理解**:永远不要把 skill 的名字当作 bash 命令来运行(例如 `finance-reporting`。Skill 本身就是指令,而不是可执行文件。
---
## 写好 `description` 字段
`SKILL.md` frontmatter 中的 `description`**主要触发机制**SDK 用它做语义路由。
### 应该这样做 ✅
- 以动词开头:"管理…"、"生成…"、"分析…"
- 明确写出 "Use when:" 场景——这是最可靠的触发信号
- 覆盖用户可能表达同一需求的多种说法
```yaml
description: 根据大纲或主题生成 PowerPoint 演示文稿。
Use when: 创建幻灯片、制作演讲稿、导出 PPTX 文件、做 PPT。
```
### 不要这样做 ❌
- 模糊描述:"一个有用的多功能工具"
- 与其他 skill 描述重叠(会造成误触发)
- 省略 "Use when:" 示例(大幅降低触发准确率)
### 实用经验
如果两个人会用不同方式表达同一需求(如"做个幻灯片"vs"制作一个演讲 deck"),两种说法都应该出现在 description 中。
---
## 目录结构:什么放在哪里
```
skill-name/
├── SKILL.md ← 必须。Frontmatter + 核心指令
├── .owui_id ← 自动生成,禁止编辑或删除
├── references/ ← 可选。补充文档,按需加载
│ └── advanced.md
├── scripts/ ← 可选。辅助脚本Shell/Python
└── assets/ ← 可选。模板、样例文件、静态数据
```
### 何时用 `references/`
当内容属于以下情况时放入 `references/`
- 仅边缘场景或高级用法才需要
- 内容太长,每次都注入会浪费上下文(> 约 100 行)
- 纯参考资料API 规格、格式文档、示例)
使用"渐进式披露"Agent 先读 `SKILL.md`,仅在任务需要时才加载特定 reference 文件:
```markdown
## 高级导出选项
详见 [references/export-options.md](references/export-options.md)。
```
### 何时内联在 `SKILL.md`
当内容属于以下情况时留在 `SKILL.md`
- 每次运行 skill 都需要
- 足够短,不会拖慢上下文注入(总计 < 约 150 行)
- 是 skill 主流程的核心内容
---
## 命名约定
| 内容 | 规范 | 示例 |
|---|---|---|
| Skill 目录名 | `kebab-case` | `export-to-pptx` |
| Frontmatter `name` 字段 | `kebab-case`,与目录名一致 | `export-to-pptx` |
| 脚本文件名 | `snake_case.py``.sh` | `build_slide.py` |
| Reference 文件名 | `kebab-case.md` | `advanced-options.md` |
Skill 目录名避免空格和大写字母——SDK 使用目录名作为 skill 标识符。
---
## 编写高效的 SKILL.md 指令
### 以角色声明开头
告诉 Agent 在这个 skill 上下文中扮演什么角色:
```markdown
# 导出为 PowerPoint
你是一个演示文稿构建器。你的任务是使用本 skill 目录中的脚本,将用户的内容转换为结构清晰的 PPTX 文件。
```
### 使用祈使句步骤
用编号步骤写指令,而不是大段散文:
```markdown
1. 如果用户未提供大纲,先询问。
2. 运行 `python3 {scripts_dir}/build_slide.py --title "..." --output "{cwd}/output.pptx"`
3. 检查文件是否存在,确认成功。
4. 向用户提供文件的下载路径。
```
### 明确处理错误
告诉 Agent 出错时怎么做:
```markdown
如果脚本以非零状态码退出,将 stderr 输出展示给用户并询问如何处理。
```
### 以收尾指令结束
```markdown
任务完成后,总结创建的内容,并提醒用户文件的存放位置。
```
---
## Skill 的适用范围
每个 skill 应该**只做一件事**。以下迹象说明 skill 太宽泛了:
- description 包含 45 个以上涵盖不同领域的 "Use when:" 条目
- SKILL.md 超过 300 行
- 已添加超过 3 个 reference 文件
当 skill 变得过大时,进行拆分:一个父 skill 负责路由,各子 skill 负责具体功能。
---
## 管理 `shared/` 目录
`shared/` 目录与 OpenWebUI 数据库**双向同步**
- 通过 OpenWebUI UI 创建的 skill 会自动导入 `shared/`
- Agent 在 `shared/` 中创建的 skill 在下次会话启动时导出到 OpenWebUI
### 安全操作方式
| 操作 | 方法 |
|---|---|
| 从 URL 安装 | `python3 {scripts_dir}/install_skill.py --url <url> --dest {shared_dir}` |
| 新建 skill | `mkdir -p {shared_dir}/<name>/ && 创建 SKILL.md` |
| 编辑 skill | 读取 → 修改 → 写回 `SKILL.md` |
| 删除 skill | `rm -rf {shared_dir}/<name>/`(不会删除 OpenWebUI UI 中的记录,需单独删除) |
| 列出 skills | `python3 {scripts_dir}/list_skills.py --path {shared_dir}` |
### `.owui_id` 文件
每个与 OpenWebUI 同步的 skill 都有一个 `.owui_id` 文件,里面存储数据库 UUID。**绝对不要编辑或删除此文件**——它是文件系统与 OpenWebUI 数据库之间的关联纽带。一旦删除,下次同步时该 skill 会被视为新建项,可能产生重复。
---
## 会话生命周期意识
Skills 在**会话开始时加载一次**。在会话期间做的修改,**下次会话才会生效**。
| 时间点 | 发生的事 |
|---|---|
| 会话启动 | SDK 守护进程读取所有 `SKILL.md``_sync_openwebui_skills` 执行双向 DB↔文件同步 |
| 会话期间 | 新建/编辑/删除的 skill 文件已在磁盘上,但守护进程尚未加载 |
| 用户开启新会话 | 新 skill 生效;修改后的 description 开始触发 |
**每次创建/编辑/删除后,必须告知用户**"此更改将在您开启新会话后生效。"
---
## 需要避免的反模式
| 反模式 | 问题所在 | 解决方式 |
|---|---|---|
| 把 `<skill名>` 当 bash 命令运行 | Skill 不是可执行文件 | 阅读 SKILL.md 指令,用标准工具执行 |
| 编辑 `.owui_id` | 破坏数据库同步 | 永远不要碰这个文件 |
| 在 SKILL.md 中存储会话状态 | SKILL.md 是静态指令,不是状态文件 | 使用工作区中的独立文件保存会话状态 |
| description 过于宽泛 | 对每条消息都误触发 | 用 "Use when:" 缩窄到具体意图 |
| 把所有逻辑写进一个 500 行的 SKILL.md | 上下文注入慢,难以维护 | 拆分为 SKILL.md + `references/*.md` |
| 在 `/tmp` 创建 skill | 不持久SDK 找不到 | 始终在 `{shared_dir}/` 中创建 |
---
## 新建 Skill 快速检查清单
- [ ] 目录名为 `kebab-case`,与 `name` 字段一致
- [ ] `description` 以动词开头,包含 "Use when:" 示例
- [ ] SKILL.md 以角色声明开头
- [ ] 指令使用祈使句编号步骤
- [ ] 过长的参考内容已移至 `references/`
- [ ] 脚本已放入 `scripts/`
- [ ] 确认description 与其他已加载 skill 无重叠
- [ ] 已告知用户:"新 skill 在下次会话后生效"

View File

@@ -0,0 +1,128 @@
# manage_skills Tool Guide
This document describes the `manage_skills` **tool** in GitHub Copilot SDK Pipe.
> Important: `manage_skills` is a tool, not a skill.
---
## Core Model
The plugin uses **one** install/sync location for skills:
- `OPENWEBUI_SKILLS_SHARED_DIR/shared/`
There is no separate install target for "manager skill" or per-workspace skill buckets.
---
## Skill Directory Layout
All skills live under the same directory:
```text
{OPENWEBUI_SKILLS_SHARED_DIR}/shared/
├── finance-reporting/
│ ├── SKILL.md
│ ├── .owui_id
│ ├── scripts/
│ └── templates/
├── docs-writer/
│ ├── SKILL.md
│ └── .owui_id
└── ...
```
- `SKILL.md` is required.
- `.owui_id` links local folder to OpenWebUI DB record.
- Extra files (`scripts/`, `templates/`, `references/`) are optional resources.
---
## What `manage_skills` Does
`manage_skills` provides deterministic skill lifecycle operations:
- `list`
- `install`
- `create`
- `edit`
- `show`
- `delete`
Use this tool for all skill CRUD operations instead of ad-hoc shell workflows.
---
## Sync Mechanism (Local Files ↔ OpenWebUI DB)
The SDK performs **real-time bidirectional sync** between the local filesystem and the OpenWebUI database to ensure consistency.
### How it works
1. **Identity Link**: Each local skill folder contains a hidden `.owui_id` file. This is the "glue" that links the folder to a specific record in the OpenWebUI database.
2. **Conflict Resolution**:
- **Content Hash**: The SDK first compares the MD5 hash of the local `SKILL.md` content against the DB record. If they match, no sync occurs.
- **Timestamp Check**: If content differs, it compares the file's `mtime` with the database's `updated_at`. The newer version wins.
3. **Operation Sync**:
- **Manual Edit (Filesystem)**: If you edit `SKILL.md` via VS Code or terminal, the next SDK request will push those changes to the OpenWebUI UI.
- **UI Edit (OpenWebUI)**: If you update instructions in the OpenWebUI workspace, the SDK will pull those changes and overwrite the local `SKILL.md`.
- **Tool Actions**: Actions like `manage_skills(action="create")` or `action="delete"` trigger an immediate atomic sync to the database.
> **Warning**: Do not manually delete the `.owui_id` file unless you want to "unlink" the skill and force the SDK to re-register it as a new entry.
---
## Typical Flows (Example Queries)
### 1. Install Skill from GitHub URL
**User Query:** "Help me install the data-visualizer skill from `https://github.com/user/skills/blob/main/data-visualizer/SKILL.md`"
**Tool Call:** `manage_skills(action="install", url="https://github.com/user/skills/blob/main/data-visualizer/SKILL.md")`
**Result:**
- Files downloaded to `{OPENWEBUI_SKILLS_SHARED_DIR}/shared/data-visualizer/`
- Skill metadata automatically synced to OpenWebUI Database.
### 2. Install Multiple Skills from Different URLs at Once
**User Query:** "Install these three skills: URL1, URL2, URL3"
**Tool Call:** `manage_skills(action="install", url=["URL1", "URL2", "URL3"])`
**Result:**
- Each URL is downloaded, extracted, and installed sequentially into `shared/`.
- A single DB sync runs after all installs complete.
- If one URL fails, the others still proceed. Failed URLs are listed in `errors`.
### 3. Install All Skills from One Repository
**User Query:** "Install everything under `https://github.com/myorg/skill-pack/tree/main/`"
**Tool Call:** `manage_skills(action="install", url="https://github.com/myorg/skill-pack/tree/main/")`
**Result:**
- All subdirectories containing a `SKILL.md` are discovered and installed in one shot.
### 4. Create Skill from Current Conversation
**User Query:** "Remember the Python cleanup logic we just discussed as a new skill called 'py-clean'"
**Tool Call:** `manage_skills(action="create", name="py-clean", content="...")`
**Result:**
- New directory `{OPENWEBUI_SKILLS_SHARED_DIR}/shared/py-clean/` created.
- `SKILL.md` written and synced to Database.
---
## Recommended Settings
- `ENABLE_OPENWEBUI_SKILLS=True`
- `OPENWEBUI_SKILLS_SHARED_DIR=/app/backend/data/cache/copilot-openwebui-skills`
- Optional blacklist: `DISABLED_SKILLS=skill-a,skill-b`
---
## Notes
- Do not run skill names as shell commands.
- Use `manage_skills` for lifecycle control.
- Keep all installed skills in one directory: `.../shared/`.

View File

@@ -0,0 +1,128 @@
# manage_skills 工具指南
本文档说明 GitHub Copilot SDK Pipe 中的 `manage_skills` **工具**
> 重点:`manage_skills` 是工具tool不是 skill。
---
## 核心模型
插件只使用**一个** skill 安装/同步目录:
- `OPENWEBUI_SKILLS_SHARED_DIR/shared/`
不存在额外的“manager skill 目录”或按工作区分裂的安装目录。
---
## Skill 目录结构
所有 skills 统一放在同一个目录下:
```text
{OPENWEBUI_SKILLS_SHARED_DIR}/shared/
├── finance-reporting/
│ ├── SKILL.md
│ ├── .owui_id
│ ├── scripts/
│ └── templates/
├── docs-writer/
│ ├── SKILL.md
│ └── .owui_id
└── ...
```
- `SKILL.md` 为必需文件。
- `.owui_id` 用于关联 OpenWebUI 数据库记录。
- `scripts/``templates/``references/` 等为可选资源文件。
---
## `manage_skills` 可以做什么
`manage_skills` 提供确定性的 skill 生命周期操作:
- `list`
- `install`
- `create`
- `edit`
- `show`
- `delete`
建议将 skill 的增删改查统一通过该工具完成,避免脆弱的临时 shell 流程。
---
## 同步机制 (本地文件 ↔ OpenWebUI 数据库)
SDK 在本地文件系统与 OpenWebUI 数据库之间执行**实时双向同步**,以确保一致性。
### 工作原理
1. **身份绑定**:每个本地 skill 文件夹内包含一个隐藏的 `.owui_id` 文件。它是将文件夹链接到 OpenWebUI 数据库中特定记录的“粘合剂”。
2. **冲突处理**
- **内容哈希**SDK 首先比较本地 `SKILL.md` 与数据库中指令的内容哈希 (MD5)。若一致,则不执行同步。
- **时间戳校验**:若内容不同,则比较文件的 `mtime` 与数据库的 `updated_at`。时间较新的一方将覆盖另一方。
3. **操作同步场景**
- **手动编辑 (文件系统)**:若你通过 VS Code 或终端修改了 `SKILL.md`,下次 SDK 请求时会自动将改动推送到 OpenWebUI 前端。
- **界面编辑 (OpenWebUI)**:若你在 OpenWebUI 工作区中修改了指令内容SDK 会拉取变更并覆写本地的 `SKILL.md`
- **工具操作**:调用 `manage_skills(action="create")``action="delete"` 会立即触发与数据库的原子同步。
> **警告**:除非你想“取消关联”并强制 SDK 将该技能注册为新条目,否则请勿手动删除 `.owui_id` 文件。
---
## 典型工作流 (典型问题示例)
### 1. 从 GitHub URL 安装 Skill
**用户提问:** "帮我安装这个数据分析 skill`https://github.com/user/skills/blob/main/data-visualizer/SKILL.md`"
**工具调用:** `manage_skills(action="install", url="https://github.com/user/skills/blob/main/data-visualizer/SKILL.md")`
**结果:**
- 文件下载至 `{OPENWEBUI_SKILLS_SHARED_DIR}/shared/data-visualizer/`
- Skill 元数据自动同步至 OpenWebUI 数据库。
### 2. 一次安装多个来自不同 URL 的 Skills
**用户提问:** "帮我安装这三个 skillURL1、URL2、URL3"
**工具调用:** `manage_skills(action="install", url=["URL1", "URL2", "URL3"])`
**结果:**
- Agent 将 `url` 传入为列表SDK 依次下载、解压并安装每个 URL 对应的 skill 到 `shared/` 目录。
- 所有安装完成后,执行一次统一的数据库同步,避免重复触发。
- 若某个 URL 失败,其余 URL 的安装仍会继续,失败信息汇总在 `errors` 字段中返回。
### 3. 从单个仓库一次安装所有 Skills
**用户提问:** "安装 `https://github.com/myorg/skill-pack/tree/main/` 下的所有 skill"
**工具调用:** `manage_skills(action="install", url="https://github.com/myorg/skill-pack/tree/main/")`
**结果:**
- SDK 自动扫描目录下所有包含 `SKILL.md` 的子文件夹,一次性批量安装。
### 4. 从当前对话创建新 Skill
**用户提问:** "把我们刚才讨论的 Python 代码清理逻辑保存为一个名为 'py-clean' 的新 skill"
**工具调用:** `manage_skills(action="create", name="py-clean", content="...")`
**结果:**
-`{OPENWEBUI_SKILLS_SHARED_DIR}/shared/py-clean/` 创建新目录。
- 写入 `SKILL.md` 并同步至数据库。
---
## 推荐配置
- `ENABLE_OPENWEBUI_SKILLS=True`
- `OPENWEBUI_SKILLS_SHARED_DIR=/app/backend/data/cache/copilot-openwebui-skills`
- 可选黑名单:`DISABLED_SKILLS=skill-a,skill-b`
---
## 注意事项
- 不要把 skill 名称当作 shell 命令执行。
- skill 生命周期管理请优先使用 `manage_skills` 工具。
- 所有已安装 skills 统一维护在一个目录:`.../shared/`

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,101 @@
# 🚀 GitHub Copilot SDK Pipe v0.9.0: Copilot SDK Skills Core Capabilities & Extended Delivery
**GitHub Copilot SDK Pipe v0.9.0** centers on making **Copilot SDK Skills** a first-class capability (native directory support + bidirectional sync + deterministic `manage_skills` lifecycle), then extends delivery with improved publishing behavior.
---
## ⭐ Release Highlights
- **🧩 Copilot SDK Skills Support (Core)**: Native support for SDK skill directories (`SKILL.md` + optional resources), so skills are loaded as first-class runtime context.
- **🔄 OpenWebUI Skills Bridge (Extension)**: Bidirectional sync between OpenWebUI and local SDK skill folders.
- **🛠️ `manage_skills` Tool (Extension)**: In-session deterministic skill lifecycle tool for `list/install/create/edit/show/delete`.
- **📤 Publishing Update**: HTML supports `artifacts` / `richui`; PDF is delivered via Markdown links.
- **📁 Folder-based Skills**: A skill can include `SKILL.md` plus templates/scripts/resources.
- **🧱 Environment Refactor**: New persistent config/workspace/toolchain layout under `/app/backend/data` with stricter isolation and better reproducibility.
---
## 📦 Quick Installation
- **GitHub Copilot SDK (Pipe)**: [Install v0.9.0](https://openwebui.com/posts/ce96f7b4-12fc-4ac3-9a01-875713e69359)
- **GitHub Copilot SDK (Filter)**: [Install v0.1.3](https://openwebui.com/posts/403a62ee-a596-45e7-be65-fab9cc249dd6)
---
## 🚀 What's New in v0.9.0
### 1. OpenWebUI Skills ↔ SDK Sync
All skills are unified under `{OPENWEBUI_SKILLS_SHARED_DIR}/shared/` and synced automatically between DB and files.
### 2. `manage_skills` Tool
The built-in tool (not a skill) supports:
- `list`
- `install` (single URL / multiple URLs)
- `create`
- `edit`
- `show`
- `delete`
### 3. Publishing Behavior
- HTML: `artifacts` (code-block embed output) or `richui` (emitter auto-render) mode.
- PDF: Markdown links only (no iframe embed).
### 4. Environment Refactor (Detailed)
This release includes a substantial runtime environment redesign:
- **Persistent SDK config directory**
- Introduced `COPILOTSDK_CONFIG_DIR`.
- Resolution order: Valve override -> `/app/backend/data/.copilot` -> `~/.copilot` fallback.
- Ensures session/config state survives container restarts in standard OpenWebUI deployments.
- **User + Chat isolated workspace model**
- Workspace root is now `/app/backend/data/copilot_workspace` (container mode).
- Effective path is isolated per user and chat: `/app/backend/data/copilot_workspace/{user_id}/{chat_id}`.
- `user_id`/`chat_id` are sanitized to prevent traversal.
- **Deterministic CLI tool runtime under data volume**
- Global tool root: `/app/backend/data/.copilot_tools`.
- NPM prefix is forced to `/app/backend/data/.copilot_tools/npm` via `NPM_CONFIG_PREFIX`.
- Python tool execution is isolated in `/app/backend/data/.copilot_tools/venv` via `VIRTUAL_ENV`.
- `PYTHONUSERBASE` and `PIP_USER` are cleared to avoid leaking user-site installs.
- PATH is rewritten to prioritize npm/venv bins for consistent tool resolution.
- **CLI bootstrap hardening**
- Copilot CLI discovery chain: `COPILOT_CLI_PATH` -> system `PATH` -> SDK bundled binary.
- `COPILOT_AUTO_UPDATE=false` to prevent uncontrolled runtime drift.
- Successful discovery auto-injects CLI bin dir into PATH.
- **System prompt path context hardening**
- Session context now injects explicit paths: isolated workspace, skills directory, config directory, and tools path.
- This reduces ambiguity and prevents accidental writes outside the approved workspace.
- **Regular-user security boundary refinement**
- Non-admin users still cannot access env vars/db/global internals.
- They can read **their own current chat session metadata** under `COPILOTSDK_CONFIG_DIR` for troubleshooting.
- Cross-user session access remains forbidden.
### 5. New Valves
- `COPILOTSDK_CONFIG_DIR`
- `ENABLE_OPENWEBUI_SKILLS`
- `OPENWEBUI_SKILLS_SHARED_DIR`
- `DISABLED_SKILLS`
---
## 🔄 Migration
- No breaking changes from v0.8.0.
- `ENABLE_WORKSPACE_TOOLS` replaced by `ENABLE_OPENWEBUI_SKILLS`.
---
## 📚 Detailed Docs
- README: <https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/README.md>
- manage_skills Tool Guide: <https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/SKILLS_MANAGER.md>

View File

@@ -0,0 +1,101 @@
# 🚀 GitHub Copilot SDK Pipe v0.9.0Copilot SDK Skills 核心能力与扩展交付
**GitHub Copilot SDK Pipe v0.9.0** 的核心是将 **Copilot SDK Skills** 提升为一等能力(原生目录支持 + 双向同步 + `manage_skills` 确定性管理),并在此基础上增强发布交付体验。
---
## ⭐ 版本亮点
- **🧩 Copilot SDK Skills 原生支持(核心)**:原生支持 SDK 技能目录(`SKILL.md` + 可选资源文件),技能可作为一等运行时上下文加载。
- **🔄 OpenWebUI Skills 桥接(扩展)**OpenWebUI 与本地 SDK 技能目录双向同步。
- **🛠️ `manage_skills` 工具(扩展)**:会话内以确定性方式完成 `list/install/create/edit/show/delete`
- **📤 发布增强**HTML 支持 `artifacts` / `richui`PDF 统一 Markdown 链接交付。
- **📁 文件夹级技能**:一个技能可包含 `SKILL.md` 及模板/脚本/资源文件。
- **🧱 环境改造**:在 `/app/backend/data` 下重构配置、工作区与工具运行时布局,隔离性和可复现性显著提升。
---
## 📦 快速安装
- **GitHub Copilot SDK (Pipe 插件)**: [安装 v0.9.0](https://openwebui.com/posts/ce96f7b4-12fc-4ac3-9a01-875713e69359)
- **GitHub Copilot SDK (Filter 伴侣插件)**: [安装 v0.1.3](https://openwebui.com/posts/403a62ee-a596-45e7-be65-fab9cc249dd6)
---
## 🚀 v0.9.0 更新内容
### 1. OpenWebUI Skills ↔ SDK 双向同步
所有技能统一存放于 `{OPENWEBUI_SKILLS_SHARED_DIR}/shared/`,在数据库与文件之间自动同步。
### 2. `manage_skills` 工具
内置原生工具(不是 skill支持
- `list`
- `install`(单 URL / 多 URL
- `create`
- `edit`
- `show`
- `delete`
### 3. 发布行为
- HTML`artifacts`(输出代码块嵌入)或 `richui`(发射器自动渲染)两种模式。
- PDF仅以 Markdown 链接交付(不嵌入 iframe
### 4. 环境改造(详细分析)
这一版本不只是功能更新,还做了较大规模的运行环境重构:
- **持久化 SDK 配置目录**
- 新增 `COPILOTSDK_CONFIG_DIR`
- 解析优先级Valve 显式配置 -> `/app/backend/data/.copilot` -> `~/.copilot` 回退。
- 标准 OpenWebUI 容器场景下,会话/配置状态可跨容器重启保留。
- **按用户 + 会话隔离的工作区模型**
- 工作区根目录统一到 `/app/backend/data/copilot_workspace`(容器模式)。
- 实际目录按用户与 chat 隔离:`/app/backend/data/copilot_workspace/{user_id}/{chat_id}`
- `user_id``chat_id` 会进行清洗,避免路径穿越风险。
- **工具运行时固定到 data 卷(可持久)**
- 工具根目录:`/app/backend/data/.copilot_tools`
- NPM 安装前缀固定为 `/app/backend/data/.copilot_tools/npm`(通过 `NPM_CONFIG_PREFIX`)。
- Python 工具执行固定在 `/app/backend/data/.copilot_tools/venv`(通过 `VIRTUAL_ENV`)。
- 同时清理 `PYTHONUSERBASE``PIP_USER`,防止 user-site 安装污染运行时。
- PATH 被重写优先指向 npm/venv bin提升工具解析一致性。
- **CLI 启动链路加固**
- Copilot CLI 发现顺序:`COPILOT_CLI_PATH` -> 系统 `PATH` -> SDK 内置 bundled binary。
- 强制 `COPILOT_AUTO_UPDATE=false`,避免运行期自动更新导致行为漂移。
- 发现成功后自动将 CLI 目录注入 PATH。
- **系统提示词中的路径上下文强化**
- 会显式注入隔离工作区、技能目录、配置目录、工具目录。
- 让 Agent 的“可写路径”和“可读路径”更确定,减少越界写入风险。
- **普通用户权限边界细化**
- 普通用户仍禁止访问环境变量、数据库和无关系统内部信息。
- 允许读取**当前用户当前会话**在 `COPILOTSDK_CONFIG_DIR` 下的会话元数据用于排障。
- 仍严格禁止跨用户会话读取。
### 5. 新增 Valves
- `COPILOTSDK_CONFIG_DIR`
- `ENABLE_OPENWEBUI_SKILLS`
- `OPENWEBUI_SKILLS_SHARED_DIR`
- `DISABLED_SKILLS`
---
## 🔄 升级说明
- 从 v0.8.0 升级无破坏性变更。
- `ENABLE_WORKSPACE_TOOLS` 已由 `ENABLE_OPENWEBUI_SKILLS` 取代。
---
## 📚 详细文档
- README_CN: <https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/README_CN.md>
- manage_skills 工具指南: <https://github.com/Fu-Jie/openwebui-extensions/blob/main/plugins/pipes/github-copilot-sdk/SKILLS_MANAGER_CN.md>

View File

@@ -0,0 +1,260 @@
"""
Workspace Skills Example - Custom Tools for GitHub Copilot SDK
This file demonstrates how to create custom tools using the @define_tool decorator
for use in your workspace's .copilot-skills/ directory.
USAGE:
======
1. Create a .copilot-skills/ directory at the root of your workspace:
```
your-workspace/
└── .copilot-skills/
├── custom_search.py (copy and modify this example)
├── data_processor.py (your custom tools)
└── README.md (optional: document your skills)
```
2. Copy this file (or your modified version) to .copilot-skills/
3. Define your tools using @define_tool decorator:
```python
from pydantic import BaseModel, Field
from copilot import define_tool
class SearchParams(BaseModel):
query: str = Field(..., description="Search query")
limit: int = Field(default=10, description="Max results")
@define_tool(description="Search your custom database")
async def search_custom_db(query: str, limit: int = 10) -> dict:
# Your implementation here
return {"results": [...]}
# Register as tool (tool name will be snake_case of function name)
custom_search = define_tool(
name="search_custom_db",
description="Search your custom database for documents or data",
params_type=SearchParams,
)(search_custom_db)
```
4. The SDK will automatically discover and register your tools from .copilot-skills/
5. Use them in your conversation: "Use the search_custom_db tool to find..."
REQUIREMENTS:
=============
- Python 3.9+
- github-copilot-sdk (v0.1.25+)
- Any external dependencies your custom tools need
"""
from pydantic import BaseModel, Field
from copilot import define_tool
# ============================================================================
# Example 1: Simple Math Helper Tool
# ============================================================================
@define_tool(description="Perform common mathematical calculations")
async def calculate_math(operation: str, value1: float, value2: float = 0) -> dict:
"""
Performs basic mathematical operations.
Args:
operation: One of 'add', 'subtract', 'multiply', 'divide', 'power', 'sqrt'
value1: First number
value2: Second number (for binary operations)
Returns:
Dictionary with 'result' and 'operation' keys
"""
import math
op_map = {
"add": lambda a, b: a + b,
"subtract": lambda a, b: a - b,
"multiply": lambda a, b: a * b,
"divide": lambda a, b: a / b if b != 0 else None,
"power": lambda a, b: a ** b,
"sqrt": lambda a, _: math.sqrt(a) if a >= 0 else None,
}
result = None
if operation in op_map:
try:
result = op_map[operation](value1, value2)
except Exception as e:
return {"success": False, "error": str(e)}
else:
return {"success": False, "error": f"Unknown operation: {operation}"}
return {
"success": True,
"operation": operation,
"value1": value1,
"value2": value2,
"result": result,
}
# ============================================================================
# Example 2: Text Processing Tool with Parameter Model
# ============================================================================
class TextProcessParams(BaseModel):
"""Parameters for text processing operations."""
text: str = Field(..., description="The text to process")
operation: str = Field(
default="count_words",
description="Operation: 'count_words', 'to_uppercase', 'to_lowercase', 'reverse', 'count_lines'"
)
@define_tool(description="Process and analyze text content")
async def process_text(text: str, operation: str = "count_words") -> dict:
"""
Processes text with various operations.
Args:
text: Input text to process
operation: Type of processing to apply
Returns:
Dictionary with processing results
"""
results = {
"operation": operation,
"input_length": len(text),
"result": None,
}
if operation == "count_words":
results["result"] = len(text.split())
elif operation == "to_uppercase":
results["result"] = text.upper()
elif operation == "to_lowercase":
results["result"] = text.lower()
elif operation == "reverse":
results["result"] = text[::-1]
elif operation == "count_lines":
results["result"] = len(text.split("\n"))
else:
results["error"] = f"Unknown operation: {operation}"
return results
# ============================================================================
# Example 3: Advanced Tool with Complex Return Type
# ============================================================================
class DataAnalysisParams(BaseModel):
"""Parameters for data analysis."""
data_points: list = Field(..., description="List of numbers to analyze")
include_stats: bool = Field(default=True, description="Include statistical analysis")
@define_tool(description="Analyze numerical data and compute statistics")
async def analyze_data(data_points: list, include_stats: bool = True) -> dict:
"""
Analyzes a list of numerical values.
Args:
data_points: List of numbers to analyze
include_stats: Whether to include statistical analysis
Returns:
Dictionary with analysis results
"""
if not data_points or not all(isinstance(x, (int, float)) for x in data_points):
return {
"error": "data_points must be a non-empty list of numbers",
"success": False,
}
results = {
"success": True,
"count": len(data_points),
"min": min(data_points),
"max": max(data_points),
"sum": sum(data_points),
}
if include_stats:
import statistics
try:
results["mean"] = statistics.mean(data_points)
results["median"] = statistics.median(data_points)
if len(data_points) > 1:
results["stdev"] = statistics.stdev(data_points)
except Exception as e:
results["stats_error"] = str(e)
return results
# ============================================================================
# Tool Registration (Optional: explicit naming)
# ============================================================================
# The SDK will auto-discover tools from @define_tool decorated functions.
# You can optionally register them explicitly by assigning to variables:
math_tool = define_tool(
name="calculate_math",
description="Perform mathematical calculations (add, subtract, multiply, divide, power, sqrt)",
params_type=BaseModel, # Can be complex if needed
)(calculate_math)
text_processor = define_tool(
name="process_text",
description="Process and analyze text (count words, case conversion, etc.)",
params_type=TextProcessParams,
)(process_text)
data_analyzer = define_tool(
name="analyze_data",
description="Analyze numerical data and compute statistics",
params_type=DataAnalysisParams,
)(analyze_data)
# ============================================================================
# Example: Custom Implementation from Scratch
# ============================================================================
# If you need more control, implement the Tool class directly:
#
# from copilot.types import Tool
#
# async def my_custom_handler(query: str) -> str:
# """Your tool logic here."""
# return f"Processed: {query}"
#
# my_tool = Tool(
# name="my_custom_tool",
# description="My custom tool description",
# handler=my_custom_handler,
# parameters={} # Add JSON Schema if complex params needed
# )
if __name__ == "__main__":
"""Test the example tools locally."""
import asyncio
async def main():
# Test math tool
result1 = await calculate_math("add", 10, 5)
print("Math (10 + 5):", result1)
# Test text processor
result2 = await process_text("Hello World", "count_words")
print("Text (count words):", result2)
# Test data analyzer
result3 = await analyze_data([1, 2, 3, 4, 5], include_stats=True)
print("Data Analysis:", result3)
asyncio.run(main())