mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
Fix bug
This commit is contained in:
@@ -96,6 +96,15 @@ export const PROVIDERS = {
|
||||
tokenUrl: "https://iflow.cn/oauth/token",
|
||||
authUrl: "https://iflow.cn/oauth"
|
||||
},
|
||||
qoder: {
|
||||
baseUrl: "https://api.qoder.com/v1/chat/completions",
|
||||
format: "openai",
|
||||
headers: { "User-Agent": "Qoder-Cli" },
|
||||
clientId: process.env.QODER_OAUTH_CLIENT_ID || "10009311001",
|
||||
clientSecret: process.env.QODER_OAUTH_CLIENT_SECRET || "4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW",
|
||||
tokenUrl: "https://api.qoder.com/oauth/token",
|
||||
authUrl: "https://qoder.com/oauth/authorize"
|
||||
},
|
||||
antigravity: {
|
||||
baseUrls: [
|
||||
"https://daily-cloudcode-pa.googleapis.com",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { AntigravityExecutor } from "./antigravity.js";
|
||||
import { GeminiCLIExecutor } from "./gemini-cli.js";
|
||||
import { GithubExecutor } from "./github.js";
|
||||
import { IFlowExecutor } from "./iflow.js";
|
||||
import { QoderExecutor } from "./qoder.js";
|
||||
import { KiroExecutor } from "./kiro.js";
|
||||
import { CodexExecutor } from "./codex.js";
|
||||
import { CursorExecutor } from "./cursor.js";
|
||||
@@ -13,6 +14,7 @@ const executors = {
|
||||
"gemini-cli": new GeminiCLIExecutor(),
|
||||
github: new GithubExecutor(),
|
||||
iflow: new IFlowExecutor(),
|
||||
qoder: new QoderExecutor(),
|
||||
kiro: new KiroExecutor(),
|
||||
codex: new CodexExecutor(),
|
||||
cursor: new CursorExecutor(),
|
||||
@@ -38,6 +40,7 @@ export { AntigravityExecutor } from "./antigravity.js";
|
||||
export { GeminiCLIExecutor } from "./gemini-cli.js";
|
||||
export { GithubExecutor } from "./github.js";
|
||||
export { IFlowExecutor } from "./iflow.js";
|
||||
export { QoderExecutor } from "./qoder.js";
|
||||
export { KiroExecutor } from "./kiro.js";
|
||||
export { CodexExecutor } from "./codex.js";
|
||||
export { CursorExecutor } from "./cursor.js";
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import crypto from "crypto";
|
||||
import { BaseExecutor } from "./base.js";
|
||||
import { PROVIDERS } from "../config/providers.js";
|
||||
|
||||
/**
|
||||
* QoderExecutor - Executor for Qoder API with HMAC-SHA256 signature
|
||||
* Requires 3 custom headers to avoid 406 error: session-id, x-qoder-timestamp, x-qoder-signature
|
||||
*/
|
||||
export class QoderExecutor extends BaseExecutor {
|
||||
constructor() {
|
||||
super("qoder", PROVIDERS.qoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Qoder signature using HMAC-SHA256
|
||||
* Formula: HMAC-SHA256(key=apiKey, message="UserAgent:sessionID:timestamp")
|
||||
*/
|
||||
createSignature(userAgent, sessionID, timestamp, apiKey) {
|
||||
if (!apiKey) return "";
|
||||
const payload = `${userAgent}:${sessionID}:${timestamp}`;
|
||||
const hmac = crypto.createHmac("sha256", apiKey);
|
||||
hmac.update(payload);
|
||||
return hmac.digest("hex");
|
||||
}
|
||||
|
||||
/**
|
||||
* Build headers with Qoder-specific signature
|
||||
*/
|
||||
buildHeaders(credentials, stream = true) {
|
||||
const sessionID = `session-${crypto.randomUUID()}`;
|
||||
const timestamp = Date.now();
|
||||
const userAgent = this.config.headers["User-Agent"] || "Qoder-Cli";
|
||||
const apiKey = credentials.apiKey || credentials.accessToken || "";
|
||||
|
||||
const signature = this.createSignature(userAgent, sessionID, timestamp, apiKey);
|
||||
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
...this.config.headers,
|
||||
"session-id": sessionID,
|
||||
"x-qoder-timestamp": timestamp.toString(),
|
||||
"x-qoder-signature": signature,
|
||||
};
|
||||
|
||||
if (credentials.apiKey) {
|
||||
headers["Authorization"] = `Bearer ${credentials.apiKey}`;
|
||||
} else if (credentials.accessToken) {
|
||||
headers["Authorization"] = `Bearer ${credentials.accessToken}`;
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
headers["Accept"] = "text/event-stream";
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
buildUrl(model, stream, urlIndex = 0, credentials = null) {
|
||||
return this.config.baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject stream_options for usage data on streaming requests
|
||||
*/
|
||||
transformRequest(model, body, stream, credentials) {
|
||||
if (stream && body.messages && !body.stream_options) {
|
||||
body.stream_options = { include_usage: true };
|
||||
}
|
||||
return body;
|
||||
}
|
||||
}
|
||||
|
||||
export default QoderExecutor;
|
||||
Reference in New Issue
Block a user