feat(OPEN-11243): add GitHub Copilot SDK tracing - #223
Open
viniciusdsmello wants to merge 1 commit into
Open
Conversation
Trace agents built on the GitHub Copilot SDK (`@github/copilot-sdk`) to
Openlayer. TypeScript counterpart to the Python integration, structurally
mirroring it so the two stay comparable.
import { traceCopilot } from "openlayer/lib/integrations/copilotSdk";
traceCopilot();
patches `CopilotClient.prototype.createSession`, so every session is
traced with no change to the code that builds them.
`openlayerEventHandler()` is the explicit alternative for callers who
build sessions themselves. Both compose with a user-supplied `onEvent`
and never replace it; an exception in either handler cannot break the
other. Combining the two is safe: the patch defers to a caller-supplied
Openlayer handler rather than adding a second collector, so mixing the
quickstart with the per-session snippet cannot produce duplicate rows.
Trace shape — one trace per `send()`:
AGENT "GitHub Copilot" user prompt in, final answer out
├─ CHAT_COMPLETION "turn 0" model, provider, tokens, latency
├─ TOOL "bash" arguments in, result out
├─ AGENT "subagent: Explore Agent" a `task` dispatch
│ ├─ CHAT_COMPLETION "turn 0"
│ └─ TOOL "view"
└─ CHAT_COMPLETION "turn 1"
Architecture: buffer live, build deferred
-----------------------------------------
`assistant.usage` — which carries every token count — is ephemeral and
absent from `getEvents()`, so we must subscribe live. But Copilot fires
tool calls *concurrently*, with completions arriving out of order, so
building steps from the live callbacks would nest siblings inside one
another. We buffer live and build the whole trace in one deterministic,
correctly-nested pass at `session.idle`.
Cost
----
Copilot's `cost` field is premium-request units, not dollars, so it is
recorded as metadata. We emit provider+model and let Openlayer price it,
mapping the model prefix to the real vendor — `llm-costs` has no `github`
provider, so labelling it that way would silently yield $0.
GitHub meters each call in AIU and ships its own per-token rates, which
are the vendor's list prices scaled by exactly 100 (1 AIU = $0.01),
verified on both an Anthropic and an OpenAI model. Each chat step records
`copilot_metered_cost_usd` so the priced cost is checkable per row; on
live traces the two agree to twelve decimal places. An unmapped model
falls back to that figure rather than landing at $0.
Packaging
---------
New subpath export `./integrations/copilot-sdk`, with
`@github/copilot-sdk` declared as an optional peerDependency (^1.0.11).
The lockfile carries all platform binaries, so a Linux CI runner resolves.
Tests
-----
28 unit tests over the same two captured sessions (converted to the
camelCase shape this binding delivers) covering concurrent tools,
subagent nesting, the apiCallId usage join, the token partition, handler
composition, and the patch itself. Plus a live end-to-end test gated on
OPENLAYER_COPILOT_LIVE_TEST=1.
Example: examples/copilot-sdk-tracing.ts, verified running end to end.
Related: openlayer-python (Python parity), openlayer-docs (docs page).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S48tdMHz7rjd7aJeZCkVic
viniciusdsmello
force-pushed
the
vini/open-11243-integration-github-copilot-sdk
branch
from
August 29, 2026 18:37
a77421d to
66f314e
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Traces agents built on the GitHub Copilot SDK (
@github/copilot-sdk) to Openlayer. TypeScript counterpart to openlayer-ai/openlayer-python#669, structurally mirroringcopilot_sdk.pyso the two stay comparable.patches
CopilotClient.prototype.createSession, so every session is traced with no change to the code that builds them.openlayerEventHandler()is the explicit alternative for callers who build sessions themselves. Both compose with a user-suppliedonEventand never replace it; an exception in either handler cannot break the other.Trace shape
One trace per
send():Every trace carries the Copilot session id, so multi-turn conversations group into one session.
Why buffer instead of building live
assistant.usage— which carries every token count — isephemeraland absent fromgetEvents(), so we must subscribe live. But Copilot fires tool calls concurrently, with completions arriving out of order, so building steps from the live callbacks would nest siblings inside one another. We buffer live and build the whole trace in one deterministic, correctly-nested pass atsession.idle.Cost
Copilot's
costfield is premium-request units, not dollars, so it is recorded as metadata. We emit provider + model and let Openlayer price it, mapping the model prefix to the real vendor —llm-costshas nogithubprovider, so labelling it that way would silently yield $0.GitHub meters each call in AIU and ships its own per-token rates, which turn out to be the vendor's list prices scaled by exactly 100 (1 AIU = $0.01), verified on both an Anthropic and an OpenAI model. Each chat step records
copilot_metered_cost_usdso the priced cost is checkable per row; on live traces the two agree to twelve decimal places. An unmapped model falls back to that figure rather than landing at $0.Packaging
New subpath export
./integrations/copilot-sdk, with@github/copilot-sdkas an optional peerDependency (^1.0.11) — mirroring how@anthropic-ai/claude-agent-sdkis handled.yarn.lockgrows because the SDK pulls platform-specific CLI binaries. The lockfile records all platforms (darwin / linux / linuxmusl / win32 × arm64/x64), so--frozen-lockfileresolves on a Linux CI runner.Testing
26 unit tests over the same two captured sessions used on the Python side, converted to the camelCase shape this binding delivers. Coverage: concurrent tools, subagent nesting, the
apiCallIdusage join, the token partition, handler composition, and the patch itself.Plus a live end-to-end test gated on
OPENLAYER_COPILOT_LIVE_TEST=1— deliberately not onGITHUB_TOKEN, which developers and unrelated CI steps commonly export and which, as an installation token, has no Copilot access.Verified against real ingest: a published row comes back with
provider: openai,model: gpt-5-mini,cost: 0.00139005, andcopilot_metered_cost_usdmatching to 1e-12.Baseline preserved (the one pre-existing
openai-tracer.test.tsfailure is untouched); lint andtscclean.Example
examples/copilot-sdk-tracing.ts— basic session, client-side tool with a subagent dispatch, and multi-turn session grouping. Verified running end to end against the real SDK.Related
Deliberately does not use
closes, since OPEN-11243 spans three PRs.🤖 Generated with Claude Code
https://claude.ai/code/session_01S48tdMHz7rjd7aJeZCkVic