Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
680590d
feat(usage): user-configurable per-model cost overlay
harryzhou2000 Aug 4, 2026
70206f5
docs(gui): docstring coverage and review fixes for modelCosts
harryzhou2000 Aug 4, 2026
c17366f
docs(i18n): document Cost4 fields in localized pages, align ru termin…
harryzhou2000 Aug 4, 2026
5f486b0
fix(usage): review fixes — __proto__ modelCosts row and registry test…
harryzhou2000 Aug 5, 2026
00cfe0b
docs(usage): screenshot of the provider-configured price overlay in t…
harryzhou2000 Aug 5, 2026
cd956e8
fix(usage): sanitize cost-overlay rows on load and in the registry
harryzhou2000 Aug 5, 2026
05d5d97
fix(usage): try the exact provider name before collapsing user overlays
harryzhou2000 Aug 5, 2026
16eba40
fix(usage): redact modelCosts keys and bind the usage cache to overla…
harryzhou2000 Aug 5, 2026
e5dcd00
test(usage): clear the overlay registry in the cache-invalidation tes…
harryzhou2000 Aug 5, 2026
d141779
fix(usage): redact provider names in modelCosts management errors
harryzhou2000 Aug 5, 2026
2fef5ce
fix(usage): preserve modelCosts on provider overwrite and Alibaba mig…
harryzhou2000 Aug 6, 2026
95397f6
fix(usage): redact provider names in modelCosts schema errors
harryzhou2000 Aug 6, 2026
0795518
fix(usage): carry modelCosts through OpenAI tier migration; redact re…
harryzhou2000 Aug 6, 2026
39021e3
fix(usage): harden overlay redaction, canonical-openai validation, an…
harryzhou2000 Aug 6, 2026
3da9bb1
fix(usage): audit follow-up — empty overlay guard, DTO drop, legacy s…
harryzhou2000 Aug 6, 2026
fd9e3cd
docs(i18n): source-neutral matched-key label and Usage reprice scope
harryzhou2000 Aug 6, 2026
771a48b
fix(usage): bound overlay rates and refresh registry after OAuth reco…
harryzhou2000 Aug 7, 2026
27b3ae6
test(docs): audit follow-up for the rate bound
harryzhou2000 Aug 7, 2026
978fb23
fix(usage): preserve modelCosts across OAuth provider upserts
harryzhou2000 Aug 7, 2026
f0235e0
fix(oauth): preserve modelCosts across key-login provider replacement
harryzhou2000 Aug 7, 2026
fcfa689
fix(i18n): user-configured zh labels and source-agnostic unmatched-pr…
harryzhou2000 Aug 7, 2026
d198ac1
fix(oauth): push the merged key-login row to a running proxy
harryzhou2000 Aug 7, 2026
1e9a4fb
fix(providers): rewrite legacy openai-multi modelCosts keys during mi…
harryzhou2000 Aug 7, 2026
95775ee
fix(providers): stable precedence for legacy modelCosts key collisions
harryzhou2000 Aug 7, 2026
fcb38af
fix(providers): preserve prototype-named modelCosts keys during migra…
harryzhou2000 Aug 7, 2026
714167c
fix(config): reject extra fields inside modelCosts rows
harryzhou2000 Aug 7, 2026
6418a9d
test(config): assert modelCosts validation errors never echo credenti…
harryzhou2000 Aug 7, 2026
5688202
fix(cli/config): harden modelCosts display and preservation paths
harryzhou2000 Aug 7, 2026
6e3a199
fix(config): refresh overlay registry only after a successful changed…
harryzhou2000 Aug 7, 2026
17fc142
fix(usage): isolate pricing namespace for configured suffix-shaped pr…
harryzhou2000 Aug 8, 2026
a00eb37
docs(ja): state quota non-effect explicitly in modelCosts row
harryzhou2000 Aug 8, 2026
79b351f
docs(ja): clarify custom providers may target any OpenAI-compatible e…
harryzhou2000 Aug 8, 2026
1296f28
fix(usage): reconcile user cost overlays from disk across processes
harryzhou2000 Aug 9, 2026
5b06151
fix(usage): review follow-ups for live overlay reconciliation
harryzhou2000 Aug 9, 2026
b02a905
fix(usage): stop cost-overlay reconciler on normal server stop
harryzhou2000 Aug 9, 2026
7090b49
fix(usage): owner-scoped reconciler lifecycle within guarded startup
harryzhou2000 Aug 9, 2026
5f1a6bb
fix(usage): recompute/clear disk-only preservation on reconciler owne…
harryzhou2000 Aug 9, 2026
bec47b9
fix(usage): owner-scoped reconciler teardown and honor min poll interval
harryzhou2000 Aug 9, 2026
913fdcf
fix(usage): strict legacy overlay shape, one-shot preservation clear,…
harryzhou2000 Aug 9, 2026
ace6296
test(usage): reset overlay registry in key-login afterEach
harryzhou2000 Aug 9, 2026
7db360d
fix(usage): stamp usage-summary cache with the captured overlay version
harryzhou2000 Aug 9, 2026
84fc82d
fix(usage): widen config change stamp, strengthen cadence/overlay tests
harryzhou2000 Aug 9, 2026
9329797
fix(config): redact provider names in all validation paths; clarify t…
harryzhou2000 Aug 9, 2026
02f5113
fix(usage): owner-aware disk-only preservation across live owners
harryzhou2000 Aug 9, 2026
d3cf248
fix(usage): let live owners delete preserved providers
Wibias Aug 10, 2026
af7937a
fix(usage): address overlay review findings
Wibias Aug 10, 2026
70150d9
fix(ci): stop overlay reconciler leak and CLI spawn hangs on shard 4
Wibias Aug 10, 2026
5dfeb4b
fix(ci): isolate api-usage tests into dedicated Linux job
Wibias Aug 10, 2026
c840973
Merge branch 'dev' into feat/provider-cost-overlay
Wibias Aug 10, 2026
72b146b
test(usage): observe invalid reconcile via test counter
Wibias Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,11 @@ jobs:
#
# `bun test --shard=i/N` sorts test files by path and deals them round-robin,
# so the split is deterministic for the files that remain in this lane.
# Storage-policy API tests are deliberately excluded here and run in the
# dedicated `storage-policy` job below. Bun 1.3.14 can corrupt the Linux
# isolate/epoll state around that Worker-heavy harness; keeping it out of the
# general shards prevents one runtime failure from wedging ~150 unrelated
# files while preserving the same coverage in a fresh Bun process.
# Storage-policy API tests and api-usage are deliberately excluded here and run
# in dedicated jobs below. Bun 1.3.14 can corrupt the Linux isolate/epoll state
# around those Worker-heavy harnesses; keeping them out of the general shards
# prevents one runtime failure from wedging ~150 unrelated files while preserving
# the same coverage in fresh Bun processes.
#
# Only the suite lives here. Typecheck, lint, build, and the scans run once in
# `gates` rather than four times — they are fixed cost, and paying it per shard
Expand Down Expand Up @@ -294,7 +294,7 @@ jobs:
bun run build

