feat: WebSearch tri-state, account stats pricing fix, quota cache fix, usage tooltip
WebSearch tri-state switch: - Account-level web_search_emulation changed from bool to tri-state string: "default" (follow channel) / "enabled" / "disabled" - shouldEmulateWebSearch checks channel config when account is "default" - SQL migration converts old bool values - Frontend select replaces toggle in Edit/CreateAccountModal Account stats pricing: - resolveAccountStatsCost uses upstream model (post-mapping) for matching - Priority: custom rules → model pricing file (when toggle on) → default - Custom rules always configurable, independent of toggle - Account ID field changed to searchable selector filtered by platform - Description updated to reflect new behavior Quota notification cache fix: - CheckAccountQuotaAfterIncrement fetches real-time account from DB - Reconstructs pre-increment usage for accurate threshold crossing detection - New AccountQuotaReader interface (minimal: GetByID only) Usage tooltip: - Per-request/image billing shows per-request price instead of $0 token price - Token billing continues to show input/output price per million tokens
This commit is contained in:
@@ -2337,7 +2337,11 @@
|
||||
{{ t('admin.accounts.anthropic.webSearchEmulationDesc') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="webSearchEmulationEnabled" />
|
||||
<select v-model="webSearchEmulationMode" class="input w-32 text-sm">
|
||||
<option value="default">{{ t('admin.accounts.anthropic.webSearchDefault') }}</option>
|
||||
<option value="enabled">{{ t('admin.accounts.anthropic.webSearchEnabled') }}</option>
|
||||
<option value="disabled">{{ t('admin.accounts.anthropic.webSearchDisabled') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2846,7 +2850,6 @@ import ConfirmDialog from '@/components/common/ConfirmDialog.vue'
|
||||
import Select from '@/components/common/Select.vue'
|
||||
import Icon from '@/components/icons/Icon.vue'
|
||||
import ProxySelector from '@/components/common/ProxySelector.vue'
|
||||
import Toggle from '@/components/common/Toggle.vue'
|
||||
import GroupSelector from '@/components/common/GroupSelector.vue'
|
||||
import ModelWhitelistSelector from '@/components/account/ModelWhitelistSelector.vue'
|
||||
import QuotaLimitCard from '@/components/account/QuotaLimitCard.vue'
|
||||
@@ -2997,7 +3000,7 @@ const openaiOAuthResponsesWebSocketV2Mode = ref<OpenAIWSMode>(OPENAI_WS_MODE_OFF
|
||||
const openaiAPIKeyResponsesWebSocketV2Mode = ref<OpenAIWSMode>(OPENAI_WS_MODE_OFF)
|
||||
const codexCLIOnlyEnabled = ref(false)
|
||||
const anthropicPassthroughEnabled = ref(false)
|
||||
const webSearchEmulationEnabled = ref(false)
|
||||
const webSearchEmulationMode = ref('default')
|
||||
const webSearchGlobalEnabled = ref(false)
|
||||
|
||||
// Load web search global state once
|
||||
@@ -3331,7 +3334,7 @@ watch(
|
||||
}
|
||||
if (newPlatform !== 'anthropic') {
|
||||
anthropicPassthroughEnabled.value = false
|
||||
webSearchEmulationEnabled.value = false
|
||||
webSearchEmulationMode.value = 'default'
|
||||
}
|
||||
// Reset OAuth states
|
||||
oauth.resetState()
|
||||
@@ -3351,7 +3354,7 @@ watch(
|
||||
}
|
||||
if (platform !== 'anthropic' || category !== 'apikey') {
|
||||
anthropicPassthroughEnabled.value = false
|
||||
webSearchEmulationEnabled.value = false
|
||||
webSearchEmulationMode.value = 'default'
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -3716,7 +3719,7 @@ const resetForm = () => {
|
||||
openaiAPIKeyResponsesWebSocketV2Mode.value = OPENAI_WS_MODE_OFF
|
||||
codexCLIOnlyEnabled.value = false
|
||||
anthropicPassthroughEnabled.value = false
|
||||
webSearchEmulationEnabled.value = false
|
||||
webSearchEmulationMode.value = 'default'
|
||||
// Reset quota control state
|
||||
windowCostEnabled.value = false
|
||||
windowCostLimit.value = null
|
||||
@@ -3804,10 +3807,10 @@ const buildAnthropicExtra = (base?: Record<string, unknown>): Record<string, unk
|
||||
} else {
|
||||
delete extra.anthropic_passthrough
|
||||
}
|
||||
if (webSearchEmulationEnabled.value) {
|
||||
extra.web_search_emulation = true
|
||||
} else {
|
||||
if (webSearchEmulationMode.value === 'default') {
|
||||
delete extra.web_search_emulation
|
||||
} else {
|
||||
extra.web_search_emulation = webSearchEmulationMode.value
|
||||
}
|
||||
|
||||
return Object.keys(extra).length > 0 ? extra : undefined
|
||||
|
||||
Reference in New Issue
Block a user