Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ target/
node_modules/
apps/codex-plus-manager/src-tauri/gen/

.kiro
.codex_asar_extract/
.codex_asar_extract_latest/
.superpowers/
Expand Down
62 changes: 62 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions apps/codex-plus-manager/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/codex-plus-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.4",
"fast-check": "4.8.0",
"tailwindcss": "^4.0.0"
}
}
57 changes: 53 additions & 4 deletions apps/codex-plus-manager/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
} from "lucide-react";
import { ProviderPresetSelector } from "@/components/ProviderPresetSelector";
import type { PresetPatch } from "@/components/ProviderPresetSelector";
import { BedrockRelayProfileEditor } from "@/components/BedrockRelayProfileEditor";
import { useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from "react";

import { Badge as UiBadge } from "@/components/ui/badge";
Expand All @@ -68,6 +69,8 @@ import {
serializeModelWindowRows,
type ModelWindowRow,
} from "./model-windows";
import type { BedrockConfig } from "./bedrock-config";
import { isBedrockRelayProfile, bedrockAllowsProviderTesting, resolveBedrockAfterDerive, bedrockValidationError } from "./bedrock-config";
import { getLanguage, t, tf, toggleLanguage } from "@/i18n";

type Status = "ok" | "failed" | "not_implemented" | "not_checked" | string;
Expand Down Expand Up @@ -210,6 +213,7 @@ export type RelayProfile = {
modelWindows: string;
userAgent: string;
aggregate?: RelayAggregateConfig | null;
bedrock?: BedrockConfig | null;
};

type RelayAggregateStrategy = "failover" | "conversationRoundRobin" | "requestRoundRobin" | "weightedRoundRobin";
Expand Down Expand Up @@ -3762,14 +3766,20 @@ function SortableRelayProfileCard({
</Button>
<span className="relay-card-extra">
<Button
disabled={isAggregateRelayProfile(profile)}
disabled={isAggregateRelayProfile(profile) || !bedrockAllowsProviderTesting(profile)}
onClick={(event) => {
event.stopPropagation();
if (isAggregateRelayProfile(profile)) return;
if (isAggregateRelayProfile(profile) || !bedrockAllowsProviderTesting(profile)) return;
void actions.testRelayProfile(profile);
}}
size="icon"
title={isAggregateRelayProfile(profile) ? t("聚合供应商会在真实对话中轮转成员,请测试成员供应商") : t("发送 hi 测试")}
title={
isAggregateRelayProfile(profile)
? t("聚合供应商会在真实对话中轮转成员,请测试成员供应商")
: !bedrockAllowsProviderTesting(profile)
? t("AWS Profile 模式下无法在此测试供应商;请在 Codex 会话中验证")
: t("发送 hi 测试")
}
variant="ghost"
>
<TestTube className="h-4 w-4" />
Expand Down Expand Up @@ -3888,7 +3898,11 @@ function RelayProfileDetail({
setDraft(nextDraft);
setModelWindowRows(modelWindowRowsFromProfile(nextDraft.modelList, nextDraft.modelWindows || ""));
}, [profile.id, profile.modelList, profile.modelWindows, profileUsesLiveFiles, isActive, isNew, relayFiles?.configContents, relayFiles?.authContents]);
const validationError = isAggregateRelayProfile(draft) ? aggregateRelayProfileValidation(draft) : null;
const validationError = isAggregateRelayProfile(draft)
? aggregateRelayProfileValidation(draft)
: isBedrockRelayProfile(draft)
? bedrockValidationError(draft.bedrock!, draft.apiKey)
: null;
const draftWithModelRows = () => {
const serializedRows = serializeModelWindowRows(modelWindowRows);
return { ...draft, modelList: serializedRows.modelList, modelWindows: serializedRows.modelWindows };
Expand Down Expand Up @@ -4016,6 +4030,18 @@ function RelayProfileEditor({
/>
);
}
if (isBedrockRelayProfile(profile)) {
return (
// 沿用通用 relay 编辑器的卡片外壳(border/border-radius/margin/padding/动画),
// 保证 Bedrock 编辑器和其它编辑器视觉一致,避免直接贴到父容器边缘。
<div className="relay-profile-editor">
<BedrockRelayProfileEditor
profile={profile}
onChange={(patch) => onProfileChange(applyRelayProfilePatchToFiles(profile, patch, { allowGenerateFiles: isNew }))}
/>
</div>
);
}

const showApiFields = profile.relayMode !== "official" || profile.officialMixApiKey;
const updateDraft = (patch: Partial<RelayProfile>) => {
Expand Down Expand Up @@ -4071,6 +4097,26 @@ function RelayProfileEditor({
onSelect={(patch: PresetPatch) => {
updateDraft(patch as unknown as Partial<RelayProfile>);
}}
onSelectBedrock={() => {
// 「直连 AWS Bedrock」的最常见路径是 AWS Profile (SSO),因此默认预填
// authMode=awsProfile + awsProfile=default。region 默认 us-east-2 是
// 因为 Bedrock Mantle 的 GPT-5.5 目前仅在 us-east-2 独家开放(见文档 §A)。
// 模型默认 openai.gpt-5.5——Bedrock Mantle 的 /v1/responses endpoint
// 只暴露 GPT-5.x 系列(openai.gpt-5.5 / openai.gpt-5.4);gpt-oss 等
// Bedrock native 模型 ID 走 Mantle 会 404(模型不存在),需要走 LiteLLM 中转。
updateDraft({
relayMode: "pureApi",
model: "openai.gpt-5.5",
bedrock: {
authMode: "awsProfile",
providerId: "",
region: "us-east-2",
awsProfile: "default",
iamUserName: "",
iamKeyValidityDays: "90",
},
});
}}
/>
) : null}
<div className="relay-fields">
Expand Down Expand Up @@ -6306,6 +6352,9 @@ function deriveRelayProfileFromFiles(profile: RelayProfile): RelayProfile {
autoCompactLimit: codexTopLevelIntFromConfig(configContents, "model_auto_compact_token_limit"),
configContents,
authContents,
// 磁盘 config 有 Bedrock 特征时以推导结果为准;否则保留 profile 上已有的 bedrock,
// 避免 UI 中间态(例如刚点「Amazon Bedrock」按钮但 config 还是通用 custom 模板)被吞掉。
bedrock: resolveBedrockAfterDerive(profile.bedrock, configContents),
};
}

Expand Down
Loading