- name: Test
run: bun test --isolate tests --path-ignore-patterns 'tests/api-storage-policy*.test.ts' --shard=${{ matrix.shard }}/4
run: bun test --isolate tests --path-ignore-patterns 'tests/api-storage-policy*.test.ts' --path-ignore-patterns 'tests/api-usage.test.ts' --shard=${{ matrix.shard }}/4

# Bun 1.3.14 has shown a Linux isolate/epoll race around the storage-policy
# harness. Keep the entire five-file family in one fresh process so a runtime
Expand Down Expand Up @@ -336,6 +336,40 @@ jobs:
./tests/api-storage-policy-run.test.ts \
./tests/api-storage-policy.test.ts

# Bun 1.3.14 has shown a Linux isolate wedge around startServer() plus the user
# cost overlay reconciler. Keep api-usage in one fresh process so a runtime
# failure is bounded to this job instead of poisoning a general test shard.
api-usage:
name: api usage
needs: changes
if: github.event_name != 'pull_request' || needs.changes.outputs.ci == 'true'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.3.14

- name: Install dependencies
run: |
bun install --frozen-lockfile
cd gui
bun install --frozen-lockfile

- name: Build GUI
run: |
cd gui
bun run build

- name: Test api usage API
run: bun test --isolate ./tests/api-usage.test.ts

# Everything that is not the suite: type safety, privacy, lint, build, smoke.
# One runner, once per push. Splitting these across the shards would repeat a
# fixed couple of minutes four times to save nothing.
Expand Down Expand Up @@ -667,7 +701,7 @@ jobs:
# direct dependencies only, so a failing `select-windows-runner` would
# otherwise reach this gate as nothing at all while its dependents report
# `skipped` — which the gate is required to read as a deliberate skip.
needs: [changes, select-windows-runner, test, storage-policy, gates, platform-macos, platform-windows, keyring-smoke, npm-global-smoke]
needs: [changes, select-windows-runner, test, storage-policy, api-usage, gates, platform-macos, platform-windows, keyring-smoke, npm-global-smoke]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ account を削除しても mapping は保持され、同じ id を再追加す
| `modelMaxInputTokens?` | `Record<string, number>` |カタログの自動圧縮ヒントに使用されるモデルごとの正の最大入力制限。 |
| `defaultMaxOutputTokens?` | `number` |クライアントが `max_output_tokens` を省略した場合の、プロバイダー全体の `openai-chat` フォールバック。 |
| `modelMaxOutputTokens?` | `Record<string, number>` |モデルごとの `openai-chat` フォールバック バジェットがプラスになります。正確な/パターン一致はプロバイダーのデフォルトを上回ります。 |
| `modelCosts?` | `Record<string, Cost4>` | モデルごとの表示価格(100万トークンあたりの米ドル)。そのプロバイダーの正確なアップストリーム モデル ID をキーにします(プロバイダー識別子やルーティングされた `provider/model` ラベルではありません)。値は `input`, `output`, `cacheRead`, `cacheWrite` の 4 フィールドです(例: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`)。組み込みカタログにないモデル ID も、任意の OpenAI 互換エンドポイントを対象とするカスタムプロバイダーや、ローカル・内部プロバイダーで有効です。ユーザー設定の価格は Logs の `~$` と Usage の見積もりで組み込みカタログより優先されます。過去のエントリも現在のオーバーレイで再計算されるため、価格を編集すると過去の合計が変わることがあります(フォールバック順: ユーザー設定 → jawcode カタログ → expected-price オーバーレイ → モデル別ベンダー価格)。全ゼロのエントリは次のソースにフォールバックします。各レートは 0 以上の有限数で、最大 1,000,000(100万トークンあたりの米ドル)です。範囲外の行は管理境界で拒否され、読み込み時に破棄されます。表示専用の見積もりであり、ルーティング・アカウント選択・クォータ・請求には影響しません。 |
| `headers?` | `Record<string, string>` |追加の上流ヘッダー。認証、Cookie、API キー ヘッダー、埋め込まれた改行、および無効な名前は拒否されます。 |
| `openRouterRouting?` | `OpenRouterProviderRouting` |デフォルトの OpenRouter `order`、`only`、および `allowFallbacks` 設定。 `openai-chat` を持つ正規 OpenRouter に対してのみ有効です。 |
| `modelOpenRouterRouting?` | `Record<string, OpenRouterProviderRouting>` |プロバイダー全体の OpenRouter 設定を置き換える正確なモデル ID のオーバーライド。 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정
| `modelMaxInputTokens?` | `Record<string, number>` | 카탈로그 자동 압축 힌트에 쓰는 양수 모델별 최대 입력 한도입니다. |
| `defaultMaxOutputTokens?` | `number` | 클라이언트가 `max_output_tokens`를 생략했을 때 쓰는 공급자 전반의 `openai-chat` 폴백입니다. |
| `modelMaxOutputTokens?` | `Record<string, number>` | 양수 모델별 `openai-chat` 폴백 예산입니다. 정확한 일치와 패턴 일치가 공급자 기본값보다 우선합니다. |
| `modelCosts?` | `Record<string, Cost4>` | 모델별 표시 가격(100만 토큰당 USD). 해당 공급자의 정확한 업스트림 모델 ID를 키로 사용하며(공급자 식별자나 라우팅된 `provider/model` 레이블이 아님) 값은 `input`, `output`, `cacheRead`, `cacheWrite` 네 필드입니다(예: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`). 커스텀 공급자는 `openai-chat` 어댑터로 임의의 OpenAI 호환 엔드포인트를 대상으로 할 수 있으며, 내장 카탈로그에 없는 로컬·내부 공급자 ID도 유효합니다. 사용자 구성 가격은 Logs `~$` 및 Usage 추정에서 내장 카탈로그보다 우선합니다. 기존 항목도 현재 오버레이로 다시 계산되므로 가격을 편집하면 과거 합계가 바뀔 수 있습니다(폴백 순서: 사용자 설정 → jawcode 카탈로그 → expected-price 오버레이 → 모델별 벤더 가격). 전부 0인 항목은 다음 소스로 폴백합니다. 각 요율은 0 이상의 유한한 숫자이며 최대 1,000,000(100만 토큰당 USD)입니다. 범위를 벗어난 행은 관리 경계에서 거부되고 로드 시 삭제됩니다. 표시 전용 추정이며 라우팅·계정 선택·할당량·청구에는 영향을 주지 않습니다. |
| `headers?` | `Record<string, string>` | 추가 상위 헤더입니다. Authorization, cookies, API-key 헤더, 내장 개행, 잘못된 이름은 허용하지 않습니다. |
| `openRouterRouting?` | `OpenRouterProviderRouting` | 기본 OpenRouter `order`, `only`, `allowFallbacks` 선호도입니다. 정식 OpenRouter와 `openai-chat`에서만 유효합니다. |
| `modelOpenRouterRouting?` | `Record<string, OpenRouterProviderRouting>` | 공급자 전반의 OpenRouter 선호도를 덮어쓰는 정확한 모델 id별 재정의입니다. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ differing backup and rewrites known legacy namespaced selected ids to bare ids.
| `modelMaxInputTokens?` | `Record<string, number>` | Positive per-model max input limits used for catalog auto-compaction hints. |
| `defaultMaxOutputTokens?` | `number` | Provider-wide `openai-chat` fallback when the client omits `max_output_tokens`. |
| `modelMaxOutputTokens?` | `Record<string, number>` | Positive per-model `openai-chat` fallback budgets; exact/pattern matches beat the provider default. |
| `modelCosts?` | `Record<string, Cost4>` | Per-model display prices (USD per 1M tokens), keyed by that provider's exact upstream model id — not a provider identifier or a routed `provider/model` label, e.g. `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Any model id is a valid key — custom providers may target any OpenAI-compatible endpoint through the `openai-chat` adapter, and local or internal provider ids work even when they are absent from the built-in catalogs. User-configured prices win over the built-in catalogs in the Logs `~$` and Usage estimates; historical entries are repriced from the current overlay, so editing a price can move past totals. The fallback order is user `modelCosts` → jawcode catalog → expected-price overlay → model-level vendor fallback, and an all-zero entry falls through to the next source in that sequence. Each rate must be a non-negative finite number at most 1,000,000 (USD per 1M tokens); out-of-range rows are rejected by the management boundary and dropped on load. Display-time estimation only: overlays never affect routing, account selection, quotas, or billing. |
| `headers?` | `Record<string, string>` | Extra upstream headers. Authorization, cookies, API-key headers, embedded newlines, and invalid names are rejected. |
| `openRouterRouting?` | `OpenRouterProviderRouting` | Default OpenRouter `order`, `only`, and `allowFallbacks` preferences; valid only for canonical OpenRouter with `openai-chat`. |
| `modelOpenRouterRouting?` | `Record<string, OpenRouterProviderRouting>` | Exact model-id overrides that replace the provider-wide OpenRouter preference. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ cross-route credential fallback не существует. Строки API GPT-
| `modelMaxInputTokens?` | `Record<string, number>` | Положительные лимиты max input по моделям, используемые для подсказок auto-compaction в каталоге. |
| `defaultMaxOutputTokens?` | `number` | Provider-wide fallback для `openai-chat`, когда клиент не передал `max_output_tokens`. |
| `modelMaxOutputTokens?` | `Record<string, number>` | Положительные fallback-budget'ы `openai-chat` по моделям; exact/pattern-match имеет приоритет над provider-default. |
| `modelCosts?` | `Record<string, Cost4>` | Отображаемые цены по моделям (USD за 1M токенов), ключ — точный upstream id модели этого провайдера (не идентификатор провайдера и не маршрутизируемая метка `provider/model`), значение — четыре поля: `input`, `output`, `cacheRead`, `cacheWrite` (пример: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`). Любой id допустим — кастомный провайдер может указывать на любой OpenAI-совместимый endpoint через адаптер `openai-chat`, а локальные и внутренние провайдеры работают даже без строки во встроенных каталогах. Пользовательские цены имеют приоритет над встроенными каталогами в оценках `~$` в Logs и Usage; исторические записи пересчитываются по текущему оверлею, поэтому изменение цены может сдвинуть прошлые суммы (порядок: пользователь → каталог jawcode → expected-price overlay → вендорская цена модели); полностью нулевая запись переходит к следующему источнику. Каждая ставка должна быть неотрицательным конечным числом не более 1 000 000 (USD за 1M токенов); строки вне диапазона отклоняются на управляющей границе и отбрасываются при загрузке. Только оценка для отображения: оверлеи не влияют на маршрутизацию, выбор аккаунта, квоты или биллинг. |
| `headers?` | `Record<string, string>` | Дополнительные upstream-header'ы. Заголовки авторизации, cookie, API-key-header'ы, встроенные переводы строк и невалидные имена отклоняются. |
| `openRouterRouting?` | `OpenRouterProviderRouting` | Предпочтения по умолчанию для OpenRouter (`order`, `only`, `allowFallbacks`); валидно только для канонического OpenRouter с `openai-chat`. |
| `modelOpenRouterRouting?` | `Record<string, OpenRouterProviderRouting>` | Exact override по model id, которые полностью заменяют provider-wide preference для OpenRouter. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ selector,而不是分配一个新名称。
| `modelMaxInputTokens?` | `Record<string, number>` | 正数型、按模型设置的最大输入限制,用于目录自动压缩提示。 |
| `defaultMaxOutputTokens?` | `number` | 当客户端省略 `max_output_tokens` 时,`openai-chat` 的提供者级回退值。 |
| `modelMaxOutputTokens?` | `Record<string, number>` | 正数型、按模型设置的 `openai-chat` 回退预算;精确/模式匹配优先于提供者默认值。 |
| `modelCosts?` | `Record<string, Cost4>` | 按模型设置的显示价格(每 100 万 token 的美元数),以该提供者的精确上游模型 ID 为键(不是提供者标识符或路由后的 `provider/model` 标签),值为四个字段:`input`、`output`、`cacheRead`、`cacheWrite`(示例:`{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`)。任何模型 ID 都是有效键——自定义提供者可以通过 `openai-chat` 适配器指向任意 OpenAI 兼容端点,即使不存在于内置目录中,本地 OpenAI 兼容和内部提供者的 ID 同样有效。用户配置的价格在 Logs 的 `~$` 和 Usage 估算中优先于内置目录;历史条目也会按当前覆盖项重新计价,因此修改价格可能改变过去的总额(回退顺序:用户配置 → jawcode 目录 → expected-price 覆盖 → 模型级厂商价格);全零条目会回退到该顺序中的下一个来源。每个费率必须是大于等于 0 的有限数字,且不超过 1,000,000(每 100 万 token 的美元数);超出范围的条目会在管理边界被拒绝,并在加载时被丢弃。仅用于显示的估算:覆盖项不影响路由、账户选择、配额或计费。 |
| `headers?` | `Record<string, string>` | 额外的上游请求头。会拒绝 Authorization、cookie、API key 头、嵌入换行符以及无效名称。 |
| `openRouterRouting?` | `OpenRouterProviderRouting` | 默认的 OpenRouter `order`、`only` 和 `allowFallbacks` 偏好;仅对使用 `openai-chat` 的规范 OpenRouter 有效。 |
| `modelOpenRouterRouting?` | `Record<string, OpenRouterProviderRouting>` | 精确模型 id 级别的覆盖项,会替换提供者级 OpenRouter 偏好。 |
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,13 +617,14 @@ export const de: Record<TKey, string> = {
"logs.detail.ttft": "TTFT",
"logs.detail.costTotal": "Listenpreis-Äquivalent",
"logs.detail.totalTokens": "Tokens gesamt",
"logs.detail.matchedKey": "Zugeordneter jawcode-Schlüssel",
"logs.detail.matchedKey": "Zugeordneter Preisschlüssel",
"logs.detail.priceSource": "Preisquelle",
"logs.detail.unavailableReason": "Grund der Nichtverfügbarkeit",
"logs.detail.copyRequestId": "Anfrage-ID kopieren",
"logs.detail.copied": "Kopiert",
"logs.detail.source.jawcode": "jawcode-Katalog",
"logs.detail.source.expected": "Expected-Preis-Overlay",
"logs.detail.source.user": "Anbieter-konfiguriertes Preis-Overlay",
"logs.detail.verification.verified": "Verifiziert",
"logs.detail.verification.derived": "Vom Basismodell abgeleitet",
"logs.detail.attempt.target": "Anbieter / Modell",
Expand All @@ -642,13 +643,14 @@ export const de: Record<TKey, string> = {
"logs.detail.reason.usage_unsupported": "Dieser Anbieter meldet keine Nutzung.",
"logs.detail.reason.output_missing": "Es wurden keine positiven Ausgabe-Tokens gemeldet.",
"logs.detail.reason.invalid_duration": "Die Anfragedauer ist ungültig.",
"logs.detail.reason.price_unmatched": "Kein passender jawcode-Preis gefunden.",
"logs.detail.reason.price_unmatched": "Kein passender Preis gefunden.",
"logs.detail.reason.invalid_cache_breakdown": "Cache-Token-Details widersprechen den Eingabe-Tokens.",
"logs.detail.reason.invalid_usage": "Die Nutzung enthält einen ungültigen Token-Wert.",
"logs.detail.reason.combo_attempt_unavailable": "Mindestens ein Combo-Versuch konnte nicht bepreist werden.",
"logs.detail.estimate.usage_estimated": "Die Anbieternutzung ist geschätzt.",
"logs.detail.estimate.cache_detail_missing": "Cache-Details fehlen; Eingabe ist als Obergrenze geschätzt.",
"logs.detail.estimate.expected_price_overlay": "Ein verifizierter Expected-Listenpreis wurde verwendet.",
"logs.detail.estimate.provider_cost_overlay": "Ein vom Anbieter konfiguriertes Preis-Overlay wurde verwendet.",
"logs.col.error": "Fehler",
"logs.col.upstreamReason": "Upstream-Grund",
"logs.col.duration": "Dauer",
Expand Down
Loading
Loading