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

110
scripts/update_pipe.py Normal file
View File

@@ -0,0 +1,110 @@
import requests
import json
import os
import re
from pathlib import Path
# ─── Configuration ───────────────────────────────────────────────────────────
SCRIPT_DIR = Path(__file__).parent
ENV_FILE = SCRIPT_DIR / ".env"
URL = (
"http://localhost:3003/api/v1/functions/id/github_copilot_official_sdk_pipe/update"
)
FILE_PATH = SCRIPT_DIR.parent / "plugins/pipes/github-copilot-sdk/github_copilot_sdk.py"
def _load_api_key() -> str:
"""Load API key from .env file in the same directory as this script.
The .env file should contain a line like:
api_key=sk-xxxxxxxxxxxx
"""
if not ENV_FILE.exists():
raise FileNotFoundError(
f".env file not found at {ENV_FILE}. "
"Please create it with: api_key=sk-xxxxxxxxxxxx"
)
for line in ENV_FILE.read_text(encoding="utf-8").splitlines():
line = line.strip()
if line.startswith("api_key="):
key = line.split("=", 1)[1].strip()
if key:
return key
raise ValueError("api_key not found in .env file.")
def update_pipe() -> None:
"""Push the latest local github_copilot_sdk.py content to OpenWebUI."""
# 1. Load API key
try:
api_key = _load_api_key()
except (FileNotFoundError, ValueError) as e:
print(f"[ERROR] {e}")
return
# 2. Read local source file
if not FILE_PATH.exists():
print(f"[ERROR] Source file not found: {FILE_PATH}")
return
content = FILE_PATH.read_text(encoding="utf-8")
# 3. Extract version from docstring
version_match = re.search(r"version:\s*([\d.]+)", content)
version = version_match.group(1) if version_match else "0.9.0"
# 4. Build payload
payload = {
"id": "github_copilot_official_sdk_pipe",
"name": "GitHub Copilot Official SDK Pipe",
"meta": {
"description": (
"Integrate GitHub Copilot SDK. Supports dynamic models, "
"multi-turn conversation, streaming, multimodal input, "
"infinite sessions, and frontend debug logging."
),
"manifest": {
"title": "GitHub Copilot Official SDK Pipe",
"author": "Fu-Jie",
"author_url": "https://github.com/Fu-Jie/openwebui-extensions",
"funding_url": "https://github.com/open-webui",
"openwebui_id": "ce96f7b4-12fc-4ac3-9a01-875713e69359",
"description": (
"Integrate GitHub Copilot SDK. Supports dynamic models, "
"multi-turn conversation, streaming, multimodal input, "
"infinite sessions, bidirectional OpenWebUI Skills bridge, "
"and manage_skills tool."
),
"version": version,
"requirements": "github-copilot-sdk==0.1.25",
},
"type": "pipe",
},
"content": content,
}
# 5. Build headers — use long-lived API key instead of short-lived JWT
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
# 6. Send update request
print(f"Updating pipe with version {version}...")
try:
response = requests.post(URL, headers=headers, data=json.dumps(payload))
if response.status_code == 200:
print("✅ Successfully updated GitHub Copilot Official SDK Pipe!")
else:
print(f"❌ Failed to update. Status: {response.status_code}")
print(f" Response: {response.text[:500]}")
except Exception as e:
print(f"❌ Request error: {e}")
if __name__ == "__main__":
update_pipe()