mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 15:22:12 +03:00
Integrated into release/v3.7.4 (PR #1742)
This commit is contained in:
@@ -705,6 +705,10 @@ APP_LOG_TO_FILE=true
|
||||
|
||||
# ── CC-compatible provider (experimental) ──
|
||||
# Enable the Claude Code compatible provider endpoint.
|
||||
# This is only for third-party relays that accept Claude Code clients exclusively.
|
||||
# OmniRoute rewrites requests to pass those relays' Claude Code client validation.
|
||||
# If you only want to use Claude Code CLI, or you are not sure what these relays are,
|
||||
# keep this disabled and add a regular Anthropic-compatible provider instead.
|
||||
# Used by: src/shared/utils/featureFlags.ts
|
||||
# ENABLE_CC_COMPATIBLE_PROVIDER=false
|
||||
|
||||
|
||||
@@ -541,12 +541,17 @@ Automatic model pricing data synchronization from external sources.
|
||||
| `CLOUDFLARED_BIN` | auto-detect | `src/lib/cloudflaredTunnel.ts` | Custom path to `cloudflared` binary. |
|
||||
| `SEARCH_CACHE_TTL_MS` | `300000` (5 min) | `open-sse/services/searchCache.ts` | TTL for search API (Perplexity, Brave, etc.) response caching. |
|
||||
| `ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE` | `false` | `src/app/api/providers/route.ts` | Allow multiple simultaneous connections per OpenAI-compatible provider. |
|
||||
| `ENABLE_CC_COMPATIBLE_PROVIDER` | `false` | `src/shared/utils/featureFlags.ts` | Enable experimental Claude Code compatible provider endpoint. |
|
||||
| `ENABLE_CC_COMPATIBLE_PROVIDER` | `false` | `src/shared/utils/featureFlags.ts` | Reveal the experimental CC-compatible provider UI for Claude Code-only relays. |
|
||||
| `CLIPROXYAPI_HOST` | `127.0.0.1` | `open-sse/executors/cliproxyapi.ts` | CLIProxyAPI bridge host (legacy integration). |
|
||||
| `CLIPROXYAPI_PORT` | `5544` | `open-sse/executors/cliproxyapi.ts` | CLIProxyAPI bridge port. |
|
||||
| `CLIPROXYAPI_CONFIG_DIR` | `~/.cli-proxy-api` | `src/lib/versionManager/processManager.ts` | CLIProxyAPI config directory. |
|
||||
| `LOCAL_HOSTNAMES` | _(empty)_ | `open-sse/config/providerRegistry.ts` | Comma-separated additional hostnames treated as "local" (Docker service names, etc.). |
|
||||
|
||||
`ENABLE_CC_COMPATIBLE_PROVIDER` is only for third-party relays that accept Claude Code clients
|
||||
exclusively. OmniRoute rewrites requests so those relays accept them. If you only want to use
|
||||
Claude Code CLI, or you are not sure what these relays are, keep this disabled and add a regular
|
||||
Anthropic-compatible provider instead.
|
||||
|
||||
---
|
||||
|
||||
## 21. Proxy Health
|
||||
|
||||
@@ -567,10 +567,7 @@ function buildClaudeCodeCompatibleSystemBlocks({
|
||||
return preparedBlock;
|
||||
});
|
||||
|
||||
const hasDefaultSystemBlock = preparedCustomSystemBlocks.some(
|
||||
(block) =>
|
||||
block.type === "text" && block.text === CLAUDE_CODE_COMPATIBLE_DEFAULT_SYSTEM_BLOCKS[0].text
|
||||
);
|
||||
const hasDefaultSystemBlock = containsDefaultSystemSkeleton(preparedCustomSystemBlocks);
|
||||
|
||||
if (hasDefaultSystemBlock) return preparedCustomSystemBlocks;
|
||||
|
||||
@@ -580,6 +577,21 @@ function buildClaudeCodeCompatibleSystemBlocks({
|
||||
];
|
||||
}
|
||||
|
||||
function containsDefaultSystemSkeleton(blocks: Array<Record<string, unknown>>) {
|
||||
const skeleton = CLAUDE_CODE_COMPATIBLE_DEFAULT_SYSTEM_BLOCKS;
|
||||
if (skeleton.length === 0) return true;
|
||||
if (blocks.length < skeleton.length) return false;
|
||||
|
||||
return blocks.some((_, startIndex) =>
|
||||
skeleton.every((defaultBlock, offset) => {
|
||||
const candidateBlock = blocks[startIndex + offset];
|
||||
if (!candidateBlock) return false;
|
||||
|
||||
return Object.entries(defaultBlock).every(([key, value]) => candidateBlock[key] === value);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function convertClaudeCodeCompatibleMessage(message: MessageLike | null | undefined) {
|
||||
const rawRole = String(message?.role || "").toLowerCase();
|
||||
const role =
|
||||
|
||||
12
public/sw.js
12
public/sw.js
@@ -13,7 +13,7 @@ self.addEventListener("install", (event) => {
|
||||
caches
|
||||
.open(CACHE_NAME)
|
||||
.then((cache) => cache.addAll(APP_SHELL))
|
||||
.then(() => self.skipWaiting()),
|
||||
.then(() => self.skipWaiting())
|
||||
);
|
||||
});
|
||||
|
||||
@@ -21,8 +21,10 @@ self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) => Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))))
|
||||
.then(() => self.clients.claim()),
|
||||
.then((keys) =>
|
||||
Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))
|
||||
)
|
||||
.then(() => self.clients.claim())
|
||||
);
|
||||
});
|
||||
|
||||
@@ -34,7 +36,7 @@ self.addEventListener("fetch", (event) => {
|
||||
const requestUrl = new URL(event.request.url);
|
||||
const isSameOrigin = requestUrl.origin === self.location.origin;
|
||||
const isExcludedPath = EXCLUDED_PATH_PREFIXES.some((prefix) =>
|
||||
requestUrl.pathname.startsWith(prefix),
|
||||
requestUrl.pathname.startsWith(prefix)
|
||||
);
|
||||
const destination = event.request.destination;
|
||||
const isStaticAsset = ["style", "script", "image", "font"].includes(destination);
|
||||
@@ -70,6 +72,6 @@ self.addEventListener("fetch", (event) => {
|
||||
void caches.open(CACHE_NAME).then((cache) => cache.put(event.request, responseClone));
|
||||
}
|
||||
return networkResponse;
|
||||
})(),
|
||||
})()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2730,7 +2730,7 @@ export default function ProviderDetailPage() {
|
||||
|
||||
{isCompatible && providerNode && (
|
||||
<Card>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold">
|
||||
{isCcCompatible
|
||||
@@ -2743,7 +2743,7 @@ export default function ProviderDetailPage() {
|
||||
{getApiLabel()} · {(providerNode.baseUrl || "").replace(/\/$/, "")}/{getApiPath()}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Button size="sm" icon="add" onClick={() => setShowAddApiKeyModal(true)}>
|
||||
{t("add")}
|
||||
</Button>
|
||||
@@ -2788,6 +2788,16 @@ export default function ProviderDetailPage() {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{isCcCompatible && (
|
||||
<div className="mb-4 rounded-lg border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-sm text-text-muted">
|
||||
<div className="flex items-start gap-2">
|
||||
<span className="material-symbols-outlined mt-0.5 text-[18px] text-amber-500">
|
||||
warning
|
||||
</span>
|
||||
<p>{t("ccCompatibleValidationHint")}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
)}
|
||||
|
||||
@@ -5869,6 +5879,16 @@ function AddApiKeyModal({
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
{isCcCompatible && (
|
||||
<div className="rounded-lg border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-sm text-text-muted">
|
||||
<div className="flex items-start gap-2">
|
||||
<span className="material-symbols-outlined mt-0.5 text-[18px] text-amber-500">
|
||||
warning
|
||||
</span>
|
||||
<p>{t("ccCompatibleValidationHint")}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Input
|
||||
label={t("nameLabel")}
|
||||
value={formData.name}
|
||||
@@ -5929,17 +5949,15 @@ function AddApiKeyModal({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{isCompatible && (
|
||||
{isCompatible && !isCcCompatible && (
|
||||
<p className="text-xs text-text-muted">
|
||||
{isCcCompatible
|
||||
? t("ccCompatibleValidationHint")
|
||||
: isAnthropic
|
||||
? t("validationChecksAnthropicCompatible", {
|
||||
provider: providerName || t("anthropicCompatibleName"),
|
||||
})
|
||||
: t("validationChecksOpenAiCompatible", {
|
||||
provider: providerName || t("openaiCompatibleName"),
|
||||
})}
|
||||
{isAnthropic
|
||||
? t("validationChecksAnthropicCompatible", {
|
||||
provider: providerName || t("anthropicCompatibleName"),
|
||||
})
|
||||
: t("validationChecksOpenAiCompatible", {
|
||||
provider: providerName || t("openaiCompatibleName"),
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
<button
|
||||
@@ -6968,6 +6986,16 @@ function EditCompatibleNodeModal({
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
{isCcCompatible && (
|
||||
<div className="rounded-lg border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-sm text-text-muted">
|
||||
<div className="flex items-start gap-2">
|
||||
<span className="material-symbols-outlined mt-0.5 text-[18px] text-amber-500">
|
||||
warning
|
||||
</span>
|
||||
<p>{t("ccCompatibleValidationHint")}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Input
|
||||
label={t("nameLabel")}
|
||||
value={formData.name}
|
||||
|
||||
@@ -1044,7 +1044,6 @@ export default function ProvidersPage() {
|
||||
<AddCcCompatibleModal
|
||||
isOpen={showAddCcCompatibleModal}
|
||||
addLabel={addCcCompatibleLabel}
|
||||
compatibleLabel={ccCompatibleLabel}
|
||||
onClose={() => setShowAddCcCompatibleModal(false)}
|
||||
onCreated={(node) => {
|
||||
setProviderNodes((prev) => [...prev, node]);
|
||||
@@ -1752,12 +1751,12 @@ AddAnthropicCompatibleModal.propTypes = {
|
||||
onCreated: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCreated }) {
|
||||
function AddCcCompatibleModal({ isOpen, addLabel, onClose, onCreated }) {
|
||||
const t = useTranslations("providers");
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
prefix: "",
|
||||
baseUrl: "https://api.anthropic.com",
|
||||
baseUrl: "",
|
||||
chatPath: CC_COMPATIBLE_DEFAULT_CHAT_PATH,
|
||||
});
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
@@ -1765,6 +1764,10 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
const [validating, setValidating] = useState(false);
|
||||
const [validationResult, setValidationResult] = useState<"success" | "failed" | null>(null);
|
||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||
const hasRequiredFields = Boolean(
|
||||
formData.name.trim() && formData.prefix.trim() && formData.baseUrl.trim()
|
||||
);
|
||||
const canValidate = Boolean(checkKey.trim() && formData.baseUrl.trim());
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
@@ -1774,7 +1777,7 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
}, [isOpen]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formData.name.trim() || !formData.prefix.trim() || !formData.baseUrl.trim()) return;
|
||||
if (!hasRequiredFields) return;
|
||||
setSubmitting(true);
|
||||
try {
|
||||
const res = await fetch("/api/provider-nodes", {
|
||||
@@ -1795,7 +1798,7 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
setFormData({
|
||||
name: "",
|
||||
prefix: "",
|
||||
baseUrl: "https://api.anthropic.com",
|
||||
baseUrl: "",
|
||||
chatPath: CC_COMPATIBLE_DEFAULT_CHAT_PATH,
|
||||
});
|
||||
setCheckKey("");
|
||||
@@ -1835,26 +1838,34 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
return (
|
||||
<Modal isOpen={isOpen} title={addLabel} onClose={onClose}>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="rounded-lg border border-amber-500/25 bg-amber-500/10 px-3 py-2 text-sm text-text-muted">
|
||||
<div className="flex items-start gap-2">
|
||||
<span className="material-symbols-outlined mt-0.5 text-[18px] text-amber-500">
|
||||
warning
|
||||
</span>
|
||||
<p>{t("ccCompatibleValidationHint")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
label={t("nameLabel")}
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
placeholder={t("compatibleProdPlaceholder", { type: compatibleLabel })}
|
||||
hint={t("nameHint")}
|
||||
placeholder={t("ccCompatibleNamePlaceholder")}
|
||||
hint={t("ccCompatibleNameHint")}
|
||||
/>
|
||||
<Input
|
||||
label={t("prefixLabel")}
|
||||
value={formData.prefix}
|
||||
onChange={(e) => setFormData({ ...formData, prefix: e.target.value })}
|
||||
placeholder="cc-prod"
|
||||
hint={t("prefixHint")}
|
||||
placeholder={t("ccCompatiblePrefixPlaceholder")}
|
||||
hint={t("ccCompatiblePrefixHint")}
|
||||
/>
|
||||
<Input
|
||||
label={t("baseUrlLabel")}
|
||||
value={formData.baseUrl}
|
||||
onChange={(e) => setFormData({ ...formData, baseUrl: e.target.value })}
|
||||
placeholder="https://api.anthropic.com"
|
||||
hint={t("compatibleBaseUrlHint", { type: compatibleLabel })}
|
||||
placeholder={t("ccCompatibleBaseUrlPlaceholder")}
|
||||
hint={t("ccCompatibleBaseUrlHint")}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1881,7 +1892,7 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
value={formData.chatPath}
|
||||
onChange={(e) => setFormData({ ...formData, chatPath: e.target.value })}
|
||||
placeholder={CC_COMPATIBLE_DEFAULT_CHAT_PATH}
|
||||
hint={t("chatPathHint")}
|
||||
hint={t("ccCompatibleChatPathHint")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -1896,7 +1907,7 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
<div className="pt-6">
|
||||
<Button
|
||||
onClick={handleValidate}
|
||||
disabled={!checkKey || validating || !formData.baseUrl.trim()}
|
||||
disabled={!canValidate || validating}
|
||||
variant="secondary"
|
||||
>
|
||||
{validating ? t("checking") : t("check")}
|
||||
@@ -1909,16 +1920,7 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
</Badge>
|
||||
)}
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
fullWidth
|
||||
disabled={
|
||||
!formData.name.trim() ||
|
||||
!formData.prefix.trim() ||
|
||||
!formData.baseUrl.trim() ||
|
||||
submitting
|
||||
}
|
||||
>
|
||||
<Button onClick={handleSubmit} fullWidth disabled={!hasRequiredFields || submitting}>
|
||||
{submitting ? t("creating") : t("add")}
|
||||
</Button>
|
||||
<Button onClick={onClose} variant="ghost" fullWidth>
|
||||
@@ -1933,7 +1935,6 @@ function AddCcCompatibleModal({ isOpen, addLabel, compatibleLabel, onClose, onCr
|
||||
AddCcCompatibleModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
addLabel: PropTypes.string.isRequired,
|
||||
compatibleLabel: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onCreated: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
"editCombo": "Edit Combo",
|
||||
"testResults": "Test Results",
|
||||
"searchQuery": "Search Query",
|
||||
"addCcCompatible": "Add Cc Compatible",
|
||||
"addCcCompatible": "Add CC Compatible",
|
||||
"duplicate": "Duplicate",
|
||||
"createCombo": "Create Combo",
|
||||
"searchTypeWeb": "Search Type Web",
|
||||
@@ -344,7 +344,7 @@
|
||||
"signatureDefaults": "Signature Defaults",
|
||||
"errorCreating": "Error Creating",
|
||||
"timeRangeYear": "Time Range Year",
|
||||
"compatibleLabel": "Compatible Label",
|
||||
"compatibleLabel": "Compatible",
|
||||
"cloudDisabledSuccess": "Cloud Disabled Success",
|
||||
"deleteConfirm": "Delete Confirm",
|
||||
"check": "Check",
|
||||
@@ -511,7 +511,7 @@
|
||||
"comboUpdated": "Combo Updated",
|
||||
"weighted": "Weighted",
|
||||
"providers": "Providers",
|
||||
"ccCompatibleLabel": "Cc Compatible Label",
|
||||
"ccCompatibleLabel": "CC Compatible",
|
||||
"noFallbackChainsDesc": "No Fallback Chains Desc",
|
||||
"yesImport": "Yes Import",
|
||||
"lockoutsAutoRefreshHint": "Lockouts Auto Refresh Hint",
|
||||
@@ -2705,7 +2705,7 @@
|
||||
"accountIdLabel": "Account Id Label",
|
||||
"accountIdPlaceholder": "Account Id Placeholder",
|
||||
"addAnotherApiKey": "Add Another Api Key",
|
||||
"addCcCompatible": "Add Cc Compatible",
|
||||
"addCcCompatible": "Add CC Compatible",
|
||||
"aggregatorsGateways": "Aggregators Gateways",
|
||||
"apiFormatLabel": "Api Format Label",
|
||||
"apiKeyOptionalHint": "Api Key Optional Hint",
|
||||
@@ -2722,27 +2722,27 @@
|
||||
"bailianBaseUrlHint": "Bailian Base Url Hint",
|
||||
"blackboxWebCookieHint": "Blackbox Web Cookie Hint",
|
||||
"blackboxWebCookiePlaceholder": "Blackbox Web Cookie Placeholder",
|
||||
"blockClaudeExtraUsageDescription": "Block Claude Extra Usage Description",
|
||||
"blockClaudeExtraUsageLabel": "Block Claude Extra Usage Label",
|
||||
"ccCompatibleBaseUrlHint": "Cc Compatible Base Url Hint",
|
||||
"ccCompatibleBaseUrlPlaceholder": "Cc Compatible Base Url Placeholder",
|
||||
"ccCompatibleChatPathHint": "Cc Compatible Chat Path Hint",
|
||||
"ccCompatibleContext1mDescription": "Cc Compatible Context1M Description",
|
||||
"ccCompatibleContext1mLabel": "Cc Compatible Context1M Label",
|
||||
"ccCompatibleDetailsTitle": "Cc Compatible Details Title",
|
||||
"ccCompatibleLabel": "Cc Compatible Label",
|
||||
"ccCompatibleModelsDescription": "Cc Compatible Models Description",
|
||||
"ccCompatibleNameHint": "Cc Compatible Name Hint",
|
||||
"ccCompatibleNamePlaceholder": "Cc Compatible Name Placeholder",
|
||||
"ccCompatiblePrefixHint": "Cc Compatible Prefix Hint",
|
||||
"ccCompatiblePrefixPlaceholder": "Cc Compatible Prefix Placeholder",
|
||||
"ccCompatibleValidationHint": "Cc Compatible Validation Hint",
|
||||
"claudeExtraUsageShort": "Claude Extra Usage Short",
|
||||
"claudeExtraUsageToggleTitle": "Claude Extra Usage Toggle Title",
|
||||
"codex5hToggleTitle": "Codex5H Toggle Title",
|
||||
"blockClaudeExtraUsageDescription": "Hide extra Claude usage rows reported by some providers when they duplicate primary token accounting.",
|
||||
"blockClaudeExtraUsageLabel": "Block duplicate Claude usage rows",
|
||||
"ccCompatibleBaseUrlHint": "Base URL for a Claude Code-only relay. Do not include /messages.",
|
||||
"ccCompatibleBaseUrlPlaceholder": "https://relay.example.com/v1",
|
||||
"ccCompatibleChatPathHint": "Defaults to Claude Code's strict Messages API path. Change only if your relay documents a different path.",
|
||||
"ccCompatibleContext1mDescription": "Adds the context-1m beta header when the selected Claude model supports it.",
|
||||
"ccCompatibleContext1mLabel": "Enable 1M context beta",
|
||||
"ccCompatibleDetailsTitle": "CC-compatible relay details",
|
||||
"ccCompatibleLabel": "CC Compatible",
|
||||
"ccCompatibleModelsDescription": "CC-compatible relays do not expose model listing. Add the Claude model IDs your relay accepts.",
|
||||
"ccCompatibleNameHint": "Display name for this Claude Code-only relay.",
|
||||
"ccCompatibleNamePlaceholder": "CC Relay Production",
|
||||
"ccCompatiblePrefixHint": "Used in model aliases such as prefix/model-id.",
|
||||
"ccCompatiblePrefixPlaceholder": "cc",
|
||||
"ccCompatibleValidationHint": "Use this provider only for relays that serve Claude Code clients exclusively. OmniRoute rewrites any incoming request into the Claude Code-compatible wire format so those relays accept it. If you only want to use Claude Code CLI, or you are not sure what this relay type means, use a regular Anthropic-compatible provider instead.",
|
||||
"claudeExtraUsageShort": "Extra usage",
|
||||
"claudeExtraUsageToggleTitle": "Block Claude extra usage accounting for this connection",
|
||||
"codex5hToggleTitle": "Track Codex 5-hour quota for this connection",
|
||||
"codexFastServiceTierDescription": "Use the priority service tier for Codex requests when available.",
|
||||
"codexFastServiceTierLabel": "Codex fast service tier",
|
||||
"codexWeeklyToggleTitle": "Codex Weekly Toggle Title",
|
||||
"codexWeeklyToggleTitle": "Track Codex weekly quota for this connection",
|
||||
"compatUpstreamHeaderNamePlaceholder": "Compat Upstream Header Name Placeholder",
|
||||
"compatUpstreamHeaderValuePlaceholder": "Compat Upstream Header Value Placeholder",
|
||||
"compatible": "Compatible",
|
||||
@@ -2750,8 +2750,8 @@
|
||||
"consoleApiKeyOracleHint": "Console Api Key Oracle Hint",
|
||||
"consoleApiKeyOracleLabel": "Console Api Key Oracle Label",
|
||||
"consoleApiKeyOraclePlaceholder": "Console Api Key Oracle Placeholder",
|
||||
"cpaModeDisabledTitle": "Cpa Mode Disabled Title",
|
||||
"cpaModeEnabledTitle": "Cpa Mode Enabled Title",
|
||||
"cpaModeDisabledTitle": "CLIProxyAPI compatibility mode is disabled",
|
||||
"cpaModeEnabledTitle": "CLIProxyAPI compatibility mode is enabled",
|
||||
"customUserAgentHint": "Custom User Agent Hint",
|
||||
"customUserAgentLabel": "Custom User Agent Label",
|
||||
"databricksBaseUrlHint": "Databricks Base Url Hint",
|
||||
@@ -2812,18 +2812,18 @@
|
||||
"sessionCookieLabel": "Session Cookie Label",
|
||||
"showEmail": "Show Email",
|
||||
"snowflakeBaseUrlHint": "Snowflake Base Url Hint",
|
||||
"supportedEndpointAudio": "Supported Endpoint Audio",
|
||||
"supportedEndpointChat": "Supported Endpoint Chat",
|
||||
"supportedEndpointEmbeddings": "Supported Endpoint Embeddings",
|
||||
"supportedEndpointImages": "Supported Endpoint Images",
|
||||
"supportedEndpointsLabel": "Supported Endpoints Label",
|
||||
"supportedEndpointAudio": "Audio",
|
||||
"supportedEndpointChat": "Chat",
|
||||
"supportedEndpointEmbeddings": "Embeddings",
|
||||
"supportedEndpointImages": "Images",
|
||||
"supportedEndpointsLabel": "Supported endpoints",
|
||||
"tagGroupHint": "Tag Group Hint",
|
||||
"tagGroupLabel": "Tag Group Label",
|
||||
"tagGroupPlaceholder": "Tag Group Placeholder",
|
||||
"testModel": "Test Model",
|
||||
"testingModel": "Testing Model",
|
||||
"toggleOffShort": "Toggle Off Short",
|
||||
"toggleOnShort": "Toggle On Short",
|
||||
"toggleOffShort": "Off",
|
||||
"toggleOnShort": "On",
|
||||
"tokenExpiredBadge": "Token Expired Badge",
|
||||
"tokenExpiredTitle": "Token Expired Title",
|
||||
"tokenExpiresSoonTitle": "Token Expires Soon Title",
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
"editCombo": "Edit Combo",
|
||||
"testResults": "Test Results",
|
||||
"searchQuery": "Search Query",
|
||||
"addCcCompatible": "Add Cc Compatible",
|
||||
"addCcCompatible": "添加 CC 兼容",
|
||||
"duplicate": "Duplicate",
|
||||
"createCombo": "Create Combo",
|
||||
"searchTypeWeb": "Search Type Web",
|
||||
@@ -344,7 +344,7 @@
|
||||
"signatureDefaults": "Signature Defaults",
|
||||
"errorCreating": "Error Creating",
|
||||
"timeRangeYear": "Time Range Year",
|
||||
"compatibleLabel": "Compatible Label",
|
||||
"compatibleLabel": "兼容",
|
||||
"cloudDisabledSuccess": "Cloud Disabled Success",
|
||||
"deleteConfirm": "Delete Confirm",
|
||||
"check": "Check",
|
||||
@@ -511,7 +511,7 @@
|
||||
"comboUpdated": "Combo Updated",
|
||||
"weighted": "Weighted",
|
||||
"providers": "Providers",
|
||||
"ccCompatibleLabel": "Cc Compatible Label",
|
||||
"ccCompatibleLabel": "CC 兼容",
|
||||
"noFallbackChainsDesc": "No Fallback Chains Desc",
|
||||
"yesImport": "Yes Import",
|
||||
"lockoutsAutoRefreshHint": "Lockouts Auto Refresh Hint",
|
||||
@@ -2642,7 +2642,7 @@
|
||||
"accountIdLabel": "Account Id Label",
|
||||
"accountIdPlaceholder": "Account Id Placeholder",
|
||||
"addAnotherApiKey": "Add Another Api Key",
|
||||
"addCcCompatible": "Add Cc Compatible",
|
||||
"addCcCompatible": "添加 CC 兼容",
|
||||
"aggregatorsGateways": "Aggregators Gateways",
|
||||
"apiFormatLabel": "Api Format Label",
|
||||
"apiKeyOptionalHint": "Api Key Optional Hint",
|
||||
@@ -2659,27 +2659,27 @@
|
||||
"bailianBaseUrlHint": "Bailian Base Url Hint",
|
||||
"blackboxWebCookieHint": "Blackbox Web Cookie Hint",
|
||||
"blackboxWebCookiePlaceholder": "Blackbox Web Cookie Placeholder",
|
||||
"blockClaudeExtraUsageDescription": "Block Claude Extra Usage Description",
|
||||
"blockClaudeExtraUsageLabel": "Block Claude Extra Usage Label",
|
||||
"ccCompatibleBaseUrlHint": "Cc Compatible Base Url Hint",
|
||||
"ccCompatibleBaseUrlPlaceholder": "Cc Compatible Base Url Placeholder",
|
||||
"ccCompatibleChatPathHint": "Cc Compatible Chat Path Hint",
|
||||
"ccCompatibleContext1mDescription": "Cc Compatible Context1M Description",
|
||||
"ccCompatibleContext1mLabel": "Cc Compatible Context1M Label",
|
||||
"ccCompatibleDetailsTitle": "Cc Compatible Details Title",
|
||||
"ccCompatibleLabel": "Cc Compatible Label",
|
||||
"ccCompatibleModelsDescription": "Cc Compatible Models Description",
|
||||
"ccCompatibleNameHint": "Cc Compatible Name Hint",
|
||||
"ccCompatibleNamePlaceholder": "Cc Compatible Name Placeholder",
|
||||
"ccCompatiblePrefixHint": "Cc Compatible Prefix Hint",
|
||||
"ccCompatiblePrefixPlaceholder": "Cc Compatible Prefix Placeholder",
|
||||
"ccCompatibleValidationHint": "Cc Compatible Validation Hint",
|
||||
"claudeExtraUsageShort": "Claude Extra Usage Short",
|
||||
"claudeExtraUsageToggleTitle": "Claude Extra Usage Toggle Title",
|
||||
"codex5hToggleTitle": "Codex5H Toggle Title",
|
||||
"blockClaudeExtraUsageDescription": "隐藏部分 Provider 返回的重复 Claude 额外用量记录,避免和主 token 统计重复。",
|
||||
"blockClaudeExtraUsageLabel": "屏蔽重复 Claude 用量",
|
||||
"ccCompatibleBaseUrlHint": "Claude Code 专用中转站的 Base URL,不要包含 /messages。",
|
||||
"ccCompatibleBaseUrlPlaceholder": "https://relay.example.com/v1",
|
||||
"ccCompatibleChatPathHint": "默认使用 Claude Code 严格的 Messages API 路径。仅在中转站文档要求时修改。",
|
||||
"ccCompatibleContext1mDescription": "当所选 Claude 模型支持时,添加 context-1m beta header。",
|
||||
"ccCompatibleContext1mLabel": "启用 1M context beta",
|
||||
"ccCompatibleDetailsTitle": "CC 兼容中转站详情",
|
||||
"ccCompatibleLabel": "CC 兼容",
|
||||
"ccCompatibleModelsDescription": "CC 兼容中转站不提供模型列表。请添加该中转站接受的 Claude 模型 ID。",
|
||||
"ccCompatibleNameHint": "这个 Claude Code 专用中转站的显示名称。",
|
||||
"ccCompatibleNamePlaceholder": "CC 中转站生产环境",
|
||||
"ccCompatiblePrefixHint": "用于 prefix/model-id 这类模型别名。",
|
||||
"ccCompatiblePrefixPlaceholder": "cc",
|
||||
"ccCompatibleValidationHint": "这个 Provider 只适用于仅向 Claude Code 客户端提供服务的中转站。OmniRoute 会把任何进入的请求改写为 Claude Code 兼容的传输格式,以通过这些中转站的验证。如果你只是想使用 Claude Code CLI,或者不清楚这类中转站是什么,请使用普通 Anthropic-compatible Provider。",
|
||||
"claudeExtraUsageShort": "额外用量",
|
||||
"claudeExtraUsageToggleTitle": "为此连接屏蔽 Claude 额外用量统计",
|
||||
"codex5hToggleTitle": "为此连接跟踪 Codex 5 小时配额",
|
||||
"codexFastServiceTierDescription": "可用时为 Codex 请求使用 priority 服务层。",
|
||||
"codexFastServiceTierLabel": "Codex 快速服务层",
|
||||
"codexWeeklyToggleTitle": "Codex Weekly Toggle Title",
|
||||
"codexWeeklyToggleTitle": "为此连接跟踪 Codex 周配额",
|
||||
"compatUpstreamHeaderNamePlaceholder": "Compat Upstream Header Name Placeholder",
|
||||
"compatUpstreamHeaderValuePlaceholder": "Compat Upstream Header Value Placeholder",
|
||||
"compatible": "Compatible",
|
||||
@@ -2687,8 +2687,8 @@
|
||||
"consoleApiKeyOracleHint": "Console Api Key Oracle Hint",
|
||||
"consoleApiKeyOracleLabel": "Console Api Key Oracle Label",
|
||||
"consoleApiKeyOraclePlaceholder": "Console Api Key Oracle Placeholder",
|
||||
"cpaModeDisabledTitle": "Cpa Mode Disabled Title",
|
||||
"cpaModeEnabledTitle": "Cpa Mode Enabled Title",
|
||||
"cpaModeDisabledTitle": "CLIProxyAPI 兼容模式已关闭",
|
||||
"cpaModeEnabledTitle": "CLIProxyAPI 兼容模式已开启",
|
||||
"customUserAgentHint": "Custom User Agent Hint",
|
||||
"customUserAgentLabel": "Custom User Agent Label",
|
||||
"databricksBaseUrlHint": "Databricks Base Url Hint",
|
||||
@@ -2749,18 +2749,18 @@
|
||||
"sessionCookieLabel": "Session Cookie Label",
|
||||
"showEmail": "Show Email",
|
||||
"snowflakeBaseUrlHint": "Snowflake Base Url Hint",
|
||||
"supportedEndpointAudio": "Supported Endpoint Audio",
|
||||
"supportedEndpointChat": "Supported Endpoint Chat",
|
||||
"supportedEndpointEmbeddings": "Supported Endpoint Embeddings",
|
||||
"supportedEndpointImages": "Supported Endpoint Images",
|
||||
"supportedEndpointsLabel": "Supported Endpoints Label",
|
||||
"supportedEndpointAudio": "音频",
|
||||
"supportedEndpointChat": "聊天",
|
||||
"supportedEndpointEmbeddings": "Embeddings",
|
||||
"supportedEndpointImages": "图像",
|
||||
"supportedEndpointsLabel": "支持的端点",
|
||||
"tagGroupHint": "Tag Group Hint",
|
||||
"tagGroupLabel": "Tag Group Label",
|
||||
"tagGroupPlaceholder": "Tag Group Placeholder",
|
||||
"testModel": "Test Model",
|
||||
"testingModel": "Testing Model",
|
||||
"toggleOffShort": "Toggle Off Short",
|
||||
"toggleOnShort": "Toggle On Short",
|
||||
"toggleOffShort": "关",
|
||||
"toggleOnShort": "开",
|
||||
"tokenExpiredBadge": "Token Expired Badge",
|
||||
"tokenExpiredTitle": "Token Expired Title",
|
||||
"tokenExpiresSoonTitle": "Token Expires Soon Title",
|
||||
|
||||
@@ -164,6 +164,26 @@ test("buildClaudeCodeCompatibleRequest prefers existing Claude top-level system
|
||||
]);
|
||||
});
|
||||
|
||||
test("buildClaudeCodeCompatibleRequest does not duplicate an existing default system skeleton", () => {
|
||||
const payload = buildClaudeCodeCompatibleRequest({
|
||||
claudeBody: {
|
||||
system: [
|
||||
{
|
||||
type: "text",
|
||||
text: "You are a Claude agent, built on Anthropic's Claude Agent SDK.",
|
||||
},
|
||||
],
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
},
|
||||
model: "claude-sonnet-4-6",
|
||||
cwd: "/tmp/claude-code-compatible",
|
||||
now: new Date("2026-01-02T12:00:00.000Z"),
|
||||
});
|
||||
|
||||
assert.equal(payload.system.length, 1);
|
||||
assert.match((payload.system[0] as any).text, /Claude Agent SDK/);
|
||||
});
|
||||
|
||||
test("buildClaudeCodeCompatibleRequest covers Claude-native bodies and cache-control stripping", () => {
|
||||
const stripped = buildClaudeCodeCompatibleRequest({
|
||||
claudeBody: {
|
||||
|
||||
Reference in New Issue
Block a user