Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds visibility into model mapping by tracking the actual upstream model (upstream_model) used after model mapping, separately from the user-requested model. When a user requests gpt-4o but it's mapped to gpt-4o-mini, both models are now logged.
Changes:
- New nullable
upstream_modelcolumn inusage_logstable (migration 068) plus full Ent schema, mutation, predicates, and runtime support ForwardResultandOpenAIForwardResultnow carryUpstreamModel; all gateway services (Anthropic, Antigravity, OpenAI HTTP, OpenAI WebSocket v2) populate it only when mapping was applied- Admin UI and Excel export show upstream model; backend DTO and repository wiring updated accordingly
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
backend/migrations/068_add_upstream_model.sql |
Adds upstream_model VARCHAR(100) column |
backend/ent/schema/usage_log.go |
Adds Optional/Nillable upstream_model field (MaxLen 100) |
backend/ent/usagelog.go |
Generated entity with UpstreamModel *string field + scan/assign logic |
backend/ent/usagelog/usagelog.go |
Field constant, validator, Columns list, and ordering function |
backend/ent/usagelog/where.go |
Generated predicates for upstream_model field |
backend/ent/usagelog_create.go |
Generated create/upsert builder methods for upstream_model |
backend/ent/usagelog_update.go |
Generated update builder + validation for upstream_model |
backend/ent/mutation.go |
Mutation struct field and all mutation methods; fixes GroupMutation capacity |
backend/ent/migrate/schema.go |
Column definition and updated foreign key/index column references |
backend/ent/runtime/runtime.go |
Updated field index offsets for all validators/defaults |
backend/internal/service/usage_log.go |
Adds UpstreamModel *string to UsageLog service struct |
backend/internal/service/gateway_service.go |
ForwardResult.UpstreamModel field; sets it in Forward/forwardAnthropicAPIKeyPassthrough; uses it for billing |
backend/internal/service/antigravity_gateway_service.go |
Sets UpstreamModel in Forward and ForwardGemini when mapping occurs |
backend/internal/service/openai_gateway_service.go |
OpenAIForwardResult.UpstreamModel; sets it in Forward; uses it for billing in RecordUsage |
backend/internal/service/openai_ws_forwarder.go |
Sets UpstreamModel in forwardOpenAIWSV2 and ProxyResponsesWebSocketFromClient |
backend/internal/repository/usage_log_repo.go |
Adds upstream_model to SELECT/INSERT and scan logic |
backend/internal/handler/dto/types.go |
Adds UpstreamModel *string to AdminUsageLog DTO |
backend/internal/handler/dto/mappers.go |
Maps l.UpstreamModel to AdminUsageLog.UpstreamModel |
backend/internal/service/gateway_anthropic_apikey_passthrough_test.go |
Updated tests to pass both originalModel and reqModel to forwardAnthropicAPIKeyPassthrough |
backend/internal/service/antigravity_gateway_service_test.go |
Updated assertions: Model = original, UpstreamModel = mapped |
backend/internal/repository/usage_log_repo_request_type_test.go |
Added sqlmock.AnyArg() and sql.NullString{} for upstream_model in mock tests |
frontend/src/types/index.ts |
Adds upstream_model?: string | null to AdminUsageLog interface |
frontend/src/components/admin/usage/UsageTable.vue |
Shows upstream_model inline below the model name in the #cell-model slot |
frontend/src/views/admin/UsageView.vue |
Adds upstream_model as a separate column in the Excel export |
frontend/src/i18n/locales/en.ts |
Adds upstreamModel: 'Upstream Model' i18n key |
frontend/src/i18n/locales/zh.ts |
Adds upstreamModel: '上游模型' i18n key |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } else if result.MediaType == "prompt" { | ||
| cost = &CostBreakdown{} | ||
| } else if result.ImageCount > 0 { | ||
| // 图片生成计费 | ||
| // 图片生成计费:使用上游模型名(映射后的模型名)查找价格 |
There was a problem hiding this comment.
In RecordUsage (gateway_service.go), the billing for Sora video models (CalculateSoraVideoCost) uses result.Model (the user-requested model), while the billing for images and tokens was updated in this PR to use result.UpstreamModel when available. The Sora video billing path (which lives just above the changed else if result.ImageCount > 0 branch) remains unchanged, so if a Sora video model is subject to model mapping, billing would use the wrong pre-mapped model name. The result.Model argument to CalculateSoraVideoCost should also prefer result.UpstreamModel when set.
f4116f7 to
9ab2f99
Compare
Add upstream_model field to usage logs to distinguish between the user-requested model and the actual model used after mapping. This gives admins visibility into model routing behavior. - Add upstream_model nullable column via migration 068 - Regenerate Ent ORM code for the new field - Update ForwardResult to carry UpstreamModel separately from Model - Update test assertions for the new field layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WSv2 single-turn (forwardOpenAIWSV2) and multi-turn (ProxyResponsesWebSocketFromClient/sendAndRelay) paths were returning OpenAIForwardResult without UpstreamModel, causing upstream_model to always be NULL in usage_logs for WebSocket-based requests even when model mapping occurred. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9ab2f99 to
23df753
Compare
概要
usage_logs表新增upstream_model可空字段(迁移 068),记录模型映射后上游实际使用的模型,与用户请求的模型区分开ForwardResult中传递上游模型信息动机
当配置了模型映射(如用户请求
gpt-4o但实际映射到gpt-4o-mini)时,管理员无法看到上游实际使用了哪个模型。本 PR 通过在使用日志中同时记录请求模型和实际模型来提供这一可见性。变更内容
后端
UsageLogEnt schema 新增upstream_model可选字符串字段 + 迁移文件068_add_upstream_model.sqlForwardResult新增UpstreamModel字段;所有网关服务(Antigravity、OpenAI、OpenAI WS v2)均已填充CreateUsageLog在有值时写入upstream_modelUsageLogResponse包含upstream_model供 API 消费者使用前端
测试计划
upstream_model正确记录🤖 Generated with Claude Code