Created
June 8, 2026 22:04
-
-
Save compustar/442835927fe23fea34b6f3d1d3704b00 to your computer and use it in GitHub Desktop.
copilot_sdk_04.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "nbformat": 4, | |
| "nbformat_minor": 0, | |
| "metadata": { | |
| "colab": { | |
| "private_outputs": true, | |
| "provenance": [], | |
| "authorship_tag": "ABX9TyNMCvdNY//DJzzkBEmneVvM", | |
| "include_colab_link": true | |
| }, | |
| "kernelspec": { | |
| "name": "python3", | |
| "display_name": "Python 3" | |
| }, | |
| "language_info": { | |
| "name": "python" | |
| } | |
| }, | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "id": "view-in-github", | |
| "colab_type": "text" | |
| }, | |
| "source": [ | |
| "<a href=\"https://colab.research.google.com/gist/compustar/442835927fe23fea34b6f3d1d3704b00/copilot_sdk_04.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "id": "sNF-MqHEChKC" | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "%%capture\n", | |
| "!pip install github-copilot-sdk\n", | |
| "!pip install nest-asyncio\n", | |
| "\n", | |
| "from IPython.display import HTML, display\n", | |
| "\n", | |
| "def set_css():\n", | |
| " display(HTML('''\n", | |
| " <style>\n", | |
| " pre {\n", | |
| " white-space: pre-wrap;\n", | |
| " }\n", | |
| " </style>\n", | |
| " '''))\n", | |
| "get_ipython().events.register('pre_run_cell', set_css)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "#@title Retrieve the API key\n", | |
| "#@markdown\n", | |
| "#@markdown Create new API key from AI Studio and setup the secrets in the sidebar\n", | |
| "\n", | |
| "from google.colab import userdata\n", | |
| "llm_key_name = \"gemini-key\" #@param {type:\"string\"}\n", | |
| "firecrawl_key_name = \"FIRECRAWL_API_KEY\" #@param {type:\"string\"}\n", | |
| "api_key = userdata.get(llm_key_name)\n", | |
| "firecrawl_api_key = userdata.get(firecrawl_key_name)\n", | |
| "\n", | |
| "#@markdown See https://ai.google.dev/gemini-api/docs/models for the list of valid models\n", | |
| "model=\"gemini-3.1-flash-lite\" #@param {type:\"string\"}" | |
| ], | |
| "metadata": { | |
| "id": "wWJS5A38DCM0" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "#@title Setup LLM Provider\n", | |
| "#@markdown This configuration redirects the GitHub Copilot SDK to use the Gemini API via its OpenAI-compatible endpoint.\n", | |
| "#@markdown This allows using the SDK without a GitHub Copilot subscription.\n", | |
| "provider = {\n", | |
| " \"type\": \"openai\",\n", | |
| " \"base_url\": \"https://generativelanguage.googleapis.com/v1beta/openai/\",\n", | |
| " \"wire_api\": \"completions\", # Use \"completions\" for older models\n", | |
| " \"api_key\": api_key\n", | |
| "}" | |
| ], | |
| "metadata": { | |
| "id": "hjVgGJ7GH8Mu" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "metadata": { | |
| "id": "f3e40e04" | |
| }, | |
| "source": [ | |
| "from typing import Any, Optional, List\n", | |
| "from pydantic import BaseModel, Field\n", | |
| "from copilot import define_tool\n", | |
| "import httpx\n", | |
| "from google.colab import userdata\n", | |
| "\n", | |
| "class FirecrawlSearchParams(BaseModel):\n", | |
| " query: str = Field(..., description=\"The search query to find information on the web\")\n", | |
| " limit: int = Field(default=5, description=\"Maximum number of results to return\")\n", | |
| "\n", | |
| "# Reverting to dict[str, Any] return type for better compatibility\n", | |
| "async def fetch_firecrawl_results(params: FirecrawlSearchParams) -> dict[str, Any]:\n", | |
| " endpoint = \"https://api.firecrawl.dev/v2/search\"\n", | |
| "\n", | |
| " headers = {\n", | |
| " \"Authorization\": f\"Bearer {firecrawl_api_key}\",\n", | |
| " \"Content-Type\": \"application/json\"\n", | |
| " }\n", | |
| "\n", | |
| " payload = {\n", | |
| " \"query\": params.query,\n", | |
| " \"limit\": params.limit,\n", | |
| " }\n", | |
| "\n", | |
| " async with httpx.AsyncClient() as client:\n", | |
| " response = await client.post(endpoint, json=payload, headers=headers, timeout=30.0)\n", | |
| " response.raise_for_status()\n", | |
| " return response.json()\n", | |
| "\n", | |
| "@define_tool(\"web_search\", description=\"Search the web\")\n", | |
| "async def firecrawl_search_tool(params: FirecrawlSearchParams) -> dict[str, Any]:\n", | |
| " return await fetch_firecrawl_results(params)" | |
| ], | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "metadata": { | |
| "cellView": "form", | |
| "id": "ce829364" | |
| }, | |
| "source": [ | |
| "#@markdown **This cell is commented out and for testing purpose only**\n", | |
| "# import asyncio\n", | |
| "\n", | |
| "# async def test_firecrawl():\n", | |
| "# # Setting up the params for the search\n", | |
| "# params = FirecrawlSearchParams(query=\"latest news on artificial intelligence\", limit=3)\n", | |
| "\n", | |
| "# print(f\"Searching for: {params.query}...\")\n", | |
| "# # Call the logic function which now returns a dictionary\n", | |
| "# result = await fetch_firecrawl_results(params)\n", | |
| "\n", | |
| "# # Accessing via dict keys instead of attributes\n", | |
| "# if result.get(\"success\"):\n", | |
| "# print(f\"Success: {result['success']}\")\n", | |
| "# data = result.get(\"data\", [])\n", | |
| "# for i, key in enumerate(data):\n", | |
| "# for j, item in enumerate(data[key]):\n", | |
| "# print(f\"\\n[{j+1}] Title: {item.get('title')}\")\n", | |
| "# print(f\" URL: {item.get('url')}\")\n", | |
| "# snippet = item.get('snippet')\n", | |
| "# if snippet:\n", | |
| "# print(f\" Snippet: {snippet[:100]}...\")\n", | |
| "# else:\n", | |
| "# print(f\"Search failed or returned no results: {result}\")\n", | |
| "\n", | |
| "\n", | |
| "# # Run the test\n", | |
| "# await test_firecrawl()" | |
| ], | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "import json\n", | |
| "import asyncio\n", | |
| "from copilot.generated.session_events import AssistantUsageData, AssistantMessageData, SystemMessageData, ToolExecutionStartData, SessionIdleData\n", | |
| "\n", | |
| "# Global queue for session events\n", | |
| "event_queue = asyncio.Queue()\n", | |
| "\n", | |
| "#@title Event Handler\n", | |
| "def handle_event(event):\n", | |
| " # Put the event into the queue for the main loop to process\n", | |
| " asyncio.get_event_loop().call_soon_threadsafe(event_queue.put_nowait, event)\n", | |
| "\n", | |
| "async def event_generator():\n", | |
| " \"\"\"Asynchronous generator yielding dicts: {'title': ..., 'content': ...}\"\"\"\n", | |
| " while True:\n", | |
| " event = await event_queue.get()\n", | |
| " try:\n", | |
| " if isinstance(event.data, AssistantUsageData):\n", | |
| " yield {\n", | |
| " \"title\": \"Tokens used\",\n", | |
| " \"content\": {\n", | |
| " \"input\": event.data.input_tokens,\n", | |
| " \"output\": event.data.output_tokens,\n", | |
| " \"cache_read\": event.data.cache_read_tokens,\n", | |
| " \"cache_write\": event.data.cache_write_tokens,\n", | |
| " }\n", | |
| " }\n", | |
| " elif isinstance(event.data, SystemMessageData):\n", | |
| " yield {\n", | |
| " \"title\": \"System message\",\n", | |
| " \"content\": json.dumps({\n", | |
| " \"first_line\": event.data.content.split('\\n')[0],\n", | |
| " \"content_length\": len(event.data.content)\n", | |
| " }, indent=2)\n", | |
| " }\n", | |
| " elif isinstance(event.data, ToolExecutionStartData):\n", | |
| " yield {\n", | |
| " \"title\": \"Tool execution\",\n", | |
| " \"content\": {\n", | |
| " \"tool_name\": event.data.tool_name,\n", | |
| " \"arguments\": event.data.arguments,\n", | |
| " }\n", | |
| " }\n", | |
| " elif isinstance(event.data, AssistantMessageData):\n", | |
| " if event.data.content:\n", | |
| " yield {\n", | |
| " \"title\": \"Assistant message\",\n", | |
| " \"content\": event.data.content\n", | |
| " }\n", | |
| " elif isinstance(event.data, SessionIdleData):\n", | |
| " break\n", | |
| " finally:\n", | |
| " event_queue.task_done()" | |
| ], | |
| "metadata": { | |
| "id": "uPcvGrDxE2e_" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "import asyncio\n", | |
| "import nest_asyncio\n", | |
| "nest_asyncio.apply()\n", | |
| "\n", | |
| "from copilot import CopilotClient\n", | |
| "from copilot.session import PermissionHandler, SystemMessageReplaceConfig\n", | |
| "\n", | |
| "async def main():\n", | |
| " question = \"what is Qwen 3.7?\" #@param {type:\"string\"}\n", | |
| " async with CopilotClient() as client:\n", | |
| " async with await client.create_session(\n", | |
| " on_permission_request=PermissionHandler.approve_all,\n", | |
| " model=model,\n", | |
| " provider=provider,\n", | |
| " system_message=SystemMessageReplaceConfig(\n", | |
| " mode=\"replace\",\n", | |
| " content=\"You are a helpful assistant. Use web_search for queries.\"\n", | |
| " ),\n", | |
| " tools=[firecrawl_search_tool],\n", | |
| " available_tools=['web_search']\n", | |
| " ) as session:\n", | |
| " session.on(handle_event)\n", | |
| "\n", | |
| " # Send the question without blocking\n", | |
| " send_task = asyncio.create_task(session.send(question))\n", | |
| "\n", | |
| " # Simple one-liner loop processing the dict\n", | |
| " async for info in event_generator():\n", | |
| " print(f\"{info['title']}: {info['content']}\")\n", | |
| "\n", | |
| " await send_task\n", | |
| "\n", | |
| "asyncio.run(main())" | |
| ], | |
| "metadata": { | |
| "id": "0wWwRlcECp8l" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [], | |
| "metadata": { | |
| "id": "A7hnuQ56Cu4h" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment