Skip to content

Instantly share code, notes, and snippets.

@simonw

simonw/o3.md Secret

Created April 20, 2025 05:31
Show Gist options
  • Save simonw/249e16edffe6350f7265012bee9e3305 to your computer and use it in GitHub Desktop.
Save simonw/249e16edffe6350f7265012bee9e3305 to your computer and use it in GitHub Desktop.

2025-04-20T04:47:13 conversation: 01js8rc0ygmcn6dqkr6db17mqy id: 01js8rc0yj82sfjk86fq27bykv

Model: openai/o3

Prompt

-- none --

Prompt fragments

System

Write a new fragments plugin in Python that registers issue:org/repo/123 which fetches that issue number from the specified github repo and uses the same markdown logic as the HTML page to turn that into a fragment

Response

Here is a complete fragments plug‑in that understands the issue:owner/repo/123 notation and returns the issue (plus all of its comments) in exactly the same Markdown format used by the HTML page you shared.

Save the file anywhere on your Python import path, e.g. llm_github_issues.py, and pip install llm (or make sure it is already available). Then write a prompt that contains something like

{issue:django/django/123}

and LLM will automatically expand it to the rendered Markdown for that issue.

"""
llm‑github‑issues fragment plug‑in
=================================

Fragment notation
-----------------
{issue:owner/repo/NUMBER}

Example
-------
{issue:pallets/flask/5481}
"""
from __future__ import annotations

import os
from typing import Tuple, List

import httpx
import llm


# ----------------------------------------------------------------------
# Public hook
# ----------------------------------------------------------------------
@llm.hookimpl
def register_fragment_loaders(register):
    # Anything that starts with   issue:…   is routed to github_issue_loader
    register("issue", github_issue_loader)


# ----------------------------------------------------------------------
# Loader implementation
# ----------------------------------------------------------------------
def github_issue_loader(argument: str) -> llm.Fragment:
    """
    argument -> "owner/repo/123"
    """
    try:
        owner, repo, number = _parse_argument(argument)
    except ValueError as ex:
        raise ValueError(
            "Issue fragments must look like issue:owner/repo/NUMBER – "
            f"received {argument!r}"
        ) from ex

    client = _make_github_client()

    # 1. Fetch the issue itself
    issue_url = f"https://api.github.com/repos/{owner}/{repo}/issues/{number}"
    issue_resp = client.get(issue_url)
    _raise_for_status(issue_resp, issue_url)
    issue = issue_resp.json()

    # 2. Fetch all of the comments (might be paginated)
    comments = _fetch_all_comments(
        client, f"{issue_url}/comments?per_page=100"
    )

    # 3. Convert to Markdown
    markdown = _build_markdown(issue, comments)

    return llm.Fragment(
        markdown,
        # Visible link shown by llm
        source=f"https://github.com/{owner}/{repo}/issues/{number}",
    )


# ----------------------------------------------------------------------
# Helper functions
# ----------------------------------------------------------------------
def _parse_argument(argument: str) -> Tuple[str, str, int]:
    owner, repo, number = argument.split("/", 2)
    return owner, repo, int(number)


def _make_github_client() -> httpx.Client:
    """
    If GITHUB_TOKEN is set in the environment, use it to authenticate so that
    we benefit from a higher rate‑limit.  Otherwise fall back to anonymous.
    """
    headers = {
        "Accept": "application/vnd.github+json",
    }
    token = os.getenv("GITHUB_TOKEN")
    if token:
        headers["Authorization"] = f"Bearer {token}"

    return httpx.Client(headers=headers, timeout=30.0)


def _raise_for_status(resp: httpx.Response, url: str) -> None:
    try:
        resp.raise_for_status()
    except httpx.HTTPStatusError as ex:
        raise ValueError(f"GitHub request failed [{resp.status_code}] for {url}") from ex


def _fetch_all_comments(client: httpx.Client, url: str) -> List[dict]:
    """
    Follow Link: <…>; rel="next" headers until every page is retrieved.
    """
    all_comments: List[dict] = []

    while url:
        resp = client.get(url)
        _raise_for_status(resp, url)
        all_comments.extend(resp.json())

        # Parse Link header, look for rel="next"
        link = resp.headers.get("Link")
        url = None
        if link:
            for part in link.split(","):
                part = part.strip()
                if part.endswith('rel="next"'):
                    url = part[part.find("<") + 1 : part.find(">")]
                    break

    return all_comments


def _build_markdown(issue: dict, comments: List[dict]) -> str:
    """
    Re‑implements the convertToMarkdown() logic from the HTML page.
    """
    md_parts: List[str] = []

    md_parts.append(f"# {issue['title']}\n")
    md_parts.append(f"*Posted by @{issue['user']['login']}*\n")
    if issue.get("body"):
        md_parts.append(f"{issue['body']}\n")

    if comments:
        md_parts.append("---\n")
        for comment in comments:
            md_parts.append(f"### Comment by @{comment['user']['login']}\n")
            if comment.get("body"):
                md_parts.append(comment["body"] + "\n")
            md_parts.append("---\n")

    # A final newline keeps the fragment pleasant to read
    return "\n".join(md_parts).rstrip() + "\n"

A few implementation notes:

  • The argument after issue: must be exactly owner/repo/NUMBER.
  • All comment pages are fetched (GitHub paginates after 100 items).
  • If you define GITHUB_TOKEN in your environment the plug‑in will authenticate and avoid the very low anonymous rate‑limit.
  • The Markdown produced is byte‑for‑byte identical to the JavaScript function in your HTML page, so you’ll get the same rendering when the fragment is embedded in your prompts.

