yymaxapi 1.0.76 → 1.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/yymaxapi.js
CHANGED
|
@@ -104,8 +104,8 @@ const DEFAULT_CODEX_MODELS = [
|
|
|
104
104
|
"name": "GPT 5.4"
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
|
-
"id": "gpt-5.
|
|
108
|
-
"name": "GPT 5.
|
|
107
|
+
"id": "gpt-5.3-codex",
|
|
108
|
+
"name": "GPT 5.3 Codex"
|
|
109
109
|
}
|
|
110
110
|
];
|
|
111
111
|
|
|
@@ -680,10 +680,14 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
680
680
|
const codexDir = path.join(os.homedir(), '.codex');
|
|
681
681
|
if (!fs.existsSync(codexDir)) fs.mkdirSync(codexDir, { recursive: true });
|
|
682
682
|
|
|
683
|
-
// ~/.codex/config.toml —
|
|
683
|
+
// ~/.codex/config.toml — 顶层设置和 section 分开管理
|
|
684
|
+
// TOML 规范:[section] 之后的 key=value 属于该 section,不是顶层
|
|
685
|
+
// 所以 model / model_provider 必须在所有 [section] 之前
|
|
684
686
|
const configPath = path.join(codexDir, 'config.toml');
|
|
685
687
|
const marker = '# >>> maxapi codex >>>';
|
|
686
688
|
const markerEnd = '# <<< maxapi codex <<<';
|
|
689
|
+
const topMarker = '# >>> maxapi codex top >>>';
|
|
690
|
+
const topMarkerEnd = '# <<< maxapi codex top <<<';
|
|
687
691
|
const providerKey = 'openclaw-relay';
|
|
688
692
|
// 确保 base_url 以 /v1 结尾(Codex CLI 要求)
|
|
689
693
|
let normalizedUrl = baseUrl.replace(/\/+$/, '');
|
|
@@ -692,24 +696,44 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
692
696
|
let existing = '';
|
|
693
697
|
if (fs.existsSync(configPath)) {
|
|
694
698
|
existing = fs.readFileSync(configPath, 'utf8');
|
|
695
|
-
// 移除旧的 maxapi section
|
|
699
|
+
// 移除旧的 maxapi section(provider block)
|
|
696
700
|
const re = new RegExp(`${marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${markerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
|
|
697
|
-
existing = existing.replace(re, '')
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
+
existing = existing.replace(re, '');
|
|
702
|
+
// 移除旧的 maxapi top-level block
|
|
703
|
+
const topRe = new RegExp(`${topMarker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${topMarkerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
|
|
704
|
+
existing = existing.replace(topRe, '');
|
|
705
|
+
// 兼容旧版:移除散落在 section 内的旧 model/model_provider(来自旧版 marker block 残留)
|
|
706
|
+
existing = existing.replace(/^model\s*=\s*"[^"]*"\s*$/gm, '');
|
|
707
|
+
existing = existing.replace(/^model_provider\s*=\s*"[^"]*"\s*$/gm, '');
|
|
708
|
+
existing = existing.replace(/\n{3,}/g, '\n\n').trim();
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// 顶层设置(MUST 在所有 [section] 之前)
|
|
712
|
+
const topBlock = [
|
|
713
|
+
topMarker,
|
|
701
714
|
`model = "${modelId}"`,
|
|
702
715
|
`model_provider = "${providerKey}"`,
|
|
703
|
-
|
|
716
|
+
topMarkerEnd
|
|
717
|
+
].join('\n');
|
|
718
|
+
|
|
719
|
+
// Provider section(追加在文件末尾)
|
|
720
|
+
const providerBlock = [
|
|
721
|
+
marker,
|
|
704
722
|
`[model_providers.${providerKey}]`,
|
|
705
723
|
`name = "OpenClaw Relay"`,
|
|
706
724
|
`base_url = "${normalizedUrl}"`,
|
|
707
725
|
`wire_api = "responses"`,
|
|
708
726
|
`experimental_bearer_token = "${apiKey}"`,
|
|
709
|
-
`requires_openai_auth = true`,
|
|
710
727
|
markerEnd
|
|
711
728
|
].join('\n');
|
|
712
|
-
|
|
729
|
+
|
|
730
|
+
// 组装:顶层设置 → 原有内容 → provider section
|
|
731
|
+
let content;
|
|
732
|
+
if (existing) {
|
|
733
|
+
content = `${topBlock}\n\n${existing}\n\n${providerBlock}\n`;
|
|
734
|
+
} else {
|
|
735
|
+
content = `${topBlock}\n\n${providerBlock}\n`;
|
|
736
|
+
}
|
|
713
737
|
fs.writeFileSync(configPath, content, 'utf8');
|
|
714
738
|
} catch { /* 非关键,静默失败 */ }
|
|
715
739
|
|
|
@@ -792,65 +816,34 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
|
|
|
792
816
|
content = fs.readFileSync(codexConfigPath, 'utf8');
|
|
793
817
|
}
|
|
794
818
|
|
|
795
|
-
//
|
|
819
|
+
// 移除旧标记块(仅移除 yunyi opencode 自己的)
|
|
796
820
|
content = content.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
|
|
797
|
-
content = content.replace(/# >>> maxapi codex >>>[\s\S]*?# <<< maxapi codex <<<\n?/g, '');
|
|
798
821
|
|
|
799
822
|
// 移除旧的 yunyi model_providers 段落(包括 yunyi-cli 写入的 [model_providers.yunyi])
|
|
800
823
|
content = content.replace(/\[model_providers\.yunyi[^\]]*\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
801
824
|
|
|
802
|
-
//
|
|
803
|
-
const
|
|
804
|
-
model_provider: '"yunyi-claude"',
|
|
805
|
-
model: '"claude-sonnet-4-6"',
|
|
806
|
-
model_context_window: '1000000',
|
|
807
|
-
model_auto_compact_token_limit: '900000',
|
|
808
|
-
model_reasoning_effort: '"xhigh"',
|
|
809
|
-
disable_response_storage: 'true',
|
|
810
|
-
};
|
|
811
|
-
for (const [key, value] of Object.entries(topSettings)) {
|
|
812
|
-
const re = new RegExp(`^${key}\\s*=\\s*[^\\n]*`, 'm');
|
|
813
|
-
if (re.test(content)) {
|
|
814
|
-
content = content.replace(re, `${key} = ${value}`);
|
|
815
|
-
} else {
|
|
816
|
-
// 插入到第一个 section 之前
|
|
817
|
-
const firstSection = content.search(/^\[/m);
|
|
818
|
-
if (firstSection > 0) {
|
|
819
|
-
content = content.slice(0, firstSection) + `${key} = ${value}\n` + content.slice(firstSection);
|
|
820
|
-
} else if (firstSection === 0) {
|
|
821
|
-
content = `${key} = ${value}\n` + content;
|
|
822
|
-
} else {
|
|
823
|
-
content += `${key} = ${value}\n`;
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
// 清理多余空行
|
|
829
|
-
content = content.replace(/\n{3,}/g, '\n\n').trim();
|
|
830
|
-
|
|
831
|
-
// 追加 model_providers 段落
|
|
832
|
-
const providers = [
|
|
833
|
-
'',
|
|
834
|
-
'# >>> yunyi opencode >>>',
|
|
835
|
-
'[model_providers.yunyi-claude]',
|
|
836
|
-
'name = "云翼 Claude"',
|
|
837
|
-
`base_url = "${claudeUrl}"`,
|
|
838
|
-
'wire_api = "anthropic"',
|
|
839
|
-
`experimental_bearer_token = "${apiKey}"`,
|
|
840
|
-
];
|
|
825
|
+
// 只追加 yunyi-codex provider(Claude 配置仅在 opencode.json 中,Codex CLI 不支持 wire_api=anthropic)
|
|
826
|
+
const providers = [''];
|
|
841
827
|
if (codexUrl) {
|
|
842
828
|
providers.push(
|
|
843
|
-
'',
|
|
829
|
+
'# >>> yunyi opencode >>>',
|
|
844
830
|
'[model_providers.yunyi-codex]',
|
|
845
831
|
'name = "云翼 Codex"',
|
|
846
832
|
`base_url = "${codexUrl}"`,
|
|
847
833
|
'wire_api = "responses"',
|
|
848
834
|
`experimental_bearer_token = "${apiKey}"`,
|
|
849
|
-
'requires_openai_auth =
|
|
835
|
+
'requires_openai_auth = false',
|
|
836
|
+
'# <<< yunyi opencode <<<'
|
|
850
837
|
);
|
|
851
838
|
}
|
|
852
|
-
|
|
853
|
-
|
|
839
|
+
|
|
840
|
+
// 清理多余空行
|
|
841
|
+
content = content.replace(/\n{3,}/g, '\n\n').trim();
|
|
842
|
+
|
|
843
|
+
// 追加 provider section
|
|
844
|
+
if (providers.length > 1) {
|
|
845
|
+
content += '\n\n' + providers.join('\n') + '\n';
|
|
846
|
+
}
|
|
854
847
|
|
|
855
848
|
fs.writeFileSync(codexConfigPath, content, 'utf8');
|
|
856
849
|
|