swayrouter 1.0.2 → 1.0.4
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/CHANGELOG.md +16 -0
- package/dashboard/dist/assets/{CliTools-Ch3gKuNw.js → CliTools-5DLXOz1A.js} +1 -1
- package/dashboard/dist/assets/{Combo-BBCldjWi.js → Combo-BCvuw7s2.js} +1 -1
- package/dashboard/dist/assets/{ConsoleLog-wywAYcPT.js → ConsoleLog-BwgJ9V8I.js} +4 -4
- package/dashboard/dist/assets/{Dashboard-DxzyF41b.js → Dashboard-B-tNs8a1.js} +1 -1
- package/dashboard/dist/assets/{Header-C_9Su9BF.js → Header-9KXz4S67.js} +1 -1
- package/dashboard/dist/assets/{Keys-D0ufgcsc.js → Keys-DE32cEsn.js} +1 -1
- package/dashboard/dist/assets/Login-z7dbRqrR.js +1 -0
- package/dashboard/dist/assets/{ManageApiKey-CVXsmW2B.js → ManageApiKey-DF3A1CXL.js} +1 -1
- package/dashboard/dist/assets/{OAuthCallback-D_UZYcF6.js → OAuthCallback-I8fzY5zi.js} +1 -1
- package/dashboard/dist/assets/Provider-Caq5lvsq.js +4 -0
- package/dashboard/dist/assets/{ProviderModelAccordion-BAifkfVR.js → ProviderModelAccordion-GZSOrZZu.js} +1 -1
- package/dashboard/dist/assets/{Proxy-CU15VJ--.js → Proxy-DJVhsf4E.js} +1 -1
- package/dashboard/dist/assets/QuotaMonitor-BA4GOxkV.js +1 -0
- package/dashboard/dist/assets/{Settings-Dt4y2dC0.js → Settings-eEpS37LF.js} +1 -1
- package/dashboard/dist/assets/{Setup-DSDUwU7N.js → Setup-D9G2dVUf.js} +1 -1
- package/dashboard/dist/assets/{StatusBadge-1nAOyHU2.js → StatusBadge-DClAYX7v.js} +1 -1
- package/dashboard/dist/assets/{SwayChat-Bup7up6D.js → SwayChat-DS0GBQKQ.js} +2 -2
- package/dashboard/dist/assets/Usage-CRQCq5jc.js +4 -0
- package/dashboard/dist/assets/{accordion-DOOPDDgt.js → accordion-BkSdf_dl.js} +1 -1
- package/dashboard/dist/assets/{admin-extras-api-CCdu5TFM.js → admin-extras-api-ppLkXcD9.js} +1 -1
- package/dashboard/dist/assets/{api-keys-api-ifAC2Ok3.js → api-keys-api-CsdHmg2W.js} +1 -1
- package/dashboard/dist/assets/{card-CC0Omjcv.js → card-BOVhvx7W.js} +1 -1
- package/dashboard/dist/assets/{checkbox-7SZBrmbN.js → checkbox-DU_0LpXJ.js} +1 -1
- package/dashboard/dist/assets/{connections-api-_N54UD3S.js → connections-api-CQHf0Hwe.js} +1 -1
- package/dashboard/dist/assets/{copy-button-qBvM6H9z.js → copy-button-nPFbNAXf.js} +1 -1
- package/dashboard/dist/assets/{currency-api-SV9CBf5e.js → currency-api-CDXu9UhW.js} +1 -1
- package/dashboard/dist/assets/{flip-button-BGgkjtl0.js → flip-button-C_PNv8Iq.js} +1 -1
- package/dashboard/dist/assets/{frame-cUiti6Lq.js → frame-BLwA8c3u.js} +1 -1
- package/dashboard/dist/assets/index-CN-Y5gO6.css +1 -0
- package/dashboard/dist/assets/index-x5tLD3Ye.js +10 -0
- package/dashboard/dist/assets/{ripple-button-l8aMiVVG.js → ripple-button-BV_KcZ7W.js} +1 -1
- package/dashboard/dist/assets/{segmented-CqmEnQjZ.js → segmented-BBSMiP-0.js} +1 -1
- package/dashboard/dist/assets/select-DELc8FMO.js +1 -0
- package/dashboard/dist/assets/{skeleton-7uJDiIXe.js → skeleton-CFSSp0e0.js} +1 -1
- package/dashboard/dist/assets/{table-D0M60Tu1.js → table-lcAgAODE.js} +1 -1
- package/dashboard/dist/assets/{tabs-C6YkuulG.js → tabs-CSBJRjaH.js} +1 -1
- package/dashboard/dist/assets/{tunnel-api-DDPsBaDV.js → tunnel-api-CdE1F_Ct.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/executors/index.js +3 -2
- package/src/executors/opencode-go.js +46 -39
- package/src/executors/opencode.js +54 -31
- package/src/handlers/chatCore.js +3 -2
- package/src/providers/registry/index.js +5 -4
- package/src/providers/registry/opencode-go.js +16 -22
- package/src/providers/registry/opencode-zen.js +34 -0
- package/src/providers/registry/opencode.js +16 -12
- package/src/routes/api/providers/[id]/models/route.js +28 -0
- package/src/routes/api/providers/[id]/test/testUtils.js +15 -6
- package/src/routes/api/providers/catalog/route.js +3 -1
- package/src/routes/api/providers/suggested-models/filters.js +7 -2
- package/src/routes/api/providers/validate/route.js +14 -11
- package/src/types/provider.ts +1 -1
- package/src/utils/opencode.js +225 -0
- package/dashboard/dist/assets/Login-BeKpipS_.js +0 -1
- package/dashboard/dist/assets/Provider-BU7JfTqm.js +0 -4
- package/dashboard/dist/assets/QuotaMonitor-HzGK7bcc.js +0 -1
- package/dashboard/dist/assets/Usage-eWnrPQ_v.js +0 -4
- package/dashboard/dist/assets/index-B6j-9zHy.js +0 -10
- package/dashboard/dist/assets/index-C-_l0yYz.css +0 -1
- package/dashboard/dist/assets/select-D8pUtMXp.js +0 -1
package/src/executors/index.js
CHANGED
|
@@ -34,8 +34,9 @@ const executors = {
|
|
|
34
34
|
cu: new CursorExecutor(),
|
|
35
35
|
vertex: new VertexExecutor("vertex"),
|
|
36
36
|
"vertex-partner": new VertexExecutor("vertex-partner"),
|
|
37
|
-
opencode: new OpenCodeExecutor(),
|
|
38
|
-
"opencode-
|
|
37
|
+
opencode: new OpenCodeExecutor(),
|
|
38
|
+
"opencode-zen": new OpenCodeExecutor("opencode-zen"),
|
|
39
|
+
"opencode-go": new OpenCodeGoExecutor(),
|
|
39
40
|
"grok-web": new GrokWebExecutor(),
|
|
40
41
|
"grok-cli": new GrokCliExecutor(),
|
|
41
42
|
gcli: new GrokCliExecutor(),
|
|
@@ -1,47 +1,54 @@
|
|
|
1
1
|
import { BaseExecutor } from "./base.js";
|
|
2
|
-
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
-
import { injectReasoningContent } from "../utils/reasoningContentInjector.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
const MESSAGES_FORMAT_MODELS = new Set([
|
|
7
|
-
"minimax-m3",
|
|
8
|
-
"minimax-m2.7",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
+
import { injectReasoningContent } from "../utils/reasoningContentInjector.js";
|
|
4
|
+
import { applyOpenCodeFingerprint, buildOpenCodeHeaders } from "../utils/opencode.js";
|
|
5
|
+
|
|
6
|
+
const MESSAGES_FORMAT_MODELS = new Set([
|
|
7
|
+
"minimax-m3",
|
|
8
|
+
"minimax-m2.7",
|
|
9
|
+
"qwen3.7-max",
|
|
10
|
+
"claude-opus-5",
|
|
11
|
+
]);
|
|
12
|
+
const RESPONSES_FORMAT_MODELS = new Set(["grok-4.5"]);
|
|
13
|
+
const modelId = (model) => typeof model === "string" ? model.split("/").pop() : model;
|
|
14
14
|
|
|
15
15
|
const BASE = "https://opencode.ai/zen/go/v1";
|
|
16
16
|
|
|
17
|
-
export class OpenCodeGoExecutor extends BaseExecutor {
|
|
17
|
+
export class OpenCodeGoExecutor extends BaseExecutor {
|
|
18
18
|
constructor() {
|
|
19
19
|
super("opencode-go", PROVIDERS["opencode-go"]);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
resolveTargetFormat(model, currentFormat) {
|
|
23
|
+
const id = modelId(model);
|
|
24
|
+
if (RESPONSES_FORMAT_MODELS.has(id)) return "openai-responses";
|
|
25
|
+
return MESSAGES_FORMAT_MODELS.has(id) ? "claude" : currentFormat;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
buildUrl(model) {
|
|
29
|
+
return MESSAGES_FORMAT_MODELS.has(modelId(model))
|
|
25
30
|
? `${BASE}/messages`
|
|
26
31
|
: `${BASE}/chat/completions`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
buildHeaders(credentials, stream = true) {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
buildHeaders(credentials, stream = true, _url, model) {
|
|
35
|
+
const id = modelId(model);
|
|
36
|
+
const format = RESPONSES_FORMAT_MODELS.has(id)
|
|
37
|
+
? "responses"
|
|
38
|
+
: MESSAGES_FORMAT_MODELS.has(id)
|
|
39
|
+
? "claude"
|
|
40
|
+
: "openai";
|
|
41
|
+
return buildOpenCodeHeaders(credentials, stream, { authorization: "", format });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
transformRequest(model, body) {
|
|
45
|
+
const id = modelId(model);
|
|
46
|
+
const format = RESPONSES_FORMAT_MODELS.has(id)
|
|
47
|
+
? "responses"
|
|
48
|
+
: MESSAGES_FORMAT_MODELS.has(id)
|
|
49
|
+
? "claude"
|
|
50
|
+
: "openai";
|
|
51
|
+
const fingerprinted = applyOpenCodeFingerprint({ ...body }, format);
|
|
52
|
+
return injectReasoningContent({ provider: this.provider, model, body: fingerprinted });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,31 +1,54 @@
|
|
|
1
|
-
import { BaseExecutor } from "./base.js";
|
|
2
|
-
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
-
import { injectReasoningContent } from "../utils/reasoningContentInjector.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
1
|
+
import { BaseExecutor } from "./base.js";
|
|
2
|
+
import { PROVIDERS } from "../config/providers.js";
|
|
3
|
+
import { injectReasoningContent } from "../utils/reasoningContentInjector.js";
|
|
4
|
+
import { applyOpenCodeFingerprint, buildOpenCodeHeaders } from "../utils/opencode.js";
|
|
5
|
+
|
|
6
|
+
const RESPONSES_MODELS = new Set([
|
|
7
|
+
"muse-spark-1.3-contributor-free",
|
|
8
|
+
"muse-spark-1.2-contributor-free",
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
const MESSAGES_MODELS = new Set(["claude-opus-5", "qwen3.7-max", "minimax-m3"]);
|
|
12
|
+
const modelId = (model) => typeof model === "string" ? model.split("/").pop() : model;
|
|
13
|
+
|
|
14
|
+
export class OpenCodeExecutor extends BaseExecutor {
|
|
15
|
+
constructor(provider = "opencode") {
|
|
16
|
+
super(provider, PROVIDERS[provider]);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
resolveTargetFormat(model, currentFormat) {
|
|
20
|
+
const id = modelId(model);
|
|
21
|
+
if (RESPONSES_MODELS.has(id)) return "openai-responses";
|
|
22
|
+
if (MESSAGES_MODELS.has(id)) return "claude";
|
|
23
|
+
return currentFormat;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getModelFormat(model) {
|
|
27
|
+
const id = modelId(model);
|
|
28
|
+
if (RESPONSES_MODELS.has(id)) return "responses";
|
|
29
|
+
if (MESSAGES_MODELS.has(id)) return "claude";
|
|
30
|
+
return "openai";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
transformRequest(model, body) {
|
|
34
|
+
const format = this.getModelFormat(model);
|
|
35
|
+
const fingerprinted = applyOpenCodeFingerprint({ ...body }, format, { forceStream: true });
|
|
36
|
+
return injectReasoningContent({ provider: this.provider, model, body: fingerprinted });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
buildUrl(model) {
|
|
40
|
+
const id = modelId(model);
|
|
41
|
+
const base = this.config.baseUrl;
|
|
42
|
+
if (RESPONSES_MODELS.has(id)) return `${base}/zen/v1/responses`;
|
|
43
|
+
return MESSAGES_MODELS.has(id)
|
|
44
|
+
? `${base}/zen/v1/messages`
|
|
45
|
+
: `${base}/zen/v1/chat/completions`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
buildHeaders(credentials, stream = true, _url, model) {
|
|
49
|
+
return buildOpenCodeHeaders(credentials, stream, {
|
|
50
|
+
authorization: "public",
|
|
51
|
+
format: this.getModelFormat(model),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/handlers/chatCore.js
CHANGED
|
@@ -83,7 +83,9 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
|
|
|
83
83
|
const modelTargetFormat = getModelTargetFormat(alias, model);
|
|
84
84
|
|
|
85
85
|
const runtimeTransport = resolveTransport(provider, sourceFormat);
|
|
86
|
-
const
|
|
86
|
+
const executor = getExecutor(provider);
|
|
87
|
+
const defaultTargetFormat = modelTargetFormat || runtimeTransport?.format || getTargetFormat(provider, credentials);
|
|
88
|
+
const targetFormat = executor.resolveTargetFormat?.(model, defaultTargetFormat) || defaultTargetFormat;
|
|
87
89
|
if (runtimeTransport && credentials) credentials.runtimeTransport = runtimeTransport;
|
|
88
90
|
|
|
89
91
|
const canonicalRequest = normalizeTranslationRequest({
|
|
@@ -308,7 +310,6 @@ export async function handleChatCore({ body, modelInfo, credentials, log, onCred
|
|
|
308
310
|
log, provider, model, reqTag
|
|
309
311
|
});
|
|
310
312
|
|
|
311
|
-
const executor = getExecutor(provider);
|
|
312
313
|
const executeOptions = {
|
|
313
314
|
model, body: translatedBody, stream, credentials,
|
|
314
315
|
signal: streamController.signal, log, proxyOptions,
|
|
@@ -43,9 +43,10 @@ import p41 from "./nvidia.js";
|
|
|
43
43
|
import p42 from "./ollama-local.js";
|
|
44
44
|
import p43 from "./ollama.js";
|
|
45
45
|
import p44 from "./openai.js";
|
|
46
|
-
import p45 from "./opencode-go.js";
|
|
47
|
-
import p46 from "./opencode.js";
|
|
48
|
-
import p47 from "./
|
|
46
|
+
import p45 from "./opencode-go.js";
|
|
47
|
+
import p46 from "./opencode.js";
|
|
48
|
+
import p47 from "./opencode-zen.js";
|
|
49
|
+
import p48 from "./openrouter.js";
|
|
49
50
|
import p50 from "./perplexity.js";
|
|
50
51
|
import p51 from "./poolside.js";
|
|
51
52
|
import p52 from "./qoder.js";
|
|
@@ -69,7 +70,7 @@ const REGISTRY = [
|
|
|
69
70
|
p10, p11, p12, p13, p14, p15, p16, p17, p18, p19,
|
|
70
71
|
p20, p21, p22, p23, p24, p25, p26, p27, p28, p29,
|
|
71
72
|
p30, p31, p32, p33, p34, p35, p36, p37, p38, p39,
|
|
72
|
-
p40, p41, p42, p43, p44, p45, p46, p47,
|
|
73
|
+
p40, p41, p42, p43, p44, p45, p46, p47, p48,
|
|
73
74
|
p50, p51, p52, p53, p54, p55, p56, p57, p58, p59,
|
|
74
75
|
p60, p61, p62, p63, p64, p65, p66,
|
|
75
76
|
];
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { OPENCODE_GO_MODELS, OPENCODE_USER_AGENT } from "../../utils/opencode.js";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
2
4
|
id: "opencode-go",
|
|
3
5
|
priority: 210,
|
|
4
6
|
alias: "opencode-go",
|
|
@@ -18,24 +20,16 @@ export default {
|
|
|
18
20
|
},
|
|
19
21
|
},
|
|
20
22
|
category: "apikey",
|
|
21
|
-
transport: {
|
|
22
|
-
baseUrl: "https://opencode.ai/zen/go/v1/chat/completions",
|
|
23
|
-
headers: {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
{ id: "minimax-m3", name: "MiniMax M3", targetFormat: "claude" },
|
|
35
|
-
{ id: "minimax-m2.7", name: "MiniMax M2.7", targetFormat: "claude" },
|
|
36
|
-
{ id: "minimax-m2.5", name: "MiniMax M2.5", targetFormat: "claude" },
|
|
37
|
-
{ id: "qwen3.7-max", name: "Qwen 3.7 Max", targetFormat: "claude" },
|
|
38
|
-
{ id: "qwen3.7-plus", name: "Qwen 3.7 Plus", targetFormat: "claude" },
|
|
39
|
-
{ id: "qwen3.6-plus", name: "Qwen 3.6 Plus", targetFormat: "claude" },
|
|
40
|
-
],
|
|
41
|
-
};
|
|
23
|
+
transport: {
|
|
24
|
+
baseUrl: "https://opencode.ai/zen/go/v1/chat/completions",
|
|
25
|
+
headers: {
|
|
26
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
27
|
+
"x-opencode-client": "desktop",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
models: OPENCODE_GO_MODELS,
|
|
31
|
+
modelsFetcher: {
|
|
32
|
+
url: "https://opencode.ai/zen/go/v1/models",
|
|
33
|
+
type: "openai",
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { OPENCODE_USER_AGENT } from "../../utils/opencode.js";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: "opencode-zen",
|
|
5
|
+
priority: 205,
|
|
6
|
+
alias: "ocz",
|
|
7
|
+
uiAlias: "ocz",
|
|
8
|
+
display: {
|
|
9
|
+
name: "OpenCode Zen",
|
|
10
|
+
icon: "terminal",
|
|
11
|
+
color: "#E87040",
|
|
12
|
+
textIcon: "OC",
|
|
13
|
+
website: "https://opencode.ai/auth",
|
|
14
|
+
notice: {
|
|
15
|
+
text: "OpenCode Zen PAYG: connect an API key from your OpenCode workspace.",
|
|
16
|
+
apiKeyUrl: "https://opencode.ai/auth",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
category: "apikey",
|
|
20
|
+
authType: "apikey",
|
|
21
|
+
authModes: ["apikey"],
|
|
22
|
+
transport: {
|
|
23
|
+
baseUrl: "https://opencode.ai",
|
|
24
|
+
headers: {
|
|
25
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
26
|
+
"x-opencode-client": "desktop",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
modelsFetcher: {
|
|
30
|
+
url: "https://opencode.ai/zen/v1/models",
|
|
31
|
+
type: "opencode-all",
|
|
32
|
+
},
|
|
33
|
+
passthroughModels: true,
|
|
34
|
+
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { OPENCODE_FREE_MODELS, OPENCODE_USER_AGENT } from "../../utils/opencode.js";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
2
4
|
id: "opencode",
|
|
3
5
|
priority: 40,
|
|
4
6
|
hasFree: true,
|
|
@@ -13,14 +15,16 @@ export default {
|
|
|
13
15
|
category: "none",
|
|
14
16
|
authType: "none",
|
|
15
17
|
noAuth: true,
|
|
16
|
-
transport: {
|
|
17
|
-
baseUrl: "https://opencode.ai",
|
|
18
|
-
headers: {
|
|
19
|
-
"x-opencode-client": "desktop",
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
18
|
+
transport: {
|
|
19
|
+
baseUrl: "https://opencode.ai",
|
|
20
|
+
headers: {
|
|
21
|
+
"x-opencode-client": "desktop",
|
|
22
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
23
|
+
},
|
|
24
|
+
forceStream: true,
|
|
25
|
+
noAuth: true,
|
|
26
|
+
},
|
|
27
|
+
models: OPENCODE_FREE_MODELS,
|
|
28
|
+
modelsFetcher: { url: "https://opencode.ai/zen/v1/models", type: "opencode-free" },
|
|
29
|
+
passthroughModels: true,
|
|
30
|
+
};
|
|
@@ -14,6 +14,7 @@ import { resolveCodeBuddyModels } from "open-sse/services/codebuddyModels.js";
|
|
|
14
14
|
import { getCapabilitiesForModel } from "open-sse/providers/capabilities.js";
|
|
15
15
|
import { getThinkingLevels } from "open-sse/providers/thinkingLevels.js";
|
|
16
16
|
import { AGENTROUTER_MODELS_URL, AGENTROUTER_OPENAI_HEADERS } from "open-sse/providers/shared.js";
|
|
17
|
+
import { OPENCODE_USER_AGENT } from "open-sse/utils/opencode.js";
|
|
17
18
|
import { resolveConnectionProxyConfig } from "@/lib/network/connectionProxy.js";
|
|
18
19
|
import { logRouteError } from "@/lib/errors/publicError";
|
|
19
20
|
|
|
@@ -244,6 +245,33 @@ const PROVIDER_MODELS_CONFIG = {
|
|
|
244
245
|
"codebuddy-intl": {
|
|
245
246
|
customResolver: async () => ({ models: getStaticProviderModels("codebuddy-intl") }),
|
|
246
247
|
},
|
|
248
|
+
opencode: {
|
|
249
|
+
customResolver: async () => ({ models: getStaticProviderModels("opencode") }),
|
|
250
|
+
},
|
|
251
|
+
"opencode-zen": {
|
|
252
|
+
url: "https://opencode.ai/zen/v1/models",
|
|
253
|
+
method: "GET",
|
|
254
|
+
headers: {
|
|
255
|
+
"Content-Type": "application/json",
|
|
256
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
257
|
+
"x-opencode-client": "desktop",
|
|
258
|
+
},
|
|
259
|
+
authHeader: "Authorization",
|
|
260
|
+
authPrefix: "Bearer ",
|
|
261
|
+
parseResponse: parseOpenAIStyleModels,
|
|
262
|
+
},
|
|
263
|
+
"opencode-go": {
|
|
264
|
+
url: "https://opencode.ai/zen/go/v1/models",
|
|
265
|
+
method: "GET",
|
|
266
|
+
headers: {
|
|
267
|
+
"Content-Type": "application/json",
|
|
268
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
269
|
+
"x-opencode-client": "desktop",
|
|
270
|
+
},
|
|
271
|
+
authHeader: "Authorization",
|
|
272
|
+
authPrefix: "Bearer ",
|
|
273
|
+
parseResponse: parseOpenAIStyleModels,
|
|
274
|
+
},
|
|
247
275
|
antigravity: {
|
|
248
276
|
customResolver: buildOAuthResolver({
|
|
249
277
|
refreshFn: (conn) => refreshGoogleToken(conn.refreshToken, GEMINI_CONFIG.clientId, GEMINI_CONFIG.clientSecret),
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "@/lib/oauth/constants/oauth";
|
|
24
24
|
import { buildClineHeaders } from "@/shared/utils/clineAuth";
|
|
25
25
|
import { AGENTROUTER_MODELS_URL, AGENTROUTER_OPENAI_HEADERS } from "open-sse/providers/shared.js";
|
|
26
|
+
import { OPENCODE_USER_AGENT } from "open-sse/utils/opencode.js";
|
|
26
27
|
import { buildCodeBuddyModelHeaders } from "@/services/codebuddyModels.js";
|
|
27
28
|
|
|
28
29
|
const OAUTH_TEST_CONFIG = {
|
|
@@ -763,13 +764,21 @@ async function testApiKeyConnection(connection, effectiveProxy = null) {
|
|
|
763
764
|
const valid = res.status !== 401 && res.status !== 403;
|
|
764
765
|
return { valid, error: valid ? null : "Invalid SSO cookie" };
|
|
765
766
|
}
|
|
767
|
+
case "opencode-zen":
|
|
766
768
|
case "opencode-go": {
|
|
767
|
-
const res = await fetchWithConnectionProxy(
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
769
|
+
const res = await fetchWithConnectionProxy(
|
|
770
|
+
connection.provider === "opencode-go" ? "https://opencode.ai/zen/go/v1/models" : "https://opencode.ai/zen/v1/models",
|
|
771
|
+
{
|
|
772
|
+
method: "GET",
|
|
773
|
+
headers: {
|
|
774
|
+
Authorization: `Bearer ${connection.apiKey}`,
|
|
775
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
776
|
+
"x-opencode-client": "desktop",
|
|
777
|
+
},
|
|
778
|
+
},
|
|
779
|
+
effectiveProxy,
|
|
780
|
+
);
|
|
781
|
+
const valid = res.ok;
|
|
773
782
|
return { valid, error: valid ? null : "Invalid API key" };
|
|
774
783
|
}
|
|
775
784
|
case "xiaomi-mimo":
|
|
@@ -8,11 +8,12 @@ export async function GET() {
|
|
|
8
8
|
const providers = REGISTRY.filter((r) => !r.hidden)
|
|
9
9
|
.map((r) => {
|
|
10
10
|
const display = r.display || {};
|
|
11
|
-
const staticModels = ["codebuddy-cn", "codebuddy-intl"].includes(r.id)
|
|
11
|
+
const staticModels = ["codebuddy-cn", "codebuddy-intl", "opencode", "opencode-go"].includes(r.id)
|
|
12
12
|
&& Array.isArray(r.models)
|
|
13
13
|
? r.models.map((model) => ({
|
|
14
14
|
id: model.id,
|
|
15
15
|
name: model.name || model.id,
|
|
16
|
+
...(model.targetFormat ? { targetFormat: model.targetFormat } : {}),
|
|
16
17
|
}))
|
|
17
18
|
: [];
|
|
18
19
|
|
|
@@ -38,6 +39,7 @@ export async function GET() {
|
|
|
38
39
|
...(r.noAuth ? { noAuth: true } : {}),
|
|
39
40
|
...(r.hasOAuth ? { hasOAuth: true } : {}),
|
|
40
41
|
...(r.passthroughModels ? { passthroughModels: true } : {}),
|
|
42
|
+
...(r.modelsFetcher?.url ? { modelsFetcherUrl: r.modelsFetcher.url } : {}),
|
|
41
43
|
...(r.thinkingConfig ? { thinkingConfig: r.thinkingConfig } : {}),
|
|
42
44
|
...(staticModels.length ? { models: staticModels } : {}),
|
|
43
45
|
...(display.color ? { color: display.color } : {}),
|
|
@@ -12,10 +12,15 @@ export const FILTERS = {
|
|
|
12
12
|
.map((m) => ({ id: m.id, name: m.name, contextLength: m.context_length }))
|
|
13
13
|
.sort((a, b) => b.contextLength - a.contextLength),
|
|
14
14
|
|
|
15
|
-
"opencode-free": (models) =>
|
|
15
|
+
"opencode-free": (models) =>
|
|
16
16
|
models
|
|
17
17
|
.filter((m) => m.id?.endsWith("-free") || KNOWN_FREE_OPENCODE_MODELS.includes(m.id))
|
|
18
|
-
.map((m) => ({ id: m.id, name: m.id })),
|
|
18
|
+
.map((m) => ({ id: m.id, name: m.id })),
|
|
19
|
+
|
|
20
|
+
"opencode-all": (models) =>
|
|
21
|
+
models
|
|
22
|
+
.filter((m) => typeof m?.id === "string")
|
|
23
|
+
.map((m) => ({ id: m.id, name: m.name || m.id })),
|
|
19
24
|
|
|
20
25
|
"mimo-free": (models) =>
|
|
21
26
|
(Array.isArray(models) ? models : [])
|
|
@@ -9,6 +9,7 @@ import { normalizeProviderId } from "@/lib/providerNormalization";
|
|
|
9
9
|
import { logRouteError } from "@/lib/errors/publicError";
|
|
10
10
|
import { KiroService } from "@/lib/oauth/services/kiro";
|
|
11
11
|
import { AGENTROUTER_MODELS_URL, AGENTROUTER_OPENAI_HEADERS } from "open-sse/providers/shared.js";
|
|
12
|
+
import { OPENCODE_USER_AGENT } from "open-sse/utils/opencode.js";
|
|
12
13
|
import { resolveCodeBuddyModels } from "@/services/codebuddyModels.js";
|
|
13
14
|
|
|
14
15
|
const VALIDATION_TIMEOUT_MS = 15000;
|
|
@@ -393,18 +394,20 @@ export async function POST(request) {
|
|
|
393
394
|
break;
|
|
394
395
|
}
|
|
395
396
|
|
|
397
|
+
case "opencode-zen":
|
|
396
398
|
case "opencode-go": {
|
|
397
|
-
const res = await fetchWithTimeout(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
399
|
+
const res = await fetchWithTimeout(
|
|
400
|
+
provider === "opencode-go" ? "https://opencode.ai/zen/go/v1/models" : "https://opencode.ai/zen/v1/models",
|
|
401
|
+
{
|
|
402
|
+
method: "GET",
|
|
403
|
+
headers: {
|
|
404
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
405
|
+
"User-Agent": OPENCODE_USER_AGENT,
|
|
406
|
+
"x-opencode-client": "desktop",
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
);
|
|
410
|
+
isValid = res.ok;
|
|
408
411
|
break;
|
|
409
412
|
}
|
|
410
413
|
|
package/src/types/provider.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type ProviderType =
|
|
|
10
10
|
| "groq" | "kilo-gateway" | "kilocode" | "kimchi" | "kimi"
|
|
11
11
|
| "kiro" | "minimax" | "minimax-cn" | "mistral"
|
|
12
12
|
| "morph" | "nebius" | "nvidia" | "ollama" | "ollama-local"
|
|
13
|
-
| "openai" | "opencode" | "opencode-go" | "openrouter" | "perplexity"
|
|
13
|
+
| "openai" | "opencode" | "opencode-zen" | "opencode-go" | "openrouter" | "perplexity"
|
|
14
14
|
| "poolside" | "qoder" | "tencent"
|
|
15
15
|
| "together" | "trae" | "venice" | "vercel-ai-gateway"
|
|
16
16
|
| "sumopod" | "vertex" | "vertex-partner" | "windsurf" | "xai" | "xiaomi-mimo"
|