Documentation
¶
Overview ¶
Package copilot implements the event-level adapter for GitHub Copilot CLI.
THREE SURFACES, ONE AUTHORITATIVE FACT EACH (issue #69). Copilot writes three unrelated local artefacts and each of them is the best record of exactly one thing; reading any of them for what another owns is how this adapter would double count.
- ~/.copilot/otel/**/*.jsonl — TOKENS. The OpenTelemetry JSONL the CLI writes when the user enables file export, plus the single file named by COPILOT_OTEL_FILE_EXPORTER_PATH. Its per-call counts are exact: measured against the vendor's own ledger over one session, input 975,612, output 15,237, cache_read 811,374 and cache_write 56,061 agree TO THE UNIT on both surfaces. It is also the only surface that carries the tool-call spans this adapter's activity rows are keyed from. When it is absent the adapter returns no usage at all — the export is opt-in, and doctor surfaces that.
- ~/.copilot/session-store.db — COST, and nothing else here reads it. See cost.go.
- ~/.copilot/session-state/<id>/events.jsonl — SKILLS AND HOOKS, which OTEL names nowhere. See events.go.
Each OTEL record can describe the same model call from several vantage points (chat span, inference log, agent-turn log, agent-summary span). We keep the highest-priority record per shared traceId / gen_ai.response.id and suppress the rest so a single call is counted once.
ACTIVITY (tool calls) comes from `execute_tool` SPANS only, never from the metric records that share the file — see activity.go, which explains why the difference is a 226x one.
CRITICAL: strictly read-only. Files are opened O_RDONLY, the session store is opened mode=ro + query_only(1); nothing under the agent's directories is created, locked, or modified.
Index ¶
- Constants
- func New() adapter.Adapter
- type Adapter
- func (Adapter) Capabilities() model.ToolCapability
- func (a Adapter) Collect(ctx context.Context, src adapter.Source) (adapter.Observation, error)
- func (a Adapter) CollectIncremental(ctx context.Context, src adapter.Source, cp *model.SourceCheckpoint) (adapter.Observation, error)
- func (a Adapter) Discover(ctx context.Context, cfg adapter.DiscoverConfig) ([]adapter.Source, error)
- func (Adapter) DisplayName() string
- func (Adapter) ID() string
Constants ¶
const ExporterEnv = "COPILOT_OTEL_FILE_EXPORTER_PATH"
ExporterEnv names the single-file OTEL exporter override. It stays the ONLY environment variable this adapter consults: the CLI package ships no override for the session store or the session-state root (verified against 1.0.80), so there is nothing further for cmd.discoveryEnv to be taught about.
const PriceSourceAIU = "copilot-nano-aiu"
PriceSourceAIU labels a cost taken from Copilot's own nano-AIU valuation. The price_source vocabulary is open and nothing parses it; the copilot- prefix keeps these distinguishable from the ladder's rungs.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Adapter ¶
type Adapter struct{}
Adapter reads GitHub Copilot CLI OpenTelemetry usage exports.
func (Adapter) Capabilities ¶
func (Adapter) Capabilities() model.ToolCapability
Capabilities declares what this project can say about Copilot.
Cost is VENDOR-reported: cost.go stamps PriceSourceAIU from the vendor's own nano-AI-unit valuation, which collect.stampCost is forbidden to overwrite with a rate-card estimate. Activity is RECORDED BUT UNATTRIBUTED because an execute_tool span's parent is the invoke_agent span, which makes it a SIBLING of the chat spans the usage rows are built from rather than their child.
func (Adapter) Collect ¶
Collect parses one OTEL JSONL file, applies cross-record suppression, and returns the surviving usage events. Malformed lines are tolerated; a read that does not complete returns an error and no checkpoint so the next cycle retries.
func (Adapter) CollectIncremental ¶
func (a Adapter) CollectIncremental(ctx context.Context, src adapter.Source, cp *model.SourceCheckpoint) (adapter.Observation, error)
CollectIncremental dispatches on the source kind and gates every file on size+mtime: unchanged files are not opened at all. A nil cp is a full read.
func (Adapter) Discover ¶
func (a Adapter) Discover(ctx context.Context, cfg adapter.DiscoverConfig) ([]adapter.Source, error)
Discover finds every OTEL JSONL file under <root>/.copilot/otel (recursively) and, additively, the single file named by COPILOT_OTEL_FILE_EXPORTER_PATH, then every <root>/.copilot/session-state/<id>/events.jsonl. Each file becomes one Source; the session store rides along on the OTEL sources as Meta["cost_db"] rather than becoming one of its own (see the metaCostDB comment). Every absence is normal and reported as no source and no error: the OTEL export is opt-in, and events.jsonl is written LAZILY — a session opened and abandoned without a prompt has a directory and no events file at all (measured: 2 of 3 local session directories).
func (Adapter) DisplayName ¶
DisplayName returns the human-friendly name.