diff --git a/provider/copilotprovider/copilot.go b/provider/copilotprovider/copilot.go index aa46e8d9..0fd0f3e1 100644 --- a/provider/copilotprovider/copilot.go +++ b/provider/copilotprovider/copilot.go @@ -847,6 +847,15 @@ func (p *provider) assistantUsageUpdate(event copilot.SessionEvent, data *copilo case data.FinishReason != nil: update.FinishReason = *data.FinishReason } + // Surface which model actually served the request, matching the Python + // client which carries it as additional_properties["model"]. Initialize the + // map lazily so existing/future properties are not overwritten. + if data.Model != "" { + if update.AdditionalProperties == nil { + update.AdditionalProperties = make(map[string]any) + } + update.AdditionalProperties["model"] = data.Model + } return update } diff --git a/provider/copilotprovider/copilot_test.go b/provider/copilotprovider/copilot_test.go index 2edb6686..dfc7475e 100644 --- a/provider/copilotprovider/copilot_test.go +++ b/provider/copilotprovider/copilot_test.go @@ -488,6 +488,28 @@ func TestConvertToAgentResponseUpdate_UsageEvent_SurfacesReasoningTokens(t *test } } +// The usage event reports which model actually served the request; it must be +// surfaced on AdditionalProperties, matching the Python client. +func TestConvertToAgentResponseUpdate_UsageEvent_SurfacesModel(t *testing.T) { + runtime := newFakeRuntime(t, + sessionEvent("assistant.usage", map[string]any{ + "model": "gpt-5", + "inputTokens": 10, + "outputTokens": 20, + }), + idleEvent(), + ) + agent := copilotprovider.NewAgent(runtime.client(), copilotprovider.AgentConfig{}) + + response, err := runText(t, agent, "hello") + if err != nil { + t.Fatalf("RunText: %v", err) + } + if got, _ := response.AdditionalProperties["model"].(string); got != "gpt-5" { + t.Fatalf("AdditionalProperties[model] = %q, want gpt-5", got) + } +} + // A content-filter-triggered usage event must report the canonical // "content_filter" finish reason, taking precedence over the raw finishReason, // matching the Python client.