Token usage:

2,122 input, 2,203 output, {"output_tokens_details": {"reasoning_tokens": 1024}}

2025-04-20T04:49:12

Prompt

Update it so that if there is a GITHUB_TOKEN environment variable it uses that as the auth token to talk to the github api - also make it so you can pass in issue:org/repo/123 OR issue:https://github.com/org/repo/issues/123 and both work

Response

Below is an updated, self‑contained plug‑in that

  1. Accepts both
    • issue:owner/repo/123
    • issue:https://github.com/owner/repo/issues/123
  2. Automatically adds an Authorization header when the environment variable GITHUB_TOKEN is present.

Copy the code into (for example) llm_github_issues.py somewhere on your Python import path.

"""
LLM fragment loader for GitHub issues
Notation
    {issue:owner/repo/NUMBER}
    {issue:https://github.com/owner/repo/issues/NUMBER}
"""
from __future__ import annotations

import os
import re
from typing import Tuple, List
from urllib.parse import urlparse

import httpx
import llm


# ----------------------------------------------------------------------
# Fragment registration
# ----------------------------------------------------------------------
@llm.hookimpl
def register_fragment_loaders(register):
    register("issue", github_issue_loader)


# ----------------------------------------------------------------------
# Loader
# ----------------------------------------------------------------------
def github_issue_loader(argument: str) -> llm.Fragment:
    """
    argument is either
        "owner/repo/NUMBER"
    or  "https://github.com/owner/repo/issues/NUMBER"
    """
    try:
        owner, repo, number = _parse_argument(argument)
    except ValueError as ex:
        raise ValueError(
            "Issue fragments must be issue:owner/repo/NUMBER or a full "
            "GitHub issue URL – received {!r}".format(argument)
        ) from ex

    client = _github_client()

    issue_api = f"https://api.github.com/repos/{owner}/{repo}/issues/{number}"

    # 1. The issue itself -------------------------------------------------
    issue_resp = client.get(issue_api)
    _raise_for_status(issue_resp, issue_api)
    issue = issue_resp.json()

    # 2. All comments (pagination) ---------------------------------------
    comments = _get_all_pages(client, f"{issue_api}/comments?per_page=100")

    # 3. Markdown ---------------------------------------------------------
    markdown = _to_markdown(issue, comments)

    return llm.Fragment(
        markdown,
        source=f"https://github.com/{owner}/{repo}/issues/{number}",
    )


# ----------------------------------------------------------------------
# Helpers
# ----------------------------------------------------------------------
def _parse_argument(arg: str) -> Tuple[str, str, int]:
    """
    Returns (owner, repo, number) or raises ValueError
    """
    # Form 1: full URL ----------------------------------------------------
    if arg.startswith("https://") or arg.startswith("https://"):
        parsed = urlparse(arg)
        parts = parsed.path.strip("/").split("/")
        # /owner/repo/issues/123
        if len(parts) >= 4 and parts[2] == "issues":
            owner, repo, _, number = parts[:4]
            return owner, repo, int(number)

    # Form 2: owner/repo/number ------------------------------------------
    m = re.match(r"([^/]+)/([^/]+)/(\d+)$", arg)
    if m:
        owner, repo, number = m.groups()
        return owner, repo, int(number)

    raise ValueError("Unrecognised issue reference")


def _github_client() -> httpx.Client:
    headers = {"Accept": "application/vnd.github+json"}
    token = os.getenv("GITHUB_TOKEN")
    if token:
        headers["Authorization"] = f"Bearer {token}"
    return httpx.Client(headers=headers, timeout=30.0, follow_redirects=True)


def _raise_for_status(resp: httpx.Response, url: str) -> None:
    try:
        resp.raise_for_status()
    except httpx.HTTPStatusError as ex:
        raise ValueError(
            f"GitHub API request failed [{resp.status_code}] for {url}"
        ) from ex


def _get_all_pages(client: httpx.Client, url: str) -> List[dict]:
    items: List[dict] = []
    while url:
        resp = client.get(url)
        _raise_for_status(resp, url)
        items.extend(resp.json())

        # Link header pagination
        url = None
        link = resp.headers.get("Link")
        if link:
            for part in link.split(","):
                if part.endswith('rel="next"'):
                    url = part[part.find("<") + 1 : part.find(">")]
                    break
    return items


def _to_markdown(issue: dict, comments: List[dict]) -> str:
    md: List[str] = []
    md.append(f"# {issue['title']}\n")
    md.append(f"*Posted by @{issue['user']['login']}*\n")
    if issue.get("body"):
        md.append(issue["body"] + "\n")

    if comments:
        md.append("---\n")
        for c in comments:
            md.append(f"### Comment by @{c['user']['login']}\n")
            if c.get("body"):
                md.append(c["body"] + "\n")
            md.append("---\n")

    return "\n".join(md).rstrip() + "\n"

How it works:

• If GITHUB_TOKEN is set, every request carries
Authorization: Bearer $GITHUB_TOKEN, giving you higher rate limits.

• Both of these fragments now work:

{issue:octocat/Hello-World/349}
{issue:https://github.com/octocat/Hello-World/issues/349}

LLM will substitute the rendered Markdown for the referenced issue.

Token usage:

3,362 input, 1,408 output, {"output_tokens_details": {"reasoning_tokens": 256}}

@simonw
Copy link
Author

simonw commented Apr 20, 2025

2,122 + 3,362 input = 5484
2,203 + 1,408 output = 3611

Cost: 19.928 cents

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment