feat: release github-copilot-sdk v0.6.0 and files-filter v0.1.2

This commit is contained in:
fujie
2026-02-09 19:45:23 +08:00
parent 1fcad993ea
commit 9185f88d40
25 changed files with 3686 additions and 2766 deletions

View File

@@ -0,0 +1,103 @@
import os
import sys
import json
import asyncio
from typing import List, Dict
# 1. 尝试导入 OpenWebUI 环境
try:
from open_webui.models.models import Models, ModelForm, ModelMeta, ModelParams
from open_webui.internal.db import get_session
except ImportError:
print("❌ 错误: 无法导入 OpenWebUI 模块。请确保在 OpenWebUI 环境(如 conda ai中运行此脚本。")
sys.exit(1)
# 2. 导入 Copilot SDK
try:
from copilot import CopilotClient
except ImportError:
print("❌ 错误: 无法导入 copilot SDK。请运行: pip install github-copilot-sdk==0.1.23")
sys.exit(1)
async def fetch_real_models() -> List[Dict]:
gh_token = os.environ.get("GH_TOKEN")
if not gh_token:
print("❌ 错误: 未设置 GH_TOKEN 环境变量。")
return []
client = CopilotClient()
try:
await client.start()
raw_models = await client.list_models()
processed = []
for m in raw_models:
m_id = getattr(m, "id", str(m))
# 提取倍率
billing = getattr(m, "billing", {})
if not isinstance(billing, dict): billing = vars(billing)
multiplier = billing.get("multiplier", 1)
# 提取能力
cap = getattr(m, "capabilities", None)
vision = False
reasoning = False
if cap:
supports = getattr(cap, "supports", {})
if not isinstance(supports, dict): supports = vars(supports)
vision = supports.get("vision", False)
reasoning = supports.get("reasoning_effort", False)
processed.append({
"id": m_id,
"name": f"GitHub Copilot ({m_id})",
"vision": vision,
"reasoning": reasoning,
"multiplier": multiplier
})
return processed
except Exception as e:
print(f"❌ 获取模型失败: {e}")
return []
finally:
await client.stop()
async def sync_to_db():
models = await fetch_real_models()
if not models: return
print(f"🔄 发现 {len(models)} 个 Copilot 模型,正在同步到工作区...")
# 默认管理员 ID
admin_user_id = "00000000-0000-0000-0000-000000000000"
for m in models:
# 对应插件中的 ID 格式
full_id = f"copilot-{m['id']}"
existing = Models.get_model_by_id(full_id)
if existing:
print(f"⚠️ 跳过: {full_id} (已存在)")
continue
form_data = ModelForm(
id=full_id,
base_model_id=None,
name=m['name'],
meta=ModelMeta(
description=f"GitHub Copilot 官方模型。倍率: {m['multiplier']}x。支持推理: {m['reasoning']}",
capabilities={
"vision": m['vision'],
"reasoning": m['reasoning']
}
),
params=ModelParams()
)
try:
if Models.insert_new_model(form_data, admin_user_id):
print(f"✅ 成功同步: {m['name']}")
except Exception as e:
print(f"❌ 同步 {m['id']} 失败: {e}")
if __name__ == "__main__":
asyncio.run(sync_to_db())

View File

@@ -0,0 +1,111 @@
import asyncio
import os
import json
import time
from typing import Any
from datetime import datetime
from copilot import CopilotClient
# 自定义 JSON 编码器,处理 datetime 等对象
class SDKEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if hasattr(obj, "to_dict"):
return obj.to_dict()
try:
return super().default(obj)
except TypeError:
return str(obj)
async def run_debug_test(client, model_id, effort, prompt):
print(f"\n" + "🔍" * 15)
print(f"DEBUGGING: {model_id} | {effort.upper()}")
print("🔍" * 15)
session_config = {
"model": model_id,
"reasoning_effort": effort
}
queue = asyncio.Queue()
done = asyncio.Event()
SENTINEL = object()
def handler(event):
try:
etype = getattr(event, "type", "unknown")
if hasattr(etype, "value"): etype = etype.value
raw_data = {}
# 优先尝试 SDK 自带的 to_dict
if hasattr(event, "to_dict"):
raw_data = event.to_dict()
elif hasattr(event, "data"):
data_obj = event.data
if isinstance(data_obj, dict):
raw_data = data_obj
elif hasattr(data_obj, "to_dict"):
raw_data = data_obj.to_dict()
else:
raw_data = {k: v for k, v in vars(data_obj).items() if not k.startswith('_')}
else:
raw_data = {k: v for k, v in vars(event).items() if not k.startswith('_')}
queue.put_nowait((etype, raw_data))
if etype in ["session.idle", "session.error"]:
done.set()
queue.put_nowait(SENTINEL)
except Exception as e:
print(f"Handler Error: {e}")
try:
session = await client.create_session(config=session_config)
unsubscribe = session.on(handler)
print(f"Sending prompt...")
asyncio.create_task(session.send({"prompt": prompt, "mode": "immediate"}))
event_count = 0
while True:
try:
item = await asyncio.wait_for(queue.get(), timeout=180)
if item is SENTINEL: break
etype, data = item
event_count += 1
# 打印所有事件,不进行过滤,这样我们可以看到完整的生命周期
print(f"\n[#{event_count} EVENT: {etype}]")
print(json.dumps(data, indent=2, ensure_ascii=False, cls=SDKEncoder))
except asyncio.TimeoutError:
print("\n⚠️ Timeout: No events for 180s")
break
unsubscribe()
await session.destroy()
except Exception as e:
print(f"❌ Session Failed: {e}")
async def main():
gh_token = os.environ.get("GH_TOKEN")
if not gh_token:
print("❌ Error: GH_TOKEN not set")
return
client = CopilotClient()
await client.start()
# 使用一个简单但需要思考的问题
prompt = "123 * 456 等于多少?请给出思考过程。"
target_model = "gpt-5-mini"
await run_debug_test(client, target_model, "high", prompt)
await client.stop()
if __name__ == "__main__":
asyncio.run(main())