Skip to content

Commit 9c5c513

Browse files
committed
修复了一些windows上可能出现的问题
1 parent a32fc5e commit 9c5c513

17 files changed

Lines changed: 402 additions & 35 deletions

.claude/settings.local.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(npm --prefix \"/mnt/h/program/cocojiang\" run build)",
5+
"Bash(node --test \"/mnt/h/program/cocojiang/build/node/core/agent/test/codex-login.test.js\")",
6+
"Bash(node --test \"/mnt/h/program/cocojiang/build/node/core/agent/test/codex-login.test.js\" \"/mnt/h/program/cocojiang/build/node/core/agent/test/codex.test.js\")",
7+
"Skill(claude-api)",
8+
"Bash(npm run:*)",
9+
"Bash(node --test build/node/core/agent/test/settings-store.test.js build/node/core/agent/test/app.integration.test.js)",
10+
"Bash(node --test build/node/core/agent/test/codex-login.test.js)",
11+
"Bash(node --test build/node/core/agent/test/capture.test.js)"
12+
]
13+
}
14+
}

apps/mac-web/public/app.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ const cloudModelField = document.querySelector("#cloud-model-field");
7676
const cloudModelSelect = document.querySelector("#cloud-model");
7777
const cloudApiKeyField = document.querySelector("#cloud-api-key-field");
7878
const cloudApiKeyInput = document.querySelector("#cloud-api-key");
79+
const claudeBaseUrlField = document.querySelector("#claude-base-url-field");
80+
const claudeBaseUrlInput = document.querySelector("#claude-base-url");
7981
const cloudProviderNote = document.querySelector("#cloud-provider-note");
8082
const localModelField = document.querySelector("#local-model-field");
8183
const localVisionModelSelect = document.querySelector("#local-vision-model");
@@ -471,6 +473,7 @@ async function loadSettings() {
471473
localVisionModelSelect.value = settings.localVisionModel || "qwen3-vl:8b";
472474
cloudModelSelect.value = settings.cloudModel || "";
473475
cloudApiKeyInput.value = settings.cloudApiKey || "";
476+
claudeBaseUrlInput.value = settings.claudeBaseUrl || "";
474477
toggleSettingsFields();
475478
}
476479

@@ -498,7 +501,8 @@ async function saveSettings() {
498501
codexReasoningEffort: codexReasoningEffortSelect.value,
499502
localVisionModel: localVisionModelSelect.value,
500503
cloudModel: cloudModelSelect.value,
501-
cloudApiKey: cloudApiKeyInput.value
504+
cloudApiKey: cloudApiKeyInput.value,
505+
claudeBaseUrl: claudeBaseUrlInput.value
502506
})
503507
});
504508
modelProviderSelect.value = settings.modelProvider || "codex";
@@ -507,6 +511,7 @@ async function saveSettings() {
507511
localVisionModelSelect.value = settings.localVisionModel || "qwen3-vl:8b";
508512
cloudModelSelect.value = settings.cloudModel || "";
509513
cloudApiKeyInput.value = settings.cloudApiKey || "";
514+
claudeBaseUrlInput.value = settings.claudeBaseUrl || "";
510515
toggleSettingsFields();
511516
showBanner("模型配置已保存。", false);
512517
} finally {
@@ -939,6 +944,7 @@ function toggleSettingsFields() {
939944
const provider = modelProviderSelect.value;
940945
const isCodex = provider === "codex";
941946
const isCloud = provider === "claude" || provider === "openai";
947+
const isClaude = provider === "claude";
942948
const isLocal = provider === "lmstudio" || provider === "ollama";
943949

944950
codexModelSelect.closest(".field").classList.toggle("hidden", !isCodex);
@@ -947,6 +953,7 @@ function toggleSettingsFields() {
947953

948954
cloudModelField.classList.toggle("hidden", !isCloud);
949955
cloudApiKeyField.classList.toggle("hidden", !isCloud);
956+
claudeBaseUrlField.classList.toggle("hidden", !isClaude);
950957
cloudProviderNote.classList.toggle("hidden", !isCloud);
951958

952959
localModelField.classList.toggle("hidden", !isLocal);
@@ -957,7 +964,7 @@ function toggleSettingsFields() {
957964
populateModelOptions(cloudModelSelect, models, cloudModelSelect.value || models[0]?.slug || "");
958965
cloudProviderNote.textContent =
959966
provider === "claude"
960-
? "需要 Anthropic API Key。在 console.anthropic.com 获取。"
967+
? "需要 Anthropic API Key。默认使用官方 API,也可以填写 Claude Base URL 接入代理或兼容网关。"
961968
: "需要 OpenAI API Key。在 platform.openai.com 获取。支持所有 OpenAI 兼容 API。";
962969
}
963970

apps/mac-web/public/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ <h4>不知道选哪个?</h4>
308308
<span>API Key</span>
309309
<input id="cloud-api-key" type="password" placeholder="sk-... 或 anthropic key" autocomplete="off" />
310310
</label>
311+
<label id="claude-base-url-field" class="field hidden">
312+
<span>Claude Base URL</span>
313+
<input id="claude-base-url" type="url" placeholder="https://api.anthropic.com" autocomplete="off" spellcheck="false" />
314+
</label>
311315
<p id="cloud-provider-note" class="status-copy hidden"></p>
312316
<label id="local-model-field" class="field">
313317
<span>本地视觉模型</span>

core/agent/src/app.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ async function routeRequest(input: {
361361
modelName: resolveSelectedModel(settings),
362362
codexReasoningEffort: settings.codexReasoningEffort,
363363
cloudApiKey: settings.cloudApiKey,
364+
claudeBaseUrl: settings.claudeBaseUrl,
364365
promptTemplate: input.promptTemplateState.value,
365366
question: session.question,
366367
clientSource: source,
@@ -408,6 +409,7 @@ async function routeRequest(input: {
408409
localVisionModel?: string;
409410
cloudModel?: string;
410411
cloudApiKey?: string;
412+
claudeBaseUrl?: string;
411413
}>(input.request);
412414

413415
const settings = await input.settingsStore.saveSettings({
@@ -416,7 +418,8 @@ async function routeRequest(input: {
416418
codexReasoningEffort: body.codexReasoningEffort,
417419
localVisionModel: body.localVisionModel,
418420
cloudModel: body.cloudModel,
419-
cloudApiKey: body.cloudApiKey
421+
cloudApiKey: body.cloudApiKey,
422+
claudeBaseUrl: body.claudeBaseUrl
420423
});
421424
sendJson(input.response, 200, settings);
422425
return;
@@ -719,6 +722,7 @@ async function routeRequest(input: {
719722
modelName: selectedModel,
720723
codexReasoningEffort: settings.codexReasoningEffort,
721724
cloudApiKey: settings.cloudApiKey,
725+
claudeBaseUrl: settings.claudeBaseUrl,
722726
spawnProcess: input.spawnProcess,
723727
onProgress: undefined
724728
});
@@ -807,6 +811,7 @@ async function processAnalysisSession(input: {
807811
modelName: string;
808812
codexReasoningEffort: "low" | "medium" | "high";
809813
cloudApiKey: string;
814+
claudeBaseUrl: string;
810815
promptTemplate: string;
811816
question: string;
812817
clientSource: ClientSource;
@@ -878,6 +883,7 @@ async function processAnalysisSession(input: {
878883
modelName: input.modelName,
879884
codexReasoningEffort: input.codexReasoningEffort,
880885
cloudApiKey: input.cloudApiKey,
886+
claudeBaseUrl: input.claudeBaseUrl,
881887
spawnProcess: input.spawnProcess,
882888
onProgress: async (message) => {
883889
await transitionSession(input.store, input.activityStore, input.hub, input.clientSource, input.sessionId, "analyzing", message);
@@ -999,12 +1005,17 @@ async function runConfiguredAnalysis(input: {
9991005
modelName: string;
10001006
codexReasoningEffort: "low" | "medium" | "high";
10011007
cloudApiKey: string;
1008+
claudeBaseUrl: string;
10021009
spawnProcess?: SpawnProcess;
10031010
onProgress?: (message: string) => void | Promise<void>;
10041011
}) {
10051012
if (input.modelProvider === "claude") {
10061013
return await runClaudeVisionAnalysis({
1007-
config: input.config,
1014+
config: {
1015+
schemaPath: input.config.schemaPath,
1016+
codexTimeoutMs: input.config.codexTimeoutMs,
1017+
claudeBaseUrl: input.claudeBaseUrl || input.config.claudeBaseUrl
1018+
},
10081019
apiKey: input.cloudApiKey,
10091020
imagePath: input.imagePath,
10101021
question: input.question,

core/agent/src/capture-macos.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export async function captureScreenOnMacos(input: {
1313
}
1414

1515
try {
16-
await input.runCommand(input.captureBin, ["-x", "-m", input.outputPath]);
16+
await input.runCommand(input.captureBin, ["-x", input.outputPath]);
1717
} catch (error) {
1818
const message = error instanceof Error ? error.message : String(error);
1919
if (message.includes("exited with code 1") || message.includes("Permission") || message.includes("not permitted")) {

core/agent/src/claude-vision.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface ClaudeMessageResponse {
1010
}
1111

1212
export async function runClaudeVisionAnalysis(input: {
13-
config: Pick<AppConfig, "schemaPath" | "codexTimeoutMs">;
13+
config: Pick<AppConfig, "schemaPath" | "codexTimeoutMs" | "claudeBaseUrl">;
1414
apiKey: string;
1515
imagePath: string;
1616
question: string;
@@ -36,11 +36,12 @@ export async function runClaudeVisionAnalysis(input: {
3636

3737
await input.onProgress?.("Uploading screenshot to Claude");
3838

39+
const baseUrl = input.config.claudeBaseUrl.replace(/\/+$/, "");
3940
const controller = new AbortController();
4041
const timeout = setTimeout(() => controller.abort(), input.config.codexTimeoutMs);
4142

4243
try {
43-
const response = await fetch("https://api.anthropic.com/v1/messages", {
44+
const response = await fetch(`${baseUrl}/v1/messages`, {
4445
method: "POST",
4546
headers: {
4647
"content-type": "application/json",
@@ -102,7 +103,7 @@ export async function runClaudeVisionAnalysis(input: {
102103

103104
const message = error instanceof Error ? error.message : String(error);
104105
if (message.includes("fetch failed")) {
105-
throw new Error("Failed to reach the Claude API. Check your network connection.");
106+
throw new Error(`Failed to reach Claude API at ${baseUrl}. Check your network connection.`);
106107
}
107108

108109
throw error instanceof Error ? error : new Error(message);

0 commit comments

Comments
 (0)