dsh-qoder-connect 0.2.1 → 0.2.3-alpha.1
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/LICENSE +21 -21
- package/README.en.md +177 -173
- package/README.md +178 -174
- package/cordis.patch.yml +6 -6
- package/lib/bin.js +1 -1
- package/lib/client.js +366 -190
- package/lib/index.d.ts +15 -2
- package/lib/index.js +1 -1
- package/lib/{variants-CjWW4lVI.js → variants-CU8HDUwi.js} +162 -20
- package/package.json +120 -120
package/lib/index.d.ts
CHANGED
|
@@ -773,8 +773,15 @@ interface QoderTransport {
|
|
|
773
773
|
*/
|
|
774
774
|
type QoderEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
775
775
|
/** How the shim should present an upstream failure to its OpenAI client. */
|
|
776
|
-
type UpstreamErrorKind = 'missing_credential' | 'auth' | 'soft_rate' | 'quota_exceeded' | 'server' | 'client';
|
|
777
|
-
/**
|
|
776
|
+
type UpstreamErrorKind = 'missing_credential' | 'auth' | 'soft_rate' | 'quota_exceeded' | 'timeout' | 'server' | 'client';
|
|
777
|
+
/**
|
|
778
|
+
* HTTP status the shim answers each failure kind with.
|
|
779
|
+
*
|
|
780
|
+
* `timeout` is 408 and deliberately not 504: the harness's pi-ai classifier tests
|
|
781
|
+
* `/\b5\d\d\b/` *before* its `timeout` test, so a 5xx status would be read as
|
|
782
|
+
* SERVER no matter what the message says. 408 is also the honest answer for a
|
|
783
|
+
* request the upstream never completed.
|
|
784
|
+
*/
|
|
778
785
|
declare const KIND_STATUS: Readonly<Record<UpstreamErrorKind, number>>;
|
|
779
786
|
/** The chat-completions answer: a streaming `Response`, or a classified failure. */
|
|
780
787
|
type QoderChatResult = {
|
|
@@ -840,6 +847,12 @@ declare function classifyUpstreamError(status: number, body: string): UpstreamEr
|
|
|
840
847
|
* `code: RATE_LIMIT, status: 403` (body carries 10605/isQueued/
|
|
841
848
|
* retryAfterSeconds), and letting the status arm claim it reported a dead
|
|
842
849
|
* credential — which the host never retries — instead of a throttle it would.
|
|
850
|
+
*
|
|
851
|
+
* `QUOTA` and the request family are tested before the auth family for the same
|
|
852
|
+
* reason: both keep the upstream's 401/403 (see `qoderHttpError`), and the status
|
|
853
|
+
* arm would call a spent daily window or a refused request a credential
|
|
854
|
+
* rejection. `status === 402` is tested before the request arm so that a 402 the
|
|
855
|
+
* transport coded `INVALID_REQUEST` (its 4xx fallback) still reads as a quota.
|
|
843
856
|
*/
|
|
844
857
|
declare function kindFromQoderFailure(failure: {
|
|
845
858
|
code: string;
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as QODER_GLOBAL_AUTH_PATH, B as patTail, C as probeModel, D as FALLBACK_QODER_MODELS, E as qoderCatalogPath, F as QODER_STATUS_PATH, G as qoderMachineIdPath, H as qoderOwnAuthPath, I as QODER_AUTH_FILENAME, K as qoderPluginDataDir, L as QODER_PAT_ENV_CN, M as QODER_GLOBAL_STATUS_PATH, N as QODER_PROBE_PATH, O as QoderCatalog, P as QODER_SETTINGS_FACE_PATH, R as QODER_PAT_ENV_GLOBAL, S as PROBE_EFFORT_CANDIDATES, T as QoderCatalogStore, U as QODER_DATA_DIR_ENV, V as qoderCredentialIdentity, W as QODER_DATA_DIR_NAME, _ as modelInfoOf, a as QODER_HOST_HEARTBEAT_FILENAME, b as createQoderTransport, c as processStartTimeMs, d as writeHostHeartbeat, f as QODER_CONNECT_VERSION, g as kindFromQoderFailure, h as classifyUpstreamError, i as variantFor, j as QODER_GLOBAL_PROBE_PATH, k as QODER_AUTH_PATH, l as qoderHostHeartbeatPath, m as QoderUpstreamClient, n as GLOBAL_VARIANT, o as clearHostHeartbeat, p as KIND_STATUS, q as qoderStateDir, r as QODER_VARIANTS, s as isHeartbeatProcessAlive, t as CHINA_VARIANT, u as readHostHeartbeat, v as normalizeCredits, w as randomSentinel, x as getMachineId, y as validateApiKey, z as QoderCredentialStore } from "./variants-
|
|
1
|
+
import { A as QODER_GLOBAL_AUTH_PATH, B as patTail, C as probeModel, D as FALLBACK_QODER_MODELS, E as qoderCatalogPath, F as QODER_STATUS_PATH, G as qoderMachineIdPath, H as qoderOwnAuthPath, I as QODER_AUTH_FILENAME, K as qoderPluginDataDir, L as QODER_PAT_ENV_CN, M as QODER_GLOBAL_STATUS_PATH, N as QODER_PROBE_PATH, O as QoderCatalog, P as QODER_SETTINGS_FACE_PATH, R as QODER_PAT_ENV_GLOBAL, S as PROBE_EFFORT_CANDIDATES, T as QoderCatalogStore, U as QODER_DATA_DIR_ENV, V as qoderCredentialIdentity, W as QODER_DATA_DIR_NAME, _ as modelInfoOf, a as QODER_HOST_HEARTBEAT_FILENAME, b as createQoderTransport, c as processStartTimeMs, d as writeHostHeartbeat, f as QODER_CONNECT_VERSION, g as kindFromQoderFailure, h as classifyUpstreamError, i as variantFor, j as QODER_GLOBAL_PROBE_PATH, k as QODER_AUTH_PATH, l as qoderHostHeartbeatPath, m as QoderUpstreamClient, n as GLOBAL_VARIANT, o as clearHostHeartbeat, p as KIND_STATUS, q as qoderStateDir, r as QODER_VARIANTS, s as isHeartbeatProcessAlive, t as CHINA_VARIANT, u as readHostHeartbeat, v as normalizeCredits, w as randomSentinel, x as getMachineId, y as validateApiKey, z as QoderCredentialStore } from "./variants-CU8HDUwi.js";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -855,6 +855,94 @@ async function probeModel(options) {
|
|
|
855
855
|
};
|
|
856
856
|
}
|
|
857
857
|
//#endregion
|
|
858
|
+
//#region src/qoder/codes.ts
|
|
859
|
+
const table = (family, rows) => rows.map(([code, name]) => ({
|
|
860
|
+
code,
|
|
861
|
+
name,
|
|
862
|
+
family
|
|
863
|
+
}));
|
|
864
|
+
/**
|
|
865
|
+
* The documented code table.
|
|
866
|
+
*
|
|
867
|
+
* Source: Qoder's *Errors and error codes* reference
|
|
868
|
+
* (https://docs.qoder.com/cli/sdk/errors), "Result error codes" — the same
|
|
869
|
+
* reference also states the rule this module exists to serve: "Authentication,
|
|
870
|
+
* quota, policy, input, and configuration errors require a change before
|
|
871
|
+
* retrying."
|
|
872
|
+
*
|
|
873
|
+
* Scope note on evidence. That page documents the Agent SDK / qodercli surface,
|
|
874
|
+
* not the loopback HTTP endpoint this plugin talks to. Two of its codes are
|
|
875
|
+
* confirmed on our own path, with matching semantics:
|
|
876
|
+
*
|
|
877
|
+
* - `10605` — observed verbatim: `{"code":"10605","message":"{\"isQueued\":true,
|
|
878
|
+
* ...\"retryAfterSeconds\":30}"}` (see `qoderQueueSignal`).
|
|
879
|
+
* - `110` — reported in dsh-qoder-connect#10 and reproduced by injecting the
|
|
880
|
+
* reported body through this transport: `{"code":"110","message":"Billing
|
|
881
|
+
* daily count exceeded"}`.
|
|
882
|
+
*
|
|
883
|
+
* The rest are carried as the upstream's documented vocabulary. They are read
|
|
884
|
+
* only to identify the family; an undocumented code is never guessed at, so a
|
|
885
|
+
* body this table does not recognize keeps whatever routing the HTTP status
|
|
886
|
+
* already gives it.
|
|
887
|
+
*/
|
|
888
|
+
const QODER_RESULT_CODES = Object.freeze([
|
|
889
|
+
...table("auth", [["105", "Login or access token expired"]]),
|
|
890
|
+
...table("quota", [
|
|
891
|
+
["110", "Daily usage limit reached"],
|
|
892
|
+
["113", "Usage quota exhausted"],
|
|
893
|
+
["114", "Free-trial account limit reached"],
|
|
894
|
+
["115", "Free-user quota reached"],
|
|
895
|
+
["116", "Team administrator Credits exhausted"],
|
|
896
|
+
["117", "Team member Credits exhausted"],
|
|
897
|
+
["118", "Personal Credits exhausted"],
|
|
898
|
+
["119", "Free usage limit for the selected model reached"],
|
|
899
|
+
["122", "Billing-group Credits limit reached"]
|
|
900
|
+
]),
|
|
901
|
+
...table("request", [
|
|
902
|
+
["406", "Request blocked because of sensitive content or model refusal"],
|
|
903
|
+
["416", "Requested range or request shape is not satisfiable"],
|
|
904
|
+
["430", "Requested capability is not supported"],
|
|
905
|
+
["47902", "Maximum Agent turns reached"],
|
|
906
|
+
["48716", "A Hook blocked Agent execution"],
|
|
907
|
+
["80411", "Input content is too long"],
|
|
908
|
+
["80412", "Too many images or documents"]
|
|
909
|
+
]),
|
|
910
|
+
...table("runtime", [
|
|
911
|
+
["500", "Request or network failure"],
|
|
912
|
+
["10408", "Request timed out"],
|
|
913
|
+
["10500", "Model service internal error"],
|
|
914
|
+
["10605", "Model request is queued"]
|
|
915
|
+
])
|
|
916
|
+
]);
|
|
917
|
+
const byCode = new Map(QODER_RESULT_CODES.map((entry) => [entry.code, entry]));
|
|
918
|
+
/**
|
|
919
|
+
* The documented result code a rejection body names, if it names one.
|
|
920
|
+
*
|
|
921
|
+
* Qoder nests: a queue answer arrives as `{"code":"10605","message":"{\"isQueued\":
|
|
922
|
+
* true,...}"}`, so the inner payload is escaped JSON and a marker can sit at any
|
|
923
|
+
* depth. Dropping the ASCII backslashes keeps every layer readable at once — the
|
|
924
|
+
* same trick `qoderQueueSignal` uses, and for the same reason; no marker this
|
|
925
|
+
* module looks for depends on a backslash.
|
|
926
|
+
*
|
|
927
|
+
* Only a *quoted* `code` key counts. Qoder also mirrors raw HTTP statuses into a
|
|
928
|
+
* `code` field (`"code":"429"`, `"code":403`), and a message that merely mentions
|
|
929
|
+
* a code in prose must not be read as one; both stay unrecognized because neither
|
|
930
|
+
* names a documented result code.
|
|
931
|
+
*
|
|
932
|
+
* @param body - the upstream error body, or the formatted message when the body
|
|
933
|
+
* was only embedded in it.
|
|
934
|
+
* @returns the matching table entry, or `undefined` when the body names no
|
|
935
|
+
* documented code — never a guess.
|
|
936
|
+
*/
|
|
937
|
+
function qoderResultCode(body) {
|
|
938
|
+
if (body === void 0 || body === "") return void 0;
|
|
939
|
+
const text = body.replace(/\\/gu, "");
|
|
940
|
+
for (const match of text.matchAll(/"(?:error_)?code"\s*:\s*"?(\d+)"?/gu)) {
|
|
941
|
+
const entry = byCode.get(match[1]);
|
|
942
|
+
if (entry !== void 0) return entry;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
//#endregion
|
|
858
946
|
//#region src/qoder/errors.ts
|
|
859
947
|
/**
|
|
860
948
|
* DSH-compatible LLM error representation.
|
|
@@ -902,18 +990,25 @@ function qoderQueueSignal(body) {
|
|
|
902
990
|
}
|
|
903
991
|
/**
|
|
904
992
|
* Replace status digits that read as authorization failure with a neutral
|
|
905
|
-
* word, for messages the upstream used to announce a
|
|
993
|
+
* word, for messages the upstream used to announce something other than a dead
|
|
994
|
+
* credential.
|
|
906
995
|
*
|
|
907
996
|
* `dsh-llm-pi-ai`'s error classifier is a text matcher whose first test is
|
|
908
|
-
* `/\b(?:401|403)\b/` — ahead of its 429/rate-limit test
|
|
909
|
-
* carrying those digits classifies AUTH no matter
|
|
910
|
-
* travelling beside it.
|
|
911
|
-
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
997
|
+
* `/\b(?:401|403)\b/` — ahead of its 429/rate-limit test and ahead of every
|
|
998
|
+
* quota test — so any message carrying those digits classifies AUTH no matter
|
|
999
|
+
* the structured code travelling beside it. An answer that is really a
|
|
1000
|
+
* throttle or an exhausted quota must not reach that matcher as-is, or the user
|
|
1001
|
+
* sees "API 密钥无效" for a limit that clears on its own (observed verbatim on
|
|
1002
|
+
* 2026-09-26 23:30 and again at 23:40 for the queue; reproduced 2026-10-08 for
|
|
1003
|
+
* the daily counter reported in #10).
|
|
1004
|
+
*
|
|
1005
|
+
* @param message - the message to neutralize.
|
|
1006
|
+
* @param replacement - the neutral word substituted for the digits. `throttled`
|
|
1007
|
+
* for the queue answer, whose wording users and tests already know; `limited`
|
|
1008
|
+
* for a quota answer, which is not a throttle.
|
|
914
1009
|
*/
|
|
915
|
-
function deauthorizeDigits(message) {
|
|
916
|
-
return message.replace(/\b(?:401|403)\b/gu,
|
|
1010
|
+
function deauthorizeDigits(message, replacement = "throttled") {
|
|
1011
|
+
return message.replace(/\b(?:401|403)\b/gu, replacement);
|
|
917
1012
|
}
|
|
918
1013
|
function qoderHttpError(message, response, body) {
|
|
919
1014
|
const { status } = response;
|
|
@@ -928,6 +1023,15 @@ function qoderHttpError(message, response, body) {
|
|
|
928
1023
|
...requestId === void 0 ? {} : { requestId }
|
|
929
1024
|
});
|
|
930
1025
|
}
|
|
1026
|
+
const documented = qoderResultCode(body ?? message);
|
|
1027
|
+
if (documented?.family === "quota") return new QoderLlmError(deauthorizeDigits(message, "limited"), "QUOTA", {
|
|
1028
|
+
status,
|
|
1029
|
+
...requestId === void 0 ? {} : { requestId }
|
|
1030
|
+
});
|
|
1031
|
+
if (documented?.family === "request" && (status === 401 || status === 403)) return new QoderLlmError(deauthorizeDigits(message, "rejected"), "INVALID_REQUEST", {
|
|
1032
|
+
status,
|
|
1033
|
+
...requestId === void 0 ? {} : { requestId }
|
|
1034
|
+
});
|
|
931
1035
|
return new QoderLlmError(message, status === 401 || status === 403 ? "AUTH" : status === 408 ? "TIMEOUT" : status === 429 ? "RATE_LIMIT" : status >= 500 && status <= 599 ? "SERVER" : status >= 400 && status <= 499 ? "INVALID_REQUEST" : "PROVIDER_ERROR", {
|
|
932
1036
|
status,
|
|
933
1037
|
...headerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: headerRetryAfterMs },
|
|
@@ -939,6 +1043,24 @@ function qoderRequestId(headers) {
|
|
|
939
1043
|
return normalized ? ProviderRequestId(normalized) : void 0;
|
|
940
1044
|
}
|
|
941
1045
|
/**
|
|
1046
|
+
* Codes that keep the upstream's 401/403 status without being credential
|
|
1047
|
+
* rejections, so the status arm of {@link isQoderAuthRejection} must not claim
|
|
1048
|
+
* them.
|
|
1049
|
+
*
|
|
1050
|
+
* `RATE_LIMIT` is the queue answer (code 10605 / isQueued / retryAfterSeconds)
|
|
1051
|
+
* and `QUOTA`/`ACCOUNT_QUOTA` is a spent usage window (#10, e.g. code 110 with
|
|
1052
|
+
* `Billing daily count exceeded`). Both arrive as 401/403 and neither is fixed
|
|
1053
|
+
* by a fresh job token — the queue cannot be jumped and a quota cannot be
|
|
1054
|
+
* exchanged away — so healing either one spends an exchange and suppresses the
|
|
1055
|
+
* retry that would actually help (the queue) or reports a failure notice for a
|
|
1056
|
+
* condition that clears on its own (the quota).
|
|
1057
|
+
*/
|
|
1058
|
+
const NON_AUTH_STATUS_CODES = [
|
|
1059
|
+
"RATE_LIMIT",
|
|
1060
|
+
"QUOTA",
|
|
1061
|
+
"ACCOUNT_QUOTA"
|
|
1062
|
+
];
|
|
1063
|
+
/**
|
|
942
1064
|
* Whether this failure is an upstream authorization rejection worth one
|
|
943
1065
|
* re-auth retry.
|
|
944
1066
|
*
|
|
@@ -949,16 +1071,16 @@ function qoderRequestId(headers) {
|
|
|
949
1071
|
* exchange, so callers clear their credential cache and retry once before
|
|
950
1072
|
* reporting `AUTH` to the user.
|
|
951
1073
|
*
|
|
952
|
-
* A
|
|
953
|
-
* 401/403**:
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
*
|
|
957
|
-
*
|
|
1074
|
+
* A code in {@link NON_AUTH_STATUS_CODES} is never a re-auth candidate, **even
|
|
1075
|
+
* when its status is 401/403**: those answers keep the status while saying the
|
|
1076
|
+
* credential was not the problem. Healing one exchanged job tokens against a
|
|
1077
|
+
* condition no token can change (observed 2026-09-26 for the queue, and again
|
|
1078
|
+
* 2026-10-08 for the daily counter), and by consuming the retry it suppressed
|
|
1079
|
+
* the rate-limit retry that would have ridden out the window.
|
|
958
1080
|
*/
|
|
959
1081
|
function isQoderAuthRejection(error) {
|
|
960
1082
|
if (!(error instanceof LlmError)) return false;
|
|
961
|
-
if (error.code
|
|
1083
|
+
if (NON_AUTH_STATUS_CODES.includes(error.code)) return false;
|
|
962
1084
|
return error.code === "AUTH" || error.failure.status === 401 || error.failure.status === 403;
|
|
963
1085
|
}
|
|
964
1086
|
function retryAfterMs(value, nowMs = Date.now()) {
|
|
@@ -3650,12 +3772,20 @@ function createQoderTransport(options) {
|
|
|
3650
3772
|
*
|
|
3651
3773
|
* @module dsh-qoder-connect/upstream
|
|
3652
3774
|
*/
|
|
3653
|
-
/**
|
|
3775
|
+
/**
|
|
3776
|
+
* HTTP status the shim answers each failure kind with.
|
|
3777
|
+
*
|
|
3778
|
+
* `timeout` is 408 and deliberately not 504: the harness's pi-ai classifier tests
|
|
3779
|
+
* `/\b5\d\d\b/` *before* its `timeout` test, so a 5xx status would be read as
|
|
3780
|
+
* SERVER no matter what the message says. 408 is also the honest answer for a
|
|
3781
|
+
* request the upstream never completed.
|
|
3782
|
+
*/
|
|
3654
3783
|
const KIND_STATUS = {
|
|
3655
3784
|
missing_credential: 401,
|
|
3656
3785
|
auth: 401,
|
|
3657
3786
|
soft_rate: 429,
|
|
3658
3787
|
quota_exceeded: 402,
|
|
3788
|
+
timeout: 408,
|
|
3659
3789
|
server: 502,
|
|
3660
3790
|
client: 400
|
|
3661
3791
|
};
|
|
@@ -3681,6 +3811,9 @@ function normalizeCredits(credits) {
|
|
|
3681
3811
|
function classifyUpstreamError(status, body) {
|
|
3682
3812
|
const lower = body.toLowerCase();
|
|
3683
3813
|
if (qoderQueueSignal(body) !== void 0) return "soft_rate";
|
|
3814
|
+
const documented = qoderResultCode(body);
|
|
3815
|
+
if (documented?.family === "quota") return "quota_exceeded";
|
|
3816
|
+
if (documented?.family === "request") return "client";
|
|
3684
3817
|
if (status === 402) return "quota_exceeded";
|
|
3685
3818
|
if (status === 429) return "soft_rate";
|
|
3686
3819
|
if (status === 401 || status === 403) return "auth";
|
|
@@ -3705,6 +3838,7 @@ function classifyUpstreamError(status, body) {
|
|
|
3705
3838
|
"forbidden",
|
|
3706
3839
|
"not authenticated"
|
|
3707
3840
|
]) if (lower.includes(marker)) return "auth";
|
|
3841
|
+
if (status === 408) return "timeout";
|
|
3708
3842
|
if (status === 0 || status >= 500) return "server";
|
|
3709
3843
|
return "client";
|
|
3710
3844
|
}
|
|
@@ -3720,14 +3854,22 @@ function classifyUpstreamError(status, body) {
|
|
|
3720
3854
|
* `code: RATE_LIMIT, status: 403` (body carries 10605/isQueued/
|
|
3721
3855
|
* retryAfterSeconds), and letting the status arm claim it reported a dead
|
|
3722
3856
|
* credential — which the host never retries — instead of a throttle it would.
|
|
3857
|
+
*
|
|
3858
|
+
* `QUOTA` and the request family are tested before the auth family for the same
|
|
3859
|
+
* reason: both keep the upstream's 401/403 (see `qoderHttpError`), and the status
|
|
3860
|
+
* arm would call a spent daily window or a refused request a credential
|
|
3861
|
+
* rejection. `status === 402` is tested before the request arm so that a 402 the
|
|
3862
|
+
* transport coded `INVALID_REQUEST` (its 4xx fallback) still reads as a quota.
|
|
3723
3863
|
*/
|
|
3724
3864
|
function kindFromQoderFailure(failure) {
|
|
3725
3865
|
if (failure.code === "MISSING_CREDENTIAL") return "missing_credential";
|
|
3726
3866
|
if (failure.code === "RATE_LIMIT") return "soft_rate";
|
|
3867
|
+
if (failure.code === "QUOTA" || failure.code === "ACCOUNT_QUOTA") return "quota_exceeded";
|
|
3868
|
+
if (failure.status === 402) return "quota_exceeded";
|
|
3869
|
+
if (failure.code.startsWith("INVALID_") || failure.code.startsWith("UNSUPPORTED_") || failure.code === "ATTACHMENT") return "client";
|
|
3727
3870
|
if (failure.code === "AUTH" || failure.status === 401 || failure.status === 403) return "auth";
|
|
3728
3871
|
if (failure.status === 429) return "soft_rate";
|
|
3729
|
-
if (failure.code === "
|
|
3730
|
-
if (failure.code.startsWith("INVALID_") || failure.code.startsWith("UNSUPPORTED_") || failure.code === "ATTACHMENT") return "client";
|
|
3872
|
+
if (failure.code === "TIMEOUT") return "timeout";
|
|
3731
3873
|
return "server";
|
|
3732
3874
|
}
|
|
3733
3875
|
/** Whether a Personal Access Token works against one region's endpoints. */
|
|
@@ -4445,7 +4587,7 @@ const DEFAULT_MAX_TOKENS = 32768;
|
|
|
4445
4587
|
const DEFAULT_CONTEXT_WINDOW = 18e4;
|
|
4446
4588
|
//#endregion
|
|
4447
4589
|
//#region src/version.ts
|
|
4448
|
-
const QODER_CONNECT_VERSION = "0.2.1";
|
|
4590
|
+
const QODER_CONNECT_VERSION = "0.2.3-alpha.1";
|
|
4449
4591
|
//#endregion
|
|
4450
4592
|
//#region src/host-heartbeat.ts
|
|
4451
4593
|
/**
|
package/package.json
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dsh-qoder-connect",
|
|
3
|
-
"displayName": "DSH Qoder Connect",
|
|
4
|
-
"description": "将 Qoder(国内版 / 国际版)的模型接入 DeepSeek Harness — bring Qoder (CN & international) models into DeepSeek Harness.",
|
|
5
|
-
"version": "0.2.1",
|
|
6
|
-
"author": "corrinehu",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"dsh-plugin",
|
|
9
|
-
"deepseek-harness",
|
|
10
|
-
"deepseek",
|
|
11
|
-
"qoder",
|
|
12
|
-
"model-provider"
|
|
13
|
-
],
|
|
14
|
-
"type": "module",
|
|
15
|
-
"engines": {
|
|
16
|
-
"dsh": ">=0.1.7-rc.1",
|
|
17
|
-
"node": "^22.19.0 || >=24.0.0"
|
|
18
|
-
},
|
|
19
|
-
"main": "lib/index.js",
|
|
20
|
-
"types": "lib/index.d.ts",
|
|
21
|
-
"bin": {
|
|
22
|
-
"dsh-qoder-connect": "lib/bin.js"
|
|
23
|
-
},
|
|
24
|
-
"scripts": {
|
|
25
|
-
"prepack": "npm run build",
|
|
26
|
-
"build": "tsdown",
|
|
27
|
-
"test": "node -r ./tests/sandbox-shim.cjs ./node_modules/vitest/vitest.mjs run",
|
|
28
|
-
"test:qoder": "node --test --test-isolation=none --experimental-strip-types tests/qoder/*.test.ts",
|
|
29
|
-
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.client.json",
|
|
30
|
-
"check": "pnpm run typecheck && pnpm run test && pnpm run test:qoder && pnpm run build"
|
|
31
|
-
},
|
|
32
|
-
"exports": {
|
|
33
|
-
".": {
|
|
34
|
-
"types": "./lib/index.d.ts",
|
|
35
|
-
"default": "./lib/index.js"
|
|
36
|
-
},
|
|
37
|
-
"./client": "./lib/client.js",
|
|
38
|
-
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
39
|
-
"./package.json": "./package.json",
|
|
40
|
-
"./locale/*.json": "./locale/*.json"
|
|
41
|
-
},
|
|
42
|
-
"files": [
|
|
43
|
-
"lib",
|
|
44
|
-
"assets",
|
|
45
|
-
"cordis.patch.yml",
|
|
46
|
-
"README.md",
|
|
47
|
-
"README.en.md",
|
|
48
|
-
"LICENSE",
|
|
49
|
-
"locale/*.json"
|
|
50
|
-
],
|
|
51
|
-
"license": "MIT",
|
|
52
|
-
"repository": {
|
|
53
|
-
"type": "git",
|
|
54
|
-
"url": "git+https://github.com/masknull/dsh-qoder-connect.git"
|
|
55
|
-
},
|
|
56
|
-
"homepage": "https://github.com/masknull/dsh-qoder-connect#readme",
|
|
57
|
-
"bugs": "https://github.com/masknull/dsh-qoder-connect/issues",
|
|
58
|
-
"dsh": {
|
|
59
|
-
"bundle": {
|
|
60
|
-
"patch": "./cordis.patch.yml"
|
|
61
|
-
},
|
|
62
|
-
"client": {
|
|
63
|
-
"inject": [
|
|
64
|
-
"@deepseek-ai/dsh-api-remotes",
|
|
65
|
-
"@deepseek-ai/dsh-api-session-controller",
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-renderer",
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
68
|
-
"@deepseek-ai/dsh-client-ui-settings",
|
|
69
|
-
"@deepseek-ai/dsh-client-ui-conversation",
|
|
70
|
-
"@deepseek-ai/dsh-client-ui-model-selection",
|
|
71
|
-
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
72
|
-
"@deepseek-ai/dsh-client-locale"
|
|
73
|
-
],
|
|
74
|
-
"platform": "web"
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
"peerDependencies": {
|
|
78
|
-
"@deepseek-ai/cordis": "^4.0.2",
|
|
79
|
-
"@deepseek-ai/dsh-atomic-write": ">=0.1.7-rc.1",
|
|
80
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.1",
|
|
81
|
-
"@deepseek-ai/dsh-home-paths": ">=0.1.7-rc.1",
|
|
82
|
-
"@deepseek-ai/dsh-host-webserver": ">=0.1.7-rc.1",
|
|
83
|
-
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.1",
|
|
84
|
-
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.7-rc.1",
|
|
85
|
-
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.1",
|
|
86
|
-
"@deepseek-ai/schemastery": "^3.18.2",
|
|
87
|
-
"@earendil-works/pi-ai": "
|
|
88
|
-
"react": "^18.2.0"
|
|
89
|
-
},
|
|
90
|
-
"devDependencies": {
|
|
91
|
-
"@deepseek-ai/cordis": "^4.0.2",
|
|
92
|
-
"@deepseek-ai/dsh-atomic-write": ">=0.1.7-rc.1",
|
|
93
|
-
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.1",
|
|
94
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.1",
|
|
95
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.7-rc.1",
|
|
96
|
-
"@deepseek-ai/dsh-client-ui-model-selection": ">=0.1.7-rc.1",
|
|
97
|
-
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.7-rc.1",
|
|
98
|
-
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.7-rc.1",
|
|
99
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins": ">=0.1.7-rc.1",
|
|
100
|
-
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.7-rc.1",
|
|
101
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.1",
|
|
102
|
-
"@deepseek-ai/dsh-credentials": ">=0.1.7-rc.1",
|
|
103
|
-
"@deepseek-ai/dsh-home-paths": ">=0.1.7-rc.1",
|
|
104
|
-
"@deepseek-ai/dsh-host-webserver": ">=0.1.7-rc.1",
|
|
105
|
-
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.1",
|
|
106
|
-
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.7-rc.1",
|
|
107
|
-
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.1",
|
|
108
|
-
"@deepseek-ai/schemastery": "^3.18.2",
|
|
109
|
-
"@earendil-works/pi-ai": "
|
|
110
|
-
"@types/node": "^22.20.0",
|
|
111
|
-
"@types/react": "~18.3.1",
|
|
112
|
-
"@types/react-test-renderer": "^18.3.1",
|
|
113
|
-
"react": "^18.2.0",
|
|
114
|
-
"react-test-renderer": "18.3.1",
|
|
115
|
-
"tsdown": "^0.22.2",
|
|
116
|
-
"typescript": "^5.9.3",
|
|
117
|
-
"vitest": "^4.1.8"
|
|
118
|
-
},
|
|
119
|
-
"icon": "./assets/icon.svg"
|
|
120
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-qoder-connect",
|
|
3
|
+
"displayName": "DSH Qoder Connect",
|
|
4
|
+
"description": "将 Qoder(国内版 / 国际版)的模型接入 DeepSeek Harness — bring Qoder (CN & international) models into DeepSeek Harness.",
|
|
5
|
+
"version": "0.2.3-alpha.1",
|
|
6
|
+
"author": "corrinehu",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"dsh-plugin",
|
|
9
|
+
"deepseek-harness",
|
|
10
|
+
"deepseek",
|
|
11
|
+
"qoder",
|
|
12
|
+
"model-provider"
|
|
13
|
+
],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"engines": {
|
|
16
|
+
"dsh": ">=0.1.7-rc.1",
|
|
17
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
18
|
+
},
|
|
19
|
+
"main": "lib/index.js",
|
|
20
|
+
"types": "lib/index.d.ts",
|
|
21
|
+
"bin": {
|
|
22
|
+
"dsh-qoder-connect": "lib/bin.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"prepack": "npm run build",
|
|
26
|
+
"build": "tsdown",
|
|
27
|
+
"test": "node -r ./tests/sandbox-shim.cjs ./node_modules/vitest/vitest.mjs run",
|
|
28
|
+
"test:qoder": "node --test --test-isolation=none --experimental-strip-types tests/qoder/*.test.ts",
|
|
29
|
+
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.client.json",
|
|
30
|
+
"check": "pnpm run typecheck && pnpm run test && pnpm run test:qoder && pnpm run build"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./lib/index.d.ts",
|
|
35
|
+
"default": "./lib/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./client": "./lib/client.js",
|
|
38
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
39
|
+
"./package.json": "./package.json",
|
|
40
|
+
"./locale/*.json": "./locale/*.json"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"lib",
|
|
44
|
+
"assets",
|
|
45
|
+
"cordis.patch.yml",
|
|
46
|
+
"README.md",
|
|
47
|
+
"README.en.md",
|
|
48
|
+
"LICENSE",
|
|
49
|
+
"locale/*.json"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/masknull/dsh-qoder-connect.git"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/masknull/dsh-qoder-connect#readme",
|
|
57
|
+
"bugs": "https://github.com/masknull/dsh-qoder-connect/issues",
|
|
58
|
+
"dsh": {
|
|
59
|
+
"bundle": {
|
|
60
|
+
"patch": "./cordis.patch.yml"
|
|
61
|
+
},
|
|
62
|
+
"client": {
|
|
63
|
+
"inject": [
|
|
64
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
65
|
+
"@deepseek-ai/dsh-api-session-controller",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-model-selection",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-sidebar",
|
|
72
|
+
"@deepseek-ai/dsh-client-locale"
|
|
73
|
+
],
|
|
74
|
+
"platform": "web"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
79
|
+
"@deepseek-ai/dsh-atomic-write": ">=0.1.7-rc.1",
|
|
80
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.1",
|
|
81
|
+
"@deepseek-ai/dsh-home-paths": ">=0.1.7-rc.1",
|
|
82
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.7-rc.1",
|
|
83
|
+
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.1",
|
|
84
|
+
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.7-rc.1",
|
|
85
|
+
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.1",
|
|
86
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
87
|
+
"@earendil-works/pi-ai": ">=0.85.1",
|
|
88
|
+
"react": "^18.2.0"
|
|
89
|
+
},
|
|
90
|
+
"devDependencies": {
|
|
91
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
92
|
+
"@deepseek-ai/dsh-atomic-write": ">=0.1.7-rc.1",
|
|
93
|
+
"@deepseek-ai/dsh-attachment": ">=0.1.7-rc.1",
|
|
94
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.7-rc.1",
|
|
95
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.7-rc.1",
|
|
96
|
+
"@deepseek-ai/dsh-client-ui-model-selection": ">=0.1.7-rc.1",
|
|
97
|
+
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.7-rc.1",
|
|
98
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.7-rc.1",
|
|
99
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins": ">=0.1.7-rc.1",
|
|
100
|
+
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.7-rc.1",
|
|
101
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.7-rc.1",
|
|
102
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.7-rc.1",
|
|
103
|
+
"@deepseek-ai/dsh-home-paths": ">=0.1.7-rc.1",
|
|
104
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.7-rc.1",
|
|
105
|
+
"@deepseek-ai/dsh-llm": ">=0.1.7-rc.1",
|
|
106
|
+
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.7-rc.1",
|
|
107
|
+
"@deepseek-ai/dsh-settings": ">=0.1.7-rc.1",
|
|
108
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
109
|
+
"@earendil-works/pi-ai": ">=0.85.1",
|
|
110
|
+
"@types/node": "^22.20.0",
|
|
111
|
+
"@types/react": "~18.3.1",
|
|
112
|
+
"@types/react-test-renderer": "^18.3.1",
|
|
113
|
+
"react": "^18.2.0",
|
|
114
|
+
"react-test-renderer": "18.3.1",
|
|
115
|
+
"tsdown": "^0.22.2",
|
|
116
|
+
"typescript": "^5.9.3",
|
|
117
|
+
"vitest": "^4.1.8"
|
|
118
|
+
},
|
|
119
|
+
"icon": "./assets/icon.svg"
|
|
120
|
+
}
|