ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

awesome-copilot Cookbook 实战:用 Python Copilot SDK 与 GitHub MCP Server 生成 PR 年龄分布图

awesome-copilot Cookbook 实战:用 Python Copilot SDK 与 GitHub MCP Server 生成 PR 年龄分布图 awesome-copilot Cookbook 实战用 Python Copilot SDK 与 GitHub MCP Server 生成 PR 年龄分布图【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot本文围绕 awesome-copilot 仓库 Cookbook 中的 Python 配方 pr-visualization.md 展开教你如何使用 GitHub Copilot Python SDKgithub-copilot-sdk在约 170 行代码内构建一个交互式 CLI 工具——它自动识别当前 Git 仓库或接收--repo参数通过 Copilot 内置的 GitHub MCP Server 拉取 Pull Request 数据生成 PR 年龄分布柱状图并进入可追问的交互会话。读完后你可以直接复现该工具并理解「零自定义工具、全依赖 SDK 内置能力」这一设计取舍背后的工程理由。1. 场景为什么要可视化 PR 年龄PR 年龄open PR 存在了多久是衡量仓库评审健康度的核心指标之一大量长时间无人处理的 PR 往往意味着评审瓶颈或成员流失。原始配方将其定义为这样一个场景你希望了解某个仓库中 PR 已经开放了多久。该工具会检测当前 Git 仓库或直接接受一个仓库作为输入然后让 Copilot 通过 GitHub MCP Server 获取 PR 数据并生成图表图像。与自己写一套 GitHub API 抓取 matplotlib 画图 固定分桶逻辑的传统做法不同该配方刻意不编写任何自定义工具而是把数据获取、计算、画图全部交给 Copilot 会话内的内置能力去现场决定。可运行示例位于 recipe/pr_visualization.py配方在 cookbook.yml 清单中注册为pr-visualization标签为github、visualization、mcp且属于站点 Samples 页的 featured cookbook。2. 环境准备与快速上手2.1 前置条件按配方文档安装只有一个核心步骤pip install github-copilot-sdk完整的依赖声明见 recipe/requirements.txt其全部内容就是github-copilot-sdk从 PyPI 安装最新稳定版无需从源码构建。运行前提依据 copilot-sdk-python.instructions.md 的说明该 SDK 目前处于 technical preview 阶段Python 3.9 或更高版本recipe/README.md 中写作 Python 3.8以官方 instructions 文档为准已安装 GitHub Copilot CLI 并加入PATH——SDK 客户端本质上会启动或连接一个 CLI 进程cli_path默认从 PATH 或COPILOT_CLI_PATH环境变量解析全程使用asyncio的 async/await 模式。2.2 两种调用方式cd recipe pip install -r requirements.txt # 方式一自动从当前 git 仓库检测 python pr_visualization.py # 方式二显式指定仓库 python pr_visualization.py --repo github/copilot-sdk仓库根目录的 cookbook/copilot-sdk/README.md 还给出了统一的语言运行约定Python 部分为cd python/cookbook/recipe pip install -r requirements.txt python filename.pyrecipe/README.md 则建议先建虚拟环境再安装依赖。3. 完整代码逐段解析以下是配方的完整源码与 pr_visualization.py 逐行一致下文按功能块拆解。#!/usr/bin/env python3 import asyncio import subprocess import sys import os import re from copilot import ( CopilotClient, SessionConfig, MessageOptions, SessionEvent, PermissionHandler, ) # # Git GitHub Detection # def is_git_repo(): try: subprocess.run( [git, rev-parse, --git-dir], checkTrue, capture_outputTrue ) return True except (subprocess.CalledProcessError, FileNotFoundError): return False def get_github_remote(): try: result subprocess.run( [git, remote, get-url, origin], checkTrue, capture_outputTrue, textTrue ) remote_url result.stdout.strip() # Handle SSH: gitgithub.com:owner/repo.git ssh_match re.search(rgitgithub\.com:(./.?)(?:\.git)?$, remote_url) if ssh_match: return ssh_match.group(1) # Handle HTTPS: https://github.com/owner/repo.git https_match re.search(rhttps://github\.com/(./.?)(?:\.git)?$, remote_url) if https_match: return https_match.group(1) return None except (subprocess.CalledProcessError, FileNotFoundError): return None def parse_args(): args sys.argv[1:] if --repo in args: idx args.index(--repo) if idx 1 len(args): return {repo: args[idx 1]} return {} def prompt_for_repo(): return input(Enter GitHub repo (owner/repo): ).strip() # # Main Application # async def main(): print( PR Age Chart Generator\n) # Determine the repository args parse_args() repo None if repo in args: repo args[repo] print(f Using specified repo: {repo}) elif is_git_repo(): detected get_github_remote() if detected: repo detected print(f Detected GitHub repo: {repo}) else: print(⚠️ Git repo found but no GitHub remote detected.) repo prompt_for_repo() else: print( Not in a git repository.) repo prompt_for_repo() if not repo or / not in repo: print(❌ Invalid repo format. Expected: owner/repo) sys.exit(1) owner, repo_name repo.split(/, 1) # Create Copilot client client CopilotClient() await client.start() session await client.create_session(SessionConfig( modelgpt-5, system_message{ content: f context You are analyzing pull requests for the GitHub repository: {owner}/{repo_name} The current working directory is: {os.getcwd()} /context instructions - Use the GitHub MCP Server tools to fetch PR data - Use your file and code execution tools to generate charts - Save any generated images to the current working directory - Be concise in your responses /instructions }, on_permission_requestPermissionHandler.approve_all)) done asyncio.Event() # Set up event handling def handle_event(event: SessionEvent): if event.type.value assistant.message: print(f\n {event.data.content}\n) elif event.type.value tool.execution_start: print(f ⚙️ {event.data.tool_name}) elif event.type.value session.idle: done.set() session.on(handle_event) # Initial prompt - let Copilot figure out the details print(\n Starting analysis...\n) await session.send(MessageOptions(promptf Fetch the open pull requests for {owner}/{repo_name} from the last week. Calculate the age of each PR in days. Then generate a bar chart image showing the distribution of PR ages (group them into sensible buckets like 1 day, 1-3 days, etc.). Save the chart as pr-age-chart.png in the current directory. Finally, summarize the PR health - average age, oldest PR, and how many might be considered stale. )) await done.wait() # Interactive loop print(\n Ask follow-up questions or type \exit\ to quit.\n) print(Examples:) print( - \Expand to the last month\) print( - \Show me the 5 oldest PRs\) print( - \Generate a pie chart instead\) print( - \Group by author instead of age\) print() while True: user_input input(You: ).strip() if user_input.lower() in [exit, quit]: print( Goodbye!) break if user_input: done.clear() await session.send(MessageOptions(promptuser_input)) await done.wait() await session.destroy() await client.stop() if __name__ __main__: asyncio.run(main())3.1 仓库检测链--repo参数 → git remote → 交互输入检测逻辑集中在文件前半部分pr_visualization.py#L20-L64形成三级回退显式参数parse_args()手工解析sys.argv找到--repo后取其后一个参数值git remote 自动检测is_git_repo()用git rev-parse --git-dir判断当前是否在 Git 仓库内get_github_remote()执行git remote get-url origin再用两条正则分别解析 SSH 形式gitgithub.com:owner/repo.git与 HTTPS 形式https://github.com/owner/repo.git统一剥掉.git后缀提取出owner/repo交互式兜底既不在 Git 仓库、或找到了 Git 仓库但 origin 不是 GitHub 远端时prompt_for_repo()提示用户手工输入。最后还有一道格式校验owner/repo必须包含/否则打印Invalid repo format. Expected: owner/repo并sys.exit(1)随后repo.split(/, 1)拆分出owner与repo_name供后续系统提示词使用。3.2 客户端与会话SessionConfig的三要素核心初始化在 pr_visualization.py#L99-L119client CopilotClient() await client.start() session await client.create_session(SessionConfig( modelgpt-5, system_message{...}, on_permission_requestPermissionHandler.approve_all))三个关键配置点modelgpt-5指定会话使用的模型。注意模型可用性取决于你的 Copilot 订阅与 CLI 环境替换为当前可用模型名即可system_message采用「contextinstructions」两段式结构。context注入目标仓库与当前工作目录os.getcwd()instructions则明确告知 Copilot 三件事用 GitHub MCP Server 工具取 PR 数据、用文件/代码执行工具画图、把图片保存到当前目录——这直接决定了零自定义工具方案能成立所有能力约束都通过提示词表达on_permission_requestPermissionHandler.approve_allCLI 工具会自动批准 Copilot 的工具调用权限请求这是能无人值守跑完取数→计算→写文件链条的前提。若需要人工把关可换成自定义回调官方 instructions 文档在 copilot-sdk-python.instructions.md 中给出了on_permission_request作为权限处理器的完整用法以及 dict 形式的等价配置写法。补充一点instructions 文档还提到手动生命周期之外的另一种写法——session.send_and_wait({prompt: ...}, timeout60.0)可以一步完成发送并等待 idle本配方为演示事件流而选择了更底层的send 事件回调组合。3.3 事件驱动的输出三类SessionEventdef handle_event(event: SessionEvent): if event.type.value assistant.message: print(f\n {event.data.content}\n) elif event.type.value tool.execution_start: print(f ⚙️ {event.data.tool_name}) elif event.type.value session.idle: done.set() session.on(handle_event)这段订阅式处理pr_visualization.py#L121-L132是整个 CLI 的进度条assistant.message打印 Copilot 的最终答复event.data.contenttool.execution_start打印正在执行的工具名让你实时看到它正在调 GitHub MCP / 写文件session.idle会话进入空闲用done.set()唤醒await done.wait()的调用方。官方 instructions 文档copilot-sdk-python.instructions.md将用asyncio.Event等待session.idle列为推荐的同步模式之一此外还说明开启streaming: True后可额外收到assistant.message.delta增量事件而assistant.message等最终事件无论是否开流式都会发送。本配方保持非流式的简洁形态。3.4 初始提示词把任务规格交给 AI初始 promptpr_visualization.py#L137-L144是一个结构完整的任务描述包含五个明确产出物拉取该仓库最近一周的 open PR计算每个 PR 的年龄天生成柱状图按合理分桶1 day、1-3 days等——分桶策略由 AI 自行判断而非硬编码图表保存为当前目录下的pr-age-chart.png输出 PR 健康度摘要平均年龄、最老的 PR、多少可能已腐烂。3.5 交互式追问循环与会话清理初始分析完成后工具进入 REPL 式循环pr_visualization.py#L148-L170while True: user_input input(You: ).strip() if user_input.lower() in [exit, quit]: print( Goodbye!) break if user_input: done.clear() await session.send(MessageOptions(promptuser_input)) await done.wait() await session.destroy() await client.stop()要点每次追问前先done.clear()再发送、等待保证上一轮完整结束后才进入下一轮会话内串行化exit/quit退出后依次调用session.destroy()与client.stop()完成资源回收——instructions 文档同时提示若stop()超时可用force_stop()。配方内置的四条示例追问也展示了该方案的灵活性Expand to the last month、Show me the 5 oldest PRs、Generate a pie chart instead、Group by author instead of age。4. 工作流程总览配方文档将其归纳为三步仓库检测--repo标志 → git remote → 提示用户输入零自定义工具完全依赖 Copilot CLI 的内置能力——GitHub MCP Server从 GitHub 拉取 PR 数据文件工具保存生成的图表图像代码执行用 Python/matplotlib 或其他方式生成图表交互会话完成初始分析后用户可持续追问调整。5. 设计取舍为什么不用自定义工具配方附带的对比表是理解该方案价值的关键AspectCustom ToolsBuilt-in CopilotCode complexityHighMinimalMaintenanceYou maintainCopilot maintainsFlexibilityFixed logicAI decides best approachChart typesWhat you codedAny type Copilot can generateData groupingHardcoded bucketsIntelligent grouping从源码结构看自定义工具路线意味着你自己封装 GitHub API 客户端、固定分桶算法、固定图表类型任何新需求换饼图、按作者分组都要改代码而本配方把这一切压缩成一个 system message 一条自然语言 prompt扩展需求只需在交互循环里多打一句话。代价是行为不再确定——输出图表与分桶由模型临场决定因此它更适合演示与探索性分析场景对结果有强一致性要求的场景instructions 文档中错误处理/恢复钩子等配方如 error-handling.md、error-recovery-hooks.md提供了对工具失败的分类与重试模式可以作为后续加固参考。6. 在 Cookbook 全景中的位置与延伸同配方的其他语言版本同一仓库的 Cookbook 将 PR Visualization 作为跨语言统一配方可对照 Node.js 版、.NET 版、Go 版 与 Java 版五种语言共用同一套场景描述 可运行示例结构同目录配方Python 配方索引 中还收录了 Error Handling、Error Recovery Hooks、Multiple Sessions、Managing Local Files、Persisting Sessions、PyInstaller Frozen Build 等主题与本篇共同构成完整的 SDK 使用样本集站点清单cookbook.yml 中pr-visualization配方的注册信息描述Generate interactive PR age charts using GitHub MCP Server与github/visualization/mcp标签与正文完全一致保证网站 Samples 页展示与文档同步。7. 局限与适用前提SDK 处于technical previewinstructions 文档明确提示可能存在破坏性变更升级github-copilot-sdk后如遇 API 变动应以最新版文档为准运行必须依赖已登录可用的 GitHub Copilot CLI 环境modelgpt-5仅表示当前仓库示例采用的模型名实际以环境可用模型为准PermissionHandler.approve_all会自动批准一切工具调用生产环境中应替换为带校验的权限回调图表质量与分桶方式由模型临场决定如需精确口径请改用自定义工具路线或收紧初始 prompt。总结这个约 170 行的配方展示了 Copilot Python SDK 的最小完整闭环——CopilotClient启动 →SessionConfig注入上下文与权限策略 →session.send下发任务 → 订阅SessionEvent渲染过程 → 会话空闲驱动交互循环 → 优雅销毁。它既是可直接运行的 PR 年龄可视化工具也是理解用提示词代替工具代码这一 SDK 编程范式的最佳样本。【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表