@pentoshi/clai 4.13.0 → 4.14.0
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/CONTRIBUTING.md +6 -3
- package/PROVIDERS.md +2 -0
- package/README.md +8 -4
- package/dist/agent/stream-recovery.d.ts +1 -1
- package/dist/agent/stream-recovery.js +5 -1
- package/dist/agent/stream-recovery.js.map +1 -1
- package/dist/classic/bootstrap/runtime-view.d.ts +6 -0
- package/dist/classic/bootstrap/runtime-view.js +46 -0
- package/dist/classic/bootstrap/runtime-view.js.map +1 -0
- package/dist/classic/bootstrap/terminal-session.d.ts +3 -0
- package/dist/classic/bootstrap/terminal-session.js +3 -0
- package/dist/classic/bootstrap/terminal-session.js.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/interactive-session/transport-node-pty.js +3 -5
- package/dist/interactive-session/transport-node-pty.js.map +1 -1
- package/dist/llm/http.d.ts +2 -1
- package/dist/llm/http.js +3 -1
- package/dist/llm/http.js.map +1 -1
- package/dist/llm/provider-info-text.js +7 -0
- package/dist/llm/provider-info-text.js.map +1 -1
- package/dist/llm/qoder/qoder-catalog.d.ts +15 -0
- package/dist/llm/qoder/qoder-catalog.js +56 -0
- package/dist/llm/qoder/qoder-catalog.js.map +1 -0
- package/dist/llm/qoder/qoder-http.d.ts +13 -0
- package/dist/llm/qoder/qoder-http.js +55 -0
- package/dist/llm/qoder/qoder-http.js.map +1 -0
- package/dist/llm/qoder/qoder-queue.d.ts +15 -0
- package/dist/llm/qoder/qoder-queue.js +169 -0
- package/dist/llm/qoder/qoder-queue.js.map +1 -0
- package/dist/llm/qoder/qoder-response.d.ts +19 -0
- package/dist/llm/qoder/qoder-response.js +98 -0
- package/dist/llm/qoder/qoder-response.js.map +1 -0
- package/dist/llm/qoder/qoder-stream.d.ts +23 -0
- package/dist/llm/qoder/qoder-stream.js +75 -0
- package/dist/llm/qoder/qoder-stream.js.map +1 -0
- package/dist/llm/qoder/qoder.d.ts +4 -4
- package/dist/llm/qoder/qoder.js +71 -189
- package/dist/llm/qoder/qoder.js.map +1 -1
- package/dist/llm/routing/error-classification.js +2 -0
- package/dist/llm/routing/error-classification.js.map +1 -1
- package/dist/llm/routing/failure-report.d.ts +1 -1
- package/dist/llm/routing/failure-report.js +5 -3
- package/dist/llm/routing/failure-report.js.map +1 -1
- package/dist/llm/wire/response-errors.d.ts +1 -0
- package/dist/llm/wire/response-errors.js +1 -1
- package/dist/llm/wire/response-errors.js.map +1 -1
- package/dist/session-runtime/child-bridge.d.ts +10 -4
- package/dist/session-runtime/child-bridge.js +34 -6
- package/dist/session-runtime/child-bridge.js.map +1 -1
- package/dist/session-runtime/client.d.ts +3 -2
- package/dist/session-runtime/client.js +22 -9
- package/dist/session-runtime/client.js.map +1 -1
- package/dist/session-runtime/host.d.ts +4 -0
- package/dist/session-runtime/host.js +108 -16
- package/dist/session-runtime/host.js.map +1 -1
- package/dist/session-runtime/launch.d.ts +1 -0
- package/dist/session-runtime/launch.js +3 -1
- package/dist/session-runtime/launch.js.map +1 -1
- package/dist/session-runtime/start-runtime.d.ts +12 -0
- package/dist/session-runtime/start-runtime.js +69 -0
- package/dist/session-runtime/start-runtime.js.map +1 -0
- package/dist/session-runtime/store.js +1 -0
- package/dist/session-runtime/store.js.map +1 -1
- package/dist/session-runtime/terminal-options.d.ts +4 -0
- package/dist/session-runtime/terminal-options.js +49 -0
- package/dist/session-runtime/terminal-options.js.map +1 -0
- package/dist/session-runtime/types.d.ts +38 -1
- package/dist/session-runtime/view-manager.d.ts +38 -0
- package/dist/session-runtime/view-manager.js +189 -0
- package/dist/session-runtime/view-manager.js.map +1 -0
- package/dist/session-runtime/view-services.d.ts +14 -0
- package/dist/session-runtime/view-services.js +83 -0
- package/dist/session-runtime/view-services.js.map +1 -0
- package/dist/session-runtime/view-terminal.d.ts +29 -0
- package/dist/session-runtime/view-terminal.js +51 -0
- package/dist/session-runtime/view-terminal.js.map +1 -0
- package/dist/tui-v2/bootstrap/runtime-view.d.ts +6 -0
- package/dist/tui-v2/bootstrap/runtime-view.js +54 -0
- package/dist/tui-v2/bootstrap/runtime-view.js.map +1 -0
- package/dist/ui-core/bootstrap/composition-root.d.ts +4 -1
- package/dist/ui-core/bootstrap/composition-root.js +5 -4
- package/dist/ui-core/bootstrap/composition-root.js.map +1 -1
- package/dist/ui-core/commands/session-commands.js +1 -1
- package/dist/ui-core/commands/session-commands.js.map +1 -1
- package/dist/ui-core/state/transcript-store.d.ts +7 -0
- package/dist/ui-core/state/transcript-store.js +53 -0
- package/dist/ui-core/state/transcript-store.js.map +1 -1
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +3 -2
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ProviderError } from "../http.js";
|
|
2
|
+
import { readBodyCapped } from "../wire/response-errors.js";
|
|
3
|
+
import { asRecord, pickString } from "./qoder-auth.js";
|
|
4
|
+
import { readQoderResponseBody } from "./qoder-http.js";
|
|
5
|
+
import { qoderResponseError } from "./qoder-response.js";
|
|
6
|
+
const MAX_CATALOG_BYTES = 4 * 1024 * 1024;
|
|
7
|
+
function finiteNumber(value) {
|
|
8
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
function parseCatalogEntry(value) {
|
|
11
|
+
const entry = asRecord(value);
|
|
12
|
+
const key = entry && pickString(entry, "key");
|
|
13
|
+
if (!entry || !key)
|
|
14
|
+
return undefined;
|
|
15
|
+
const thinking = asRecord(entry.thinking_config);
|
|
16
|
+
const enabled = asRecord(thinking?.enabled);
|
|
17
|
+
const efforts = asRecord(enabled?.efforts);
|
|
18
|
+
return {
|
|
19
|
+
key,
|
|
20
|
+
display_name: pickString(entry, "display_name"),
|
|
21
|
+
is_reasoning: entry.is_reasoning === true,
|
|
22
|
+
is_vl: entry.is_vl === true,
|
|
23
|
+
is_free: entry.is_free === true,
|
|
24
|
+
price_factor: finiteNumber(entry.price_factor),
|
|
25
|
+
max_input_tokens: finiteNumber(entry.max_input_tokens),
|
|
26
|
+
...(efforts ? { thinking_config: { enabled: { efforts } } } : {}),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export async function readQoderModelCatalog(response, signal) {
|
|
30
|
+
if (!response.ok)
|
|
31
|
+
throw qoderResponseError(response.status, await readQoderResponseBody(response, signal));
|
|
32
|
+
const raw = await readBodyCapped(response, MAX_CATALOG_BYTES + 1, signal);
|
|
33
|
+
if (Buffer.byteLength(raw, "utf8") > MAX_CATALOG_BYTES) {
|
|
34
|
+
await response.body?.cancel().catch(() => undefined);
|
|
35
|
+
throw new ProviderError("Qoder model catalog exceeded the 4 MiB response limit.", 502);
|
|
36
|
+
}
|
|
37
|
+
let payload;
|
|
38
|
+
try {
|
|
39
|
+
payload = JSON.parse(raw);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new ProviderError("Qoder returned malformed model catalog JSON.", 502, raw.slice(0, 2000));
|
|
43
|
+
}
|
|
44
|
+
const chat = asRecord(payload)?.chat;
|
|
45
|
+
if (!Array.isArray(chat)) {
|
|
46
|
+
throw new ProviderError("Qoder returned an invalid model catalog: expected a chat array.", 502, raw.slice(0, 2000));
|
|
47
|
+
}
|
|
48
|
+
const entries = [];
|
|
49
|
+
for (const value of chat) {
|
|
50
|
+
const entry = parseCatalogEntry(value);
|
|
51
|
+
if (entry)
|
|
52
|
+
entries.push(entry);
|
|
53
|
+
}
|
|
54
|
+
return entries;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=qoder-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qoder-catalog.js","sourceRoot":"","sources":["../../../src/llm/qoder/qoder-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { QoderCredential } from "./qoder-credential.js";
|
|
2
|
+
export declare function qoderTransportHeaders(credential: QoderCredential, signedHeaders: Record<string, string>): Record<string, string>;
|
|
3
|
+
export declare function qoderRequestSignal(signal?: AbortSignal, timeoutMs?: number): AbortSignal;
|
|
4
|
+
export declare function readQoderResponseBody(response: Response, signal?: AbortSignal): Promise<string>;
|
|
5
|
+
export declare function fetchQoderInference(url: string, init: RequestInit): Promise<Response>;
|
|
6
|
+
export declare function fetchSignedQoderRequest(credential: QoderCredential, request: {
|
|
7
|
+
endpoint: string;
|
|
8
|
+
path: string;
|
|
9
|
+
method: "GET" | "POST";
|
|
10
|
+
body?: string | undefined;
|
|
11
|
+
headers?: Record<string, string> | undefined;
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
}): Promise<Response>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { hostname } from "node:os";
|
|
2
|
+
import { readBodyCapped } from "../wire/response-errors.js";
|
|
3
|
+
import { QODER_CLI_VERSION } from "./qoder-auth.js";
|
|
4
|
+
import { QoderSigner } from "./qoder-signer.js";
|
|
5
|
+
export function qoderTransportHeaders(credential, signedHeaders) {
|
|
6
|
+
const headers = {
|
|
7
|
+
...signedHeaders,
|
|
8
|
+
"Cosy-MachineToken": credential.machineToken,
|
|
9
|
+
...(credential.machineType ? { "Cosy-MachineType": credential.machineType } : {}),
|
|
10
|
+
"Cosy-MachineHostname": hostname(),
|
|
11
|
+
};
|
|
12
|
+
for (const key of Object.keys(headers)) {
|
|
13
|
+
if (["connection", "cache-control", "accept-encoding", "content-length"].includes(key.toLowerCase()))
|
|
14
|
+
delete headers[key];
|
|
15
|
+
}
|
|
16
|
+
return headers;
|
|
17
|
+
}
|
|
18
|
+
export function qoderRequestSignal(signal, timeoutMs = 30_000) {
|
|
19
|
+
const timeout = AbortSignal.timeout(Math.max(1, Math.ceil(timeoutMs)));
|
|
20
|
+
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
21
|
+
}
|
|
22
|
+
export async function readQoderResponseBody(response, signal) {
|
|
23
|
+
return readBodyCapped(response, 65_536, signal);
|
|
24
|
+
}
|
|
25
|
+
export async function fetchQoderInference(url, init) {
|
|
26
|
+
init.signal?.throwIfAborted();
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
const signal = init.signal ? AbortSignal.any([init.signal, controller.signal]) : controller.signal;
|
|
29
|
+
const timer = setTimeout(() => controller.abort(new DOMException("Qoder request timed out before any response.", "TimeoutError")), 30_000);
|
|
30
|
+
try {
|
|
31
|
+
return await fetch(url, { ...init, signal });
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export async function fetchSignedQoderRequest(credential, request) {
|
|
38
|
+
request.signal.throwIfAborted();
|
|
39
|
+
const signer = await QoderSigner.create({ machineId: credential.machineId, cosyVersion: QODER_CLI_VERSION, userInfo: credential });
|
|
40
|
+
try {
|
|
41
|
+
const signed = signer.prepare({ ...request, authType: "auth" });
|
|
42
|
+
const url = signed.url.startsWith("http") ? signed.url : `${request.endpoint}${signed.url}`;
|
|
43
|
+
const body = signed.body ?? request.body;
|
|
44
|
+
return await fetch(url, {
|
|
45
|
+
method: request.method,
|
|
46
|
+
headers: { ...qoderTransportHeaders(credential, signed.headers), ...request.headers },
|
|
47
|
+
...(body !== undefined ? { body } : {}),
|
|
48
|
+
signal: request.signal,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
signer.free();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=qoder-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qoder-http.js","sourceRoot":"","sources":["../../../src/llm/qoder/qoder-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ProviderAuth } from "../provider.js";
|
|
2
|
+
import { type QoderCredential } from "./qoder-credential.js";
|
|
3
|
+
export interface QoderRequestIdentity {
|
|
4
|
+
requestId: string;
|
|
5
|
+
requestSetId: string;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function withQoderModelQueue<T>(options: {
|
|
9
|
+
auth: ProviderAuth;
|
|
10
|
+
modelKey: string;
|
|
11
|
+
run: (credential: QoderCredential, identity: QoderRequestIdentity) => Promise<T>;
|
|
12
|
+
canRetry: () => boolean;
|
|
13
|
+
signal?: AbortSignal | undefined;
|
|
14
|
+
onStatus?: ((message: string) => void) | undefined;
|
|
15
|
+
}): Promise<T>;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { ProviderError } from "../http.js";
|
|
2
|
+
import { currentSessionAffinity } from "../session-affinity.js";
|
|
3
|
+
import { sessionCacheAffinityKey } from "../cache-affinity.js";
|
|
4
|
+
import { QODER_INFERENCE_ORIGIN } from "./qoder-auth.js";
|
|
5
|
+
import { parseQoderCredential } from "./qoder-credential.js";
|
|
6
|
+
import { fetchSignedQoderRequest, qoderRequestSignal, readQoderResponseBody } from "./qoder-http.js";
|
|
7
|
+
import { withQoderCredential } from "./qoder-refresh.js";
|
|
8
|
+
import { parseQoderQueueStatus, QoderModelQueuedError, qoderResponseError } from "./qoder-response.js";
|
|
9
|
+
function requestIdentity() {
|
|
10
|
+
const affinity = currentSessionAffinity();
|
|
11
|
+
const key = affinity ? sessionCacheAffinityKey(affinity).slice(5, 37) : undefined;
|
|
12
|
+
const sessionId = key
|
|
13
|
+
? `${key.slice(0, 8)}-${key.slice(8, 12)}-5${key.slice(13, 16)}-8${key.slice(17, 20)}-${key.slice(20)}`
|
|
14
|
+
: crypto.randomUUID();
|
|
15
|
+
return { requestId: crypto.randomUUID(), requestSetId: crypto.randomUUID(), sessionId };
|
|
16
|
+
}
|
|
17
|
+
function queueWaitLimitMs() {
|
|
18
|
+
const value = Number(process.env.QODER_MODEL_QUEUE_MAX_WAIT_MS);
|
|
19
|
+
return Number.isFinite(value) && value > 0 ? value : 3_600_000;
|
|
20
|
+
}
|
|
21
|
+
function pollDelayMs(status) {
|
|
22
|
+
return Math.min(30_000, Math.max(500, (status.retryAfterSeconds ?? 30) * 1000));
|
|
23
|
+
}
|
|
24
|
+
async function wait(ms, signal) {
|
|
25
|
+
signal?.throwIfAborted();
|
|
26
|
+
if (ms <= 0)
|
|
27
|
+
return;
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
const abort = () => {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
signal?.removeEventListener("abort", abort);
|
|
32
|
+
reject(signal?.reason ?? new DOMException("Qoder queue wait cancelled", "AbortError"));
|
|
33
|
+
};
|
|
34
|
+
const timer = setTimeout(() => {
|
|
35
|
+
signal?.removeEventListener("abort", abort);
|
|
36
|
+
resolve();
|
|
37
|
+
}, ms);
|
|
38
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function queueEnded(message, body) {
|
|
42
|
+
return new ProviderError(`Qoder model queue ${message}. Retry later or choose another model with /model.`, undefined, body, undefined, false);
|
|
43
|
+
}
|
|
44
|
+
async function checkQueue(options, status) {
|
|
45
|
+
const query = new URLSearchParams({ requestSetId: options.identity.requestSetId, modelKey: status.modelKey ?? options.modelKey });
|
|
46
|
+
if (status.queueType)
|
|
47
|
+
query.set("queueType", status.queueType);
|
|
48
|
+
return withQoderCredential(options.auth, async (credential) => {
|
|
49
|
+
const signal = qoderRequestSignal(options.signal, Math.min(30_000, options.deadline - Date.now()));
|
|
50
|
+
const response = await fetchSignedQoderRequest(credential, {
|
|
51
|
+
endpoint: QODER_INFERENCE_ORIGIN,
|
|
52
|
+
path: `/api/v2/service/ask/queue/status?${query}`,
|
|
53
|
+
method: "GET",
|
|
54
|
+
headers: { Accept: "application/json", "X-Request-ID": options.identity.requestId, "X-Session-ID": options.identity.sessionId },
|
|
55
|
+
signal,
|
|
56
|
+
});
|
|
57
|
+
const raw = await readQoderResponseBody(response, signal);
|
|
58
|
+
if (!response.ok)
|
|
59
|
+
throw qoderResponseError(response.status, raw);
|
|
60
|
+
const queue = parseQoderQueueStatus(raw);
|
|
61
|
+
if (!queue)
|
|
62
|
+
throw queueEnded("status response is invalid", raw);
|
|
63
|
+
return queue;
|
|
64
|
+
}, options.onStatus, () => !options.signal?.aborted);
|
|
65
|
+
}
|
|
66
|
+
function checkWaitLimit(options, body) {
|
|
67
|
+
options.signal?.throwIfAborted();
|
|
68
|
+
if (Date.now() >= options.deadline)
|
|
69
|
+
throw queueEnded(`wait limit reached after ${Math.ceil(options.maxWaitMs / 1000)}s`, body);
|
|
70
|
+
}
|
|
71
|
+
function queuedStatusMessage(status, modelKey) {
|
|
72
|
+
const count = status.queueCount === undefined ? "" : `; ${status.queueCount} ahead`;
|
|
73
|
+
return `ℹ Qoder ${modelKey} request queued${count} — checking again in ${Math.ceil(pollDelayMs(status) / 1000)}s`;
|
|
74
|
+
}
|
|
75
|
+
async function waitForQueue(options, initial) {
|
|
76
|
+
let status = initial.queue;
|
|
77
|
+
let firstPoll = true;
|
|
78
|
+
let failures = 0;
|
|
79
|
+
for (;;) {
|
|
80
|
+
checkWaitLimit(options, initial.body ?? "");
|
|
81
|
+
options.onStatus?.(queuedStatusMessage(status, options.modelKey));
|
|
82
|
+
if (!firstPoll)
|
|
83
|
+
await wait(Math.min(pollDelayMs(status), options.deadline - Date.now()), options.signal);
|
|
84
|
+
firstPoll = false;
|
|
85
|
+
checkWaitLimit(options, initial.body ?? "");
|
|
86
|
+
try {
|
|
87
|
+
status = await checkQueue(options, status);
|
|
88
|
+
failures = 0;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
checkWaitLimit(options, initial.body ?? "");
|
|
92
|
+
if (error instanceof ProviderError && (error.status === 401 || error.status === 403))
|
|
93
|
+
throw error;
|
|
94
|
+
if (error instanceof ProviderError && error.status === 404)
|
|
95
|
+
throw queueEnded("status endpoint is not available", error.body);
|
|
96
|
+
if (++failures >= 3)
|
|
97
|
+
throw queueEnded("status polling failed after 3 checks", error instanceof ProviderError ? error.body : undefined);
|
|
98
|
+
options.onStatus?.(`ℹ Qoder queue status check failed — retrying in 30s (${failures}/3)`);
|
|
99
|
+
status = { ...status, retryAfterSeconds: undefined };
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
checkWaitLimit(options, initial.body ?? "");
|
|
103
|
+
if (status.isQueued === false) {
|
|
104
|
+
const readyDelay = status.retryAfterSeconds && status.retryAfterSeconds > 0 ? pollDelayMs(status) : 0;
|
|
105
|
+
await wait(Math.min(readyDelay, options.deadline - Date.now()), options.signal);
|
|
106
|
+
checkWaitLimit(options, initial.body ?? "");
|
|
107
|
+
options.onStatus?.("ℹ Qoder model available — continuing request");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (status.isQueued !== true && status.serviceAvailable !== false)
|
|
111
|
+
throw queueEnded("status cannot be recovered", initial.body);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function releaseQueueLease(credential, identity, modelKey, startedAt) {
|
|
115
|
+
if (!credential.uid)
|
|
116
|
+
return;
|
|
117
|
+
const signal = qoderRequestSignal(undefined, 3_000);
|
|
118
|
+
const body = JSON.stringify({
|
|
119
|
+
payload: JSON.stringify({ model_key: modelKey, request_set_id: identity.requestSetId, user_id: credential.uid, time_consumed: Math.max(0, Date.now() - startedAt) }),
|
|
120
|
+
encodeVersion: "1",
|
|
121
|
+
});
|
|
122
|
+
const response = await fetchSignedQoderRequest(credential, {
|
|
123
|
+
endpoint: QODER_INFERENCE_ORIGIN, path: "/api/v2/service/ask/finish?Encode=1", method: "POST", body,
|
|
124
|
+
headers: { Accept: "application/json", "Content-Type": "application/json", "X-Request-ID": crypto.randomUUID() }, signal,
|
|
125
|
+
});
|
|
126
|
+
const raw = await readQoderResponseBody(response, signal);
|
|
127
|
+
if (!response.ok)
|
|
128
|
+
throw qoderResponseError(response.status, raw);
|
|
129
|
+
}
|
|
130
|
+
export async function withQoderModelQueue(options) {
|
|
131
|
+
const identity = requestIdentity();
|
|
132
|
+
const leasedModels = new Set();
|
|
133
|
+
const startedAt = Date.now();
|
|
134
|
+
const maxWaitMs = queueWaitLimitMs();
|
|
135
|
+
let deadline;
|
|
136
|
+
let recoveries = 0;
|
|
137
|
+
try {
|
|
138
|
+
for (;;) {
|
|
139
|
+
options.signal?.throwIfAborted();
|
|
140
|
+
try {
|
|
141
|
+
return await withQoderCredential(options.auth, (credential) => {
|
|
142
|
+
identity.requestId = crypto.randomUUID();
|
|
143
|
+
return options.run(credential, identity);
|
|
144
|
+
}, options.onStatus, options.canRetry);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (!(error instanceof QoderModelQueuedError))
|
|
148
|
+
throw error;
|
|
149
|
+
leasedModels.add(error.queue.modelKey ?? options.modelKey);
|
|
150
|
+
if (!options.canRetry())
|
|
151
|
+
throw error;
|
|
152
|
+
if (recoveries++ >= 10)
|
|
153
|
+
throw queueEnded("recovery limit reached after 10 attempts", error.body);
|
|
154
|
+
deadline ??= Date.now() + maxWaitMs;
|
|
155
|
+
await waitForQueue({ ...options, identity, deadline, maxWaitMs }, error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
if (leasedModels.size > 0 && options.auth.apiKey) {
|
|
161
|
+
const credential = parseQoderCredential(options.auth.apiKey);
|
|
162
|
+
const releases = await Promise.allSettled([...leasedModels].map((modelKey) => releaseQueueLease(credential, identity, modelKey, startedAt)));
|
|
163
|
+
if (!options.signal?.aborted && releases.some((release) => release.status === "rejected")) {
|
|
164
|
+
options.onStatus?.("ℹ Qoder queue lease release failed; the server will release it automatically");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=qoder-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qoder-queue.js","sourceRoot":"","sources":["../../../src/llm/qoder/qoder-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ProviderError } from "../http.js";
|
|
2
|
+
export interface QoderQueueStatus {
|
|
3
|
+
isQueued?: boolean | undefined;
|
|
4
|
+
serviceAvailable?: boolean | undefined;
|
|
5
|
+
modelKey?: string | undefined;
|
|
6
|
+
queueType?: string | undefined;
|
|
7
|
+
queueCount?: number | undefined;
|
|
8
|
+
retryAfterSeconds?: number | undefined;
|
|
9
|
+
waitTime?: number | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare function parseQoderQueueStatus(raw: string): QoderQueueStatus | undefined;
|
|
12
|
+
export declare class QoderModelQueuedError extends ProviderError {
|
|
13
|
+
readonly wireStatus: number;
|
|
14
|
+
readonly queue: QoderQueueStatus;
|
|
15
|
+
constructor(wireStatus: number, body: string, queue: QoderQueueStatus);
|
|
16
|
+
}
|
|
17
|
+
export declare function qoderModelQueuedError(status: number, raw: string): QoderModelQueuedError | undefined;
|
|
18
|
+
export declare function qoderResponseError(status: number, raw: string): ProviderError;
|
|
19
|
+
export declare function extractQoderStreamBody(payload: string): string | undefined;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ProviderError } from "../http.js";
|
|
2
|
+
import { asRecord, pickString } from "./qoder-auth.js";
|
|
3
|
+
function responseRecords(raw) {
|
|
4
|
+
const pending = [raw];
|
|
5
|
+
const records = [];
|
|
6
|
+
for (let index = 0; index < pending.length && index < 64; index++) {
|
|
7
|
+
let value = pending[index];
|
|
8
|
+
if (typeof value === "string") {
|
|
9
|
+
try {
|
|
10
|
+
value = JSON.parse(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const record = asRecord(value);
|
|
17
|
+
if (!record)
|
|
18
|
+
continue;
|
|
19
|
+
records.push(record);
|
|
20
|
+
for (const key of ["data", "result", "message", "body", "error"]) {
|
|
21
|
+
if (record[key] !== undefined)
|
|
22
|
+
pending.push(record[key]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return records;
|
|
26
|
+
}
|
|
27
|
+
function nonnegativeNumber(value) {
|
|
28
|
+
const number = typeof value === "string" && value.trim() ? Number(value) : value;
|
|
29
|
+
return typeof number === "number" && Number.isFinite(number) && number >= 0 ? number : undefined;
|
|
30
|
+
}
|
|
31
|
+
function queueStatus(records) {
|
|
32
|
+
const record = records.find((entry) => typeof entry.isQueued === "boolean" || typeof entry.serviceAvailable === "boolean");
|
|
33
|
+
if (!record)
|
|
34
|
+
return undefined;
|
|
35
|
+
return {
|
|
36
|
+
isQueued: typeof record.isQueued === "boolean" ? record.isQueued : undefined,
|
|
37
|
+
serviceAvailable: typeof record.serviceAvailable === "boolean" ? record.serviceAvailable : undefined,
|
|
38
|
+
modelKey: pickString(record, "modelKey"),
|
|
39
|
+
queueType: pickString(record, "queueType"),
|
|
40
|
+
queueCount: nonnegativeNumber(record.queueCount),
|
|
41
|
+
retryAfterSeconds: nonnegativeNumber(record.retryAfterSeconds),
|
|
42
|
+
waitTime: nonnegativeNumber(record.waitTime),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function parseQoderQueueStatus(raw) {
|
|
46
|
+
return queueStatus(responseRecords(raw));
|
|
47
|
+
}
|
|
48
|
+
export class QoderModelQueuedError extends ProviderError {
|
|
49
|
+
wireStatus;
|
|
50
|
+
queue;
|
|
51
|
+
constructor(wireStatus, body, queue) {
|
|
52
|
+
super(`Qoder model request queued (code 10605; HTTP ${wireStatus}). Waiting for model capacity.`, 503, body, queue.retryAfterSeconds);
|
|
53
|
+
this.wireStatus = wireStatus;
|
|
54
|
+
this.queue = queue;
|
|
55
|
+
this.name = "QoderModelQueuedError";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function qoderModelQueuedError(status, raw) {
|
|
59
|
+
const records = responseRecords(raw);
|
|
60
|
+
const queue = queueStatus(records);
|
|
61
|
+
const queuedCode = records.some((record) => String(record.code) === "10605");
|
|
62
|
+
if (!queuedCode && queue?.isQueued !== true && !(queue?.serviceAvailable === false && queue.isQueued !== false))
|
|
63
|
+
return undefined;
|
|
64
|
+
return new QoderModelQueuedError(status, raw, queue ?? {});
|
|
65
|
+
}
|
|
66
|
+
export function qoderResponseError(status, raw) {
|
|
67
|
+
const queued = qoderModelQueuedError(status, raw);
|
|
68
|
+
if (queued)
|
|
69
|
+
return queued;
|
|
70
|
+
let detail = raw;
|
|
71
|
+
for (const record of responseRecords(raw)) {
|
|
72
|
+
detail = pickString(record, "message", "errorMessage", "error", "detail") ?? detail;
|
|
73
|
+
}
|
|
74
|
+
return new ProviderError(`Qoder request failed (HTTP ${status})${detail ? `: ${detail.slice(0, 2000)}` : "."}`, status, raw);
|
|
75
|
+
}
|
|
76
|
+
export function extractQoderStreamBody(payload) {
|
|
77
|
+
let wrapper;
|
|
78
|
+
try {
|
|
79
|
+
wrapper = asRecord(JSON.parse(payload));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
if (!wrapper)
|
|
85
|
+
return undefined;
|
|
86
|
+
const body = typeof wrapper.body === "string" ? wrapper.body : undefined;
|
|
87
|
+
const status = nonnegativeNumber(wrapper.statusCodeValue) ?? 200;
|
|
88
|
+
const raw = body ?? payload;
|
|
89
|
+
if (status !== 200)
|
|
90
|
+
throw qoderResponseError(status, raw);
|
|
91
|
+
const queued = qoderModelQueuedError(status, raw);
|
|
92
|
+
if (queued)
|
|
93
|
+
throw queued;
|
|
94
|
+
if (body !== undefined)
|
|
95
|
+
return body;
|
|
96
|
+
return wrapper.choices !== undefined || wrapper.usage !== undefined ? payload : undefined;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=qoder-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qoder-response.js","sourceRoot":"","sources":["../../../src/llm/qoder/qoder-response.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface QoderStreamDelta {
|
|
2
|
+
content?: string;
|
|
3
|
+
reasoning_content?: string;
|
|
4
|
+
reasoning?: string;
|
|
5
|
+
thinking?: string;
|
|
6
|
+
tool_calls?: Array<{
|
|
7
|
+
index?: number;
|
|
8
|
+
id?: string;
|
|
9
|
+
function?: {
|
|
10
|
+
name?: string;
|
|
11
|
+
arguments?: string | Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
interface QoderStreamChunk {
|
|
16
|
+
choices?: Array<{
|
|
17
|
+
delta?: QoderStreamDelta;
|
|
18
|
+
finish_reason?: string;
|
|
19
|
+
}>;
|
|
20
|
+
usage?: unknown;
|
|
21
|
+
}
|
|
22
|
+
export declare function readQoderStreamChunks(response: Response, reasoningEnabled: boolean, outputProgress: () => number, signal?: AbortSignal): AsyncGenerator<QoderStreamChunk, void, void>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ProviderError, createSseFrameAssembler, readStreamLines, streamIdleBudgets } from "../http.js";
|
|
2
|
+
import { parseOpenAiUsage } from "../token-usage.js";
|
|
3
|
+
import { extractQoderStreamBody } from "./qoder-response.js";
|
|
4
|
+
const USAGE_TAIL_TIMEOUT_MS = 5_000;
|
|
5
|
+
function parseChunk(raw) {
|
|
6
|
+
try {
|
|
7
|
+
const chunk = JSON.parse(raw);
|
|
8
|
+
if (!chunk || typeof chunk !== "object" || Array.isArray(chunk))
|
|
9
|
+
throw new Error("Invalid stream chunk");
|
|
10
|
+
if (chunk.choices !== undefined && !Array.isArray(chunk.choices))
|
|
11
|
+
throw new Error("Invalid stream choices");
|
|
12
|
+
return chunk;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new ProviderError("Qoder returned malformed stream data.", 502, raw.slice(0, 2000));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function* readQoderStreamChunks(response, reasoningEnabled, outputProgress, signal) {
|
|
19
|
+
const tailController = new AbortController();
|
|
20
|
+
const streamSignal = signal ? AbortSignal.any([signal, tailController.signal]) : tailController.signal;
|
|
21
|
+
let tailTimer;
|
|
22
|
+
let finished = false;
|
|
23
|
+
const frames = createSseFrameAssembler();
|
|
24
|
+
try {
|
|
25
|
+
for await (const line of readStreamLines(response, {
|
|
26
|
+
signal: streamSignal,
|
|
27
|
+
...streamIdleBudgets(reasoningEnabled),
|
|
28
|
+
outputProgress,
|
|
29
|
+
})) {
|
|
30
|
+
const payload = frames.pushLine(line);
|
|
31
|
+
if (!payload)
|
|
32
|
+
continue;
|
|
33
|
+
if (payload === "[DONE]") {
|
|
34
|
+
finished = true;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
const raw = extractQoderStreamBody(payload);
|
|
38
|
+
if (!raw)
|
|
39
|
+
continue;
|
|
40
|
+
if (raw === "[DONE]") {
|
|
41
|
+
finished = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
if (/^\[(?:NOT_EXCEED_QUOTA|EXCEED_QUOTA|NOTIFICATIONS)\]/.test(raw))
|
|
45
|
+
continue;
|
|
46
|
+
const chunk = parseChunk(raw);
|
|
47
|
+
if (finished) {
|
|
48
|
+
if (parseOpenAiUsage(chunk.usage)) {
|
|
49
|
+
yield { usage: chunk.usage };
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
yield chunk;
|
|
55
|
+
if (!chunk.choices?.[0]?.finish_reason)
|
|
56
|
+
continue;
|
|
57
|
+
finished = true;
|
|
58
|
+
if (parseOpenAiUsage(chunk.usage))
|
|
59
|
+
break;
|
|
60
|
+
tailTimer = setTimeout(() => tailController.abort(new DOMException("Qoder usage trailer timed out.", "TimeoutError")), USAGE_TAIL_TIMEOUT_MS);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
signal?.throwIfAborted();
|
|
65
|
+
if (!finished)
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
if (tailTimer)
|
|
70
|
+
clearTimeout(tailTimer);
|
|
71
|
+
}
|
|
72
|
+
if (!finished)
|
|
73
|
+
throw new ProviderError("Qoder stream ended before completion.", 502);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=qoder-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qoder-stream.js","sourceRoot":"","sources":["../../../src/llm/qoder/qoder-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { readQoderMachineId, readQoderMachineIdentity } from "./qoder-auth.js";
|
|
|
3
3
|
export { encodeQoderCredential, qoderCredentialFromImport, type QoderCredential } from "./qoder-credential.js";
|
|
4
4
|
export declare const QODER_FREE_SUFFIX = ":free";
|
|
5
5
|
export declare function isQoderFreeEntry(entry: {
|
|
6
|
-
is_free?: boolean;
|
|
7
|
-
price_factor?: number;
|
|
6
|
+
is_free?: boolean | undefined;
|
|
7
|
+
price_factor?: number | undefined;
|
|
8
8
|
}): boolean;
|
|
9
9
|
/**
|
|
10
10
|
* Model ids carry a price tag so `/model` shows the multiplier qodercli shows:
|
|
@@ -12,8 +12,8 @@ export declare function isQoderFreeEntry(entry: {
|
|
|
12
12
|
* display-only and stripped before the wire call (see {@link qoderWireModelKey}).
|
|
13
13
|
*/
|
|
14
14
|
export declare function qoderListedModel(key: string, entry: {
|
|
15
|
-
is_free?: boolean;
|
|
16
|
-
price_factor?: number;
|
|
15
|
+
is_free?: boolean | undefined;
|
|
16
|
+
price_factor?: number | undefined;
|
|
17
17
|
}): string;
|
|
18
18
|
export declare function qoderWireModelKey(model: string): string;
|
|
19
19
|
export declare const qoderProvider: LlmProvider;
|