feat: import formatted model prices from upstream - #799
Conversation
|
Warning Review limit reached
Next review available in: 39 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (14)
📝 WalkthroughWalkthrough新增 LiteLLM 外部模型价格获取接口。系统支持来源解析、价格标准化、前端差异预览和选择性应用。获取阶段不写入数据库,应用阶段使用现有创建和更新操作。 Changes外部价格同步
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Admin
participant ModelPricesPage
participant HttpTransport
participant AdminHandler
participant AdminService
participant LiteLLM
Admin->>ModelPricesPage: 选择来源并开始预览
ModelPricesPage->>HttpTransport: fetchExternalModelPrices(source)
HttpTransport->>AdminHandler: POST /model-prices/upstream/prices
AdminHandler->>AdminService: ListModelPricesFromExternalSource(source)
AdminService->>LiteLLM: 获取模型价格
LiteLLM-->>AdminService: 返回价格数据
AdminService-->>HttpTransport: 返回标准化价格结果
HttpTransport-->>ModelPricesPage: 展示创建和更新差异
Admin->>ModelPricesPage: 选择变更并应用
ModelPricesPage->>ModelPricesPage: 调用现有创建或更新操作
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
internal/handler/admin.go (1)
2533-2561: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win错误一律返回 500,客户端无法区分错误类型。
服务层会返回两类不同性质的错误:
unsupported model price sync source %q属于客户端输入错误,抓取或解码失败属于上游源故障。当前两者都映射为 500。建议对不支持的来源返回 400,对外部抓取失败返回 502。前端可据此显示不同提示。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/handler/admin.go` around lines 2533 - 2561, Update handleModelPricesSyncExternalPreview and handleModelPricesSyncExternalApply to distinguish service errors: return HTTP 400 for unsupported model price sync sources and HTTP 502 for external source fetch or decode failures. Reuse the existing error text or error classification mechanism, preserving the current JSON error response format and successful response paths.internal/service/admin.go (2)
2289-2337: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift同步写入没有事务保护。
循环内逐条调用
Create和Update。如果中途某次写入失败,函数直接返回错误,此前已写入的记录会保留。数据库处于部分同步状态,且返回给调用方的result被丢弃,管理员无法得知已应用了哪些变更。建议将应用阶段包裹在一个事务中,或在返回错误时同时返回已完成的变更统计。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/service/admin.go` around lines 2289 - 2337, Update syncModelPrices to protect the apply phase from partial writes by executing the loop’s Create and Update operations within a single repository transaction, committing only after all writes succeed and rolling back on any error. Preserve dry-run behavior and ensure result statistics are returned only for a successfully applied synchronization.
2341-2376: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win外部响应体没有大小上限,并且请求缺少 context。
json.NewDecoder(resp.Body)直接解码整个响应。如果配置的源 URL 返回超大响应,服务进程内存会被放大占用。建议用io.LimitReader限制读取长度。另外建议改用http.NewRequestWithContext,使调用方可以取消请求。🛠️ 建议的修复
- var raw map[string]liteLLMModelPrice - if err := json.NewDecoder(resp.Body).Decode(&raw); err != nil { + const maxModelPriceBodyBytes = 32 << 20 + var raw map[string]liteLLMModelPrice + if err := json.NewDecoder(io.LimitReader(resp.Body, maxModelPriceBodyBytes)).Decode(&raw); err != nil { return nil, source, sourceURL, fmt.Errorf("decode model price source %q: %w", source.Code, err) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/service/admin.go` around lines 2341 - 2376, Update fetchExternalModelPrices to accept and propagate a caller context, create the request with http.NewRequestWithContext instead of client.Get, and execute it through the HTTP client so cancellation is honored. Bound response decoding with io.LimitReader using an appropriate maximum response size while preserving the existing error handling and price conversion flow.tests/e2e/model_prices_test.go (1)
265-306: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value建议补充对
sample_过滤和total的断言,并使用安全的类型断言。两点建议:
- 测试数据包含
sample_spec,转换函数会过滤它。当前测试没有断言该条目被排除。建议断言total为 2,或断言结果中不存在sample_spec。这样可以覆盖过滤逻辑。preview["created"].(float64)使用非安全类型断言。如果字段缺失或类型变化,测试会 panic,失败信息不清晰。建议使用双返回值形式。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/e2e/model_prices_test.go` around lines 265 - 306, 补充同步预览/应用结果的断言:验证 total 为 2 或确认返回结果中不存在被过滤的 sample_spec 条目,以覆盖 sample_ 过滤逻辑;同时将 preview 和 result 中 created、updated 的直接类型断言改为带 ok 检查的安全断言,并在字段缺失或类型错误时输出明确失败信息。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/handler/admin.go`:
- Around line 2567-2577: Update decodeModelPriceSyncRequest to treat
json.Decoder.Decode returning io.EOF as an empty request body, returning req,
true instead of writing a 400 response; continue returning 400 for all other
decoding errors.
In `@web/src/hooks/queries/use-model-prices.ts`:
- Around line 106-108: Update the onSuccess handler to also invalidate cached
model price detail queries by invalidating modelPriceKeys.details() (or
modelPriceKeys.all), while preserving the existing list and pricing
invalidations.
In `@web/src/locales/en.json`:
- Line 1588: Update the syncExternalPreviewDesc translation in
web/src/locales/en.json at lines 1588-1588 and web/src/locales/zh.json at lines
1585-1585 to state that only database prices for modelId records absent from the
selected external source are preserved; clarify that matching upstream records
with changed prices may be updated.
In `@web/src/pages/model-prices/index.tsx`:
- Around line 202-204: Bind the apply operation to the reviewed external-price
snapshot instead of re-fetching by source. In
web/src/pages/model-prices/index.tsx:202-204, pass the snapshot identifier; add
a usable expiry, version, or content hash to the preview result in
web/src/lib/transport/types.ts:1674-1683; accept it in
web/src/lib/transport/interface.ts:370-371 and send it from
web/src/lib/transport/http-transport.ts:1342-1355. Update
handleModelPricesSyncExternalPreview and handleModelPricesSyncExternalApply to
create, receive, and validate the snapshot before applying it.
---
Nitpick comments:
In `@internal/handler/admin.go`:
- Around line 2533-2561: Update handleModelPricesSyncExternalPreview and
handleModelPricesSyncExternalApply to distinguish service errors: return HTTP
400 for unsupported model price sync sources and HTTP 502 for external source
fetch or decode failures. Reuse the existing error text or error classification
mechanism, preserving the current JSON error response format and successful
response paths.
In `@internal/service/admin.go`:
- Around line 2289-2337: Update syncModelPrices to protect the apply phase from
partial writes by executing the loop’s Create and Update operations within a
single repository transaction, committing only after all writes succeed and
rolling back on any error. Preserve dry-run behavior and ensure result
statistics are returned only for a successfully applied synchronization.
- Around line 2341-2376: Update fetchExternalModelPrices to accept and propagate
a caller context, create the request with http.NewRequestWithContext instead of
client.Get, and execute it through the HTTP client so cancellation is honored.
Bound response decoding with io.LimitReader using an appropriate maximum
response size while preserving the existing error handling and price conversion
flow.
In `@tests/e2e/model_prices_test.go`:
- Around line 265-306: 补充同步预览/应用结果的断言:验证 total 为 2 或确认返回结果中不存在被过滤的 sample_spec
条目,以覆盖 sample_ 过滤逻辑;同时将 preview 和 result 中 created、updated 的直接类型断言改为带 ok
检查的安全断言,并在字段缺失或类型错误时输出明确失败信息。
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f62e58e6-e58c-42ba-a69c-cbd41628e5ca
📒 Files selected for processing (12)
internal/handler/admin.gointernal/service/admin.gotests/e2e/model_prices_test.goweb/src/hooks/queries/index.tsweb/src/hooks/queries/use-model-prices.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/index.tsweb/src/lib/transport/interface.tsweb/src/lib/transport/types.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/model-prices/index.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
- GitHub Check: Backend Checks
- GitHub Check: Frontend Checks
- GitHub Check: playwright
- GitHub Check: e2e
🔇 Additional comments (11)
internal/service/admin.go (5)
7-14: LGTM!Also applies to: 31-52, 2004-2038
2378-2388: LGTM!
2429-2473: LGTM!
2320-2328: 🗄️ Data Integrity & Integration无需修改:
ModelPriceRepository.Update不会用传入的CreatedAt覆盖当前行;no-op 分支会回填当前行的CreatedAt,变更分支会插入新行并回填新行的CreatedAt。> Likely an incorrect or invalid review comment.
2390-2427: 🗄️ Data Integrity & Integration无需修改。
Context1MThreshold使用数值判定阈值,默认值为200_000;Has1MContext仅表示启用长上下文溢价,不是 1M 阈值。Context1MThreshold=200000与默认行为一致。internal/handler/admin.go (1)
2443-2450: LGTM!tests/e2e/model_prices_test.go (2)
6-6: LGTM!Also applies to: 215-263
308-335: LGTM!web/src/lib/transport/index.ts (1)
162-162: LGTM!web/src/hooks/queries/index.ts (1)
198-199: LGTM!web/src/pages/model-prices/index.tsx (1)
14-18: LGTM!Also applies to: 37-40, 72-73, 137-150, 191-200, 205-222, 238-261, 284-286, 588-662
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
web/src/pages/model-prices/index.tsx (2)
696-708: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value用
Set替代数组查找。第 705 行在渲染循环中对
selectedSyncChangeKeys做includes。选中集合可能包含全部变更,渲染成本为 O(n×m)。当前上限是 50 行,影响有限。可把选中状态改为
Set<string>,或在渲染前构造一次Set。♻️ 建议的修改
+ const selectedKeySet = new Set(selectedSyncChangeKeys);- checked={selectedSyncChangeKeys.includes(key)} + checked={selectedKeySet.has(key)}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/model-prices/index.tsx` around lines 696 - 708, 在同步预览渲染逻辑中优化 selectedSyncChangeKeys 的查找:在 map 循环前基于该数组构造一次 Set,并在 checkbox 的 checked 判断中使用 Set.has,避免每行调用 includes;保持现有选中状态与 handleToggleSyncChange 行为不变。
253-259: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win显式判断
update分支。第 256 行使用
else兜底。如果后端后续新增action取值(例如skip或delete),该分支会用change.after.id调用更新接口。对于没有id的变更,请求会带上undefined。请改为显式判断
change.action === 'update',并忽略未知取值。♻️ 建议的修改
if (change.action === 'create') { await createPrice.mutateAsync(input); created++; - } else { + } else if (change.action === 'update') { await updatePrice.mutateAsync({ id: change.after.id, data: input }); updated++; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/model-prices/index.tsx` around lines 253 - 259, 在处理变更的分支中,将 `else` 替换为显式判断 `change.action === 'update'`,仅对更新操作调用 `updatePrice.mutateAsync` 并递增 `updated`;对未知 action 直接忽略,保留 `create` 分支行为不变。internal/modelpricesync/source.go (1)
28-41: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win为 source 注册表添加并发保护。
如果服务启动后调用
Register,Line 41 的 map 写入可能与 Line 51 的读取并发执行。Go 会因并发 map 读写而 panic。使用sync.RWMutex保护sources的读取和写入,或明确限制Register只能在服务启动前调用。建议修改
import ( "fmt" "sort" "strings" + "sync" @@ -var sources = map[string]Source{ - DefaultSourceCode: NewLiteLLMSource(), -} +var ( + sources = map[string]Source{ + DefaultSourceCode: NewLiteLLMSource(), + } + sourcesMu sync.RWMutex +) @@ + sourcesMu.Lock() + defer sourcesMu.Unlock() sources[code] = source @@ + sourcesMu.RLock() source, ok := sources[code] + sourcesMu.RUnlock()Also applies to: 45-55
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/modelpricesync/source.go` around lines 28 - 41, 为 sources 注册表增加并发保护:定义并使用 sync.RWMutex,在 Register 中写入 sources 前加写锁并确保释放,同时在涉及 sources 读取的查找函数中使用读锁。保留现有 source 校验与规范化逻辑,确保注册和读取不会并发访问 map。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/modelpricesync/source_test.go`:
- Around line 27-30: 在 TestRegisterSupportsIndependentSourceImplementations 中注册
fakeSource 后增加 t.Cleanup,测试结束时恢复注册表中原有值或删除本次新增的 fake source,确保不会影响同包后续测试。
In `@web/src/pages/model-prices/index.tsx`:
- Around line 233-240: Update handleToggleAllSyncChanges to select only the
syncPreview.changes entries currently rendered in the dialog’s visible 50-item
list, rather than the full change set; keep clearing the selection when
unchecked and preserve the existing syncChangeKey generation.
- Around line 242-270: Update handleApplyExternalSync to catch errors from each
createPrice.mutateAsync or updatePrice.mutateAsync operation, continue
processing remaining selected changes, and track failed operations alongside
created and updated counts. Include failed in the syncExternalResult translation
parameters, and ensure the result text is set and the sync preview is closed
even when some changes fail.
---
Nitpick comments:
In `@internal/modelpricesync/source.go`:
- Around line 28-41: 为 sources 注册表增加并发保护:定义并使用 sync.RWMutex,在 Register 中写入
sources 前加写锁并确保释放,同时在涉及 sources 读取的查找函数中使用读锁。保留现有 source 校验与规范化逻辑,确保注册和读取不会并发访问
map。
In `@web/src/pages/model-prices/index.tsx`:
- Around line 696-708: 在同步预览渲染逻辑中优化 selectedSyncChangeKeys 的查找:在 map
循环前基于该数组构造一次 Set,并在 checkbox 的 checked 判断中使用 Set.has,避免每行调用 includes;保持现有选中状态与
handleToggleSyncChange 行为不变。
- Around line 253-259: 在处理变更的分支中,将 `else` 替换为显式判断 `change.action ===
'update'`,仅对更新操作调用 `updatePrice.mutateAsync` 并递增 `updated`;对未知 action 直接忽略,保留
`create` 分支行为不变。
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 411d209e-3e94-4460-9dfe-7bf1e7ba0e48
📒 Files selected for processing (14)
internal/handler/admin.gointernal/modelpricesync/litellm.gointernal/modelpricesync/source.gointernal/modelpricesync/source_test.gointernal/modelpricesync/sync.gointernal/service/admin.gotests/e2e/model_prices_test.goweb/src/hooks/queries/index.tsweb/src/hooks/queries/use-model-prices.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/interface.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/model-prices/index.tsx
💤 Files with no reviewable changes (5)
- web/src/hooks/queries/index.ts
- web/src/hooks/queries/use-model-prices.ts
- web/src/lib/transport/http-transport.ts
- internal/handler/admin.go
- web/src/lib/transport/interface.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- web/src/locales/en.json
- web/src/locales/zh.json
- tests/e2e/model_prices_test.go
- internal/service/admin.go
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: Backend Checks
- GitHub Check: playwright
- GitHub Check: e2e
🔇 Additional comments (1)
web/src/pages/model-prices/index.tsx (1)
109-130: LGTM!Also applies to: 159-172, 272-277, 293-316, 339-341
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/modelpricesync/sync.go (1)
62-64: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win不要修改
sourcePrices中的对象。Line 62 修改了调用方传入的
price。CompareRows只应生成比较结果,不应改变来源价格数据。请复制price后再设置数据库 ID,并将该副本写入After。建议修复
- price.ID = current.ID + after := cloneModelPrice(price) + after.ID = current.ID result.Updated++ - result.Changes = append(result.Changes, Change{Action: "update", Before: cloneModelPrice(current), After: cloneModelPrice(price)}) + result.Changes = append(result.Changes, Change{Action: "update", Before: cloneModelPrice(current), After: after})🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/modelpricesync/sync.go` around lines 62 - 64, 在 CompareRows 的更新分支中不要直接修改调用方传入的 price;先复制 price,向副本设置 current.ID,并将该副本用于 After 和后续数据库更新,同时保持 sourcePrices 中的原对象不变。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@internal/modelpricesync/sync.go`:
- Around line 62-64: 在 CompareRows 的更新分支中不要直接修改调用方传入的 price;先复制 price,向副本设置
current.ID,并将该副本用于 After 和后续数据库更新,同时保持 sourcePrices 中的原对象不变。
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 6526e350-8492-43a8-96b8-ea077d221194
📒 Files selected for processing (12)
internal/handler/admin.gointernal/modelpricesync/source.gointernal/modelpricesync/sync.gointernal/service/admin.gotests/e2e/model_prices_test.goweb/src/hooks/queries/index.tsweb/src/hooks/queries/use-model-prices.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/interface.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/model-prices/index.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- web/src/locales/en.json
- web/src/hooks/queries/use-model-prices.ts
- web/src/locales/zh.json
- web/src/pages/model-prices/index.tsx
- internal/modelpricesync/source.go
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: e2e
- GitHub Check: playwright
🔇 Additional comments (6)
internal/service/admin.go (1)
2201-2204: LGTM!internal/handler/admin.go (1)
2443-2445: LGTM!Also applies to: 2529-2540
tests/e2e/model_prices_test.go (1)
215-341: LGTM!web/src/lib/transport/interface.ts (1)
370-370: LGTM!web/src/lib/transport/http-transport.ts (1)
1342-1348: LGTM!web/src/hooks/queries/index.ts (1)
189-199: LGTM!
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/handler/admin.go`:
- Around line 2535-2538: 更新 ListModelPricesFromExternalSource 及其调用处理逻辑,为未知
source 返回可识别的专用错误,并在对应 handler 中将该错误映射为 http.StatusBadRequest;其他上游请求失败仍保持返回
http.StatusInternalServerError。
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 06c60c71-0a6e-45d9-898e-484cfc9cfe73
📒 Files selected for processing (16)
internal/handler/admin.gointernal/modelpriceupstream/litellm.gointernal/modelpriceupstream/prices.gointernal/modelpriceupstream/source.gointernal/modelpriceupstream/source_test.gointernal/service/admin.gotests/e2e/model_prices_test.goweb/src/hooks/queries/index.tsweb/src/hooks/queries/use-model-prices.tsweb/src/lib/transport/http-transport.tsweb/src/lib/transport/index.tsweb/src/lib/transport/interface.tsweb/src/lib/transport/types.tsweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/model-prices/index.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- web/src/locales/zh.json
- web/src/locales/en.json
- web/src/pages/model-prices/index.tsx
- web/src/lib/transport/index.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: playwright
- GitHub Check: Backend Checks
- GitHub Check: e2e
🔇 Additional comments (12)
internal/modelpriceupstream/source.go (1)
1-1: LGTM!Also applies to: 13-13, 32-53
internal/modelpriceupstream/litellm.go (1)
1-1: LGTM!internal/modelpriceupstream/prices.go (1)
1-20: LGTM!internal/modelpriceupstream/source_test.go (1)
1-1: LGTM!Also applies to: 52-63
internal/service/admin.go (1)
22-22: LGTM!Also applies to: 2201-2204
internal/handler/admin.go (1)
2443-2445: LGTM!tests/e2e/model_prices_test.go (1)
215-339: LGTM!web/src/lib/transport/types.ts (1)
588-589: LGTM!Also applies to: 677-678, 1665-1669
web/src/lib/transport/interface.ts (1)
106-106: LGTM!Also applies to: 370-370
web/src/lib/transport/http-transport.ts (1)
107-107: LGTM!Also applies to: 1342-1347
web/src/hooks/queries/use-model-prices.ts (1)
94-97: LGTM!web/src/hooks/queries/index.ts (1)
198-198: LGTM!
Summary
POST /model-prices/upstream/pricesto fetch formatted upstream model pricesdomain.ModelPrice; it does not diff, compare, sync, or applyinternal/handler/admin.go: route dispatch onlyinternal/service/admin.go: thin delegation onlyweb/src/pages/model-prices/index.tsx: imports/renders the upstream import component onlyinternal/modelpriceupstreamandinternal/handler/model_price_upstream.goupstream-prices-import.tsxandupstream-prices-dialog.tsxApply behavior
SyncModelPricesFromExternalSourcepathPOST /model-pricesPUT /model-prices/{id}Extensibility
sourcedefaults tolitellmmodelpriceupstream.Sourceand register withmodelpriceupstream.RegisterReview hardening
Test plan
go test ./internal/modelpriceupstream ./internal/service ./internal/handler ./tests/e2e -run 'ModelPrice|ModelPrices|Resolve|Convert|Register|Fetch|List'pnpm -C web typecheck