@qoniai/qoni 0.4.0 → 0.4.2
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 +61 -4
- package/README.md +28 -14
- package/README.zh-CN.md +21 -14
- package/dist/index.cjs +208 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +208 -109
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/qoni-sdk/SKILL.md +6 -6
- package/skills/qoni-sdk/agents/openai.yaml +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,8 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
InteractionStatuses: () => InteractionStatuses,
|
|
26
26
|
InteractionTypes: () => InteractionTypes,
|
|
27
27
|
MonitorHandle: () => MonitorHandle,
|
|
28
|
-
Qoni: () =>
|
|
29
|
-
QoniAgentKit: () => QoniAgentKit,
|
|
28
|
+
Qoni: () => Qoni,
|
|
30
29
|
QoniAuthError: () => QoniAuthError,
|
|
31
30
|
QoniDelegationRequiredError: () => QoniDelegationRequiredError,
|
|
32
31
|
QoniError: () => QoniError,
|
|
@@ -817,11 +816,11 @@ var RunHandle = class {
|
|
|
817
816
|
}
|
|
818
817
|
/** Drive the run to a terminal state and return the settled result. */
|
|
819
818
|
async wait(opts = {}) {
|
|
820
|
-
const { signal, timedOut } = withTimeout(opts.signal, opts.timeoutMs);
|
|
819
|
+
const { signal, timedOut, dispose } = withTimeout(opts.signal, opts.timeoutMs);
|
|
821
820
|
let lastEventId;
|
|
822
821
|
let eventIdAtLastClose;
|
|
823
822
|
let sawCleanClose = false;
|
|
824
|
-
let
|
|
823
|
+
let terminalDetail;
|
|
825
824
|
let terminalDoneReason;
|
|
826
825
|
let screenshotIndex = 0;
|
|
827
826
|
try {
|
|
@@ -829,24 +828,28 @@ var RunHandle = class {
|
|
|
829
828
|
for await (const event of this.events({
|
|
830
829
|
signal,
|
|
831
830
|
lastEventId,
|
|
832
|
-
onWireEvent:
|
|
831
|
+
onWireEvent: (wire) => waitWithSignal(() => {
|
|
832
|
+
if (wire.id !== void 0) lastEventId = wire.id;
|
|
833
|
+
return opts.onWireEvent?.(wire);
|
|
834
|
+
}, signal),
|
|
833
835
|
onReconnect: opts.onReconnect
|
|
834
836
|
})) {
|
|
835
|
-
|
|
836
|
-
await opts.onEvent?.(event);
|
|
837
|
+
await waitWithSignal(() => opts.onEvent?.(event), signal);
|
|
837
838
|
if (event.type === "screenshot") {
|
|
838
|
-
await opts.onScreenshot?.(event.image, screenshotIndex++);
|
|
839
|
+
await waitWithSignal(() => opts.onScreenshot?.(event.image, screenshotIndex++), signal);
|
|
839
840
|
} else if (event.type === "interaction") {
|
|
840
|
-
await opts.onInteraction?.(this.interactionHandle(event.data), event);
|
|
841
|
+
await waitWithSignal(() => opts.onInteraction?.(this.interactionHandle(event.data), event), signal);
|
|
841
842
|
}
|
|
842
843
|
if (event.isTerminal) {
|
|
843
|
-
terminalPayload = isJsonObject(event.raw.data) ? event.raw.data : void 0;
|
|
844
844
|
if (event.type === "done") terminalDoneReason = event.data.terminalReason || void 0;
|
|
845
845
|
break settled;
|
|
846
846
|
}
|
|
847
847
|
}
|
|
848
|
-
const detail2 = await this.ops.getDetail();
|
|
849
|
-
if (isTerminalRunStatus(detail2.status))
|
|
848
|
+
const detail2 = await waitWithSignal(() => this.ops.getDetail(signal), signal);
|
|
849
|
+
if (isTerminalRunStatus(normalizeRunStatus(this.id, detail2).status)) {
|
|
850
|
+
terminalDetail = detail2;
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
850
853
|
if (sawCleanClose && lastEventId === eventIdAtLastClose) {
|
|
851
854
|
throw new QoniError(
|
|
852
855
|
`run event stream ended before a terminal event while the run is still "${String(detail2.status)}" \u2014 re-attach or poll status()`,
|
|
@@ -856,6 +859,11 @@ var RunHandle = class {
|
|
|
856
859
|
sawCleanClose = true;
|
|
857
860
|
eventIdAtLastClose = lastEventId;
|
|
858
861
|
}
|
|
862
|
+
const detail = terminalDetail ?? await waitWithSignal(() => this.ops.getDetail(signal), signal);
|
|
863
|
+
this.#adoptSessionRef(detail);
|
|
864
|
+
const result = settleRunResult(this.id, detail, [], terminalDoneReason);
|
|
865
|
+
result.artifacts = this.ops.listArtifacts ? await waitWithSignal(() => this.ops.listArtifacts(signal), signal) : [];
|
|
866
|
+
return result;
|
|
859
867
|
} catch (err) {
|
|
860
868
|
if (timedOut() && !opts.signal?.aborted) {
|
|
861
869
|
throw new QoniTimeoutError(
|
|
@@ -864,17 +872,9 @@ var RunHandle = class {
|
|
|
864
872
|
);
|
|
865
873
|
}
|
|
866
874
|
throw err;
|
|
875
|
+
} finally {
|
|
876
|
+
dispose();
|
|
867
877
|
}
|
|
868
|
-
let detail;
|
|
869
|
-
try {
|
|
870
|
-
detail = await this.ops.getDetail();
|
|
871
|
-
} catch (err) {
|
|
872
|
-
if (!terminalPayload) throw err;
|
|
873
|
-
detail = terminalPayload;
|
|
874
|
-
}
|
|
875
|
-
this.#adoptSessionRef(detail);
|
|
876
|
-
const artifacts = this.ops.listArtifacts ? await this.ops.listArtifacts() : [];
|
|
877
|
-
return settleRunResult(this.id, detail, artifacts, terminalDoneReason);
|
|
878
878
|
}
|
|
879
879
|
/**
|
|
880
880
|
* Wrap an {@link Interaction} (from `event.data` of an `interaction` event)
|
|
@@ -927,15 +927,12 @@ function normalizeRunStatus(id, detail) {
|
|
|
927
927
|
function settleRunResult(runId, detail, artifacts, fallbackTerminalReason) {
|
|
928
928
|
const terminalReason = (typeof detail.terminal_reason === "string" ? detail.terminal_reason : void 0) ?? fallbackTerminalReason;
|
|
929
929
|
const isTaskSuccessful = typeof detail.is_task_successful === "boolean" ? detail.is_task_successful : void 0;
|
|
930
|
-
|
|
931
|
-
if (isTerminalRunStatus(
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
status = "failed";
|
|
937
|
-
} else {
|
|
938
|
-
status = "succeeded";
|
|
930
|
+
const status = normalizeRunStatus(runId, detail).status;
|
|
931
|
+
if (!isTerminalRunStatus(status)) {
|
|
932
|
+
throw new QoniError(
|
|
933
|
+
"run detail did not confirm a terminal state \u2014 re-attach or poll status()",
|
|
934
|
+
{ code: "upstream.failed", retryable: true, body: detail }
|
|
935
|
+
);
|
|
939
936
|
}
|
|
940
937
|
return {
|
|
941
938
|
runId,
|
|
@@ -962,19 +959,40 @@ function isVideoFrame(wire) {
|
|
|
962
959
|
return type === "browser_video_frame" || type === "run.browser_video_frame";
|
|
963
960
|
}
|
|
964
961
|
function withTimeout(signal, timeoutMs) {
|
|
965
|
-
if (!timeoutMs) return { signal, timedOut: () => false
|
|
962
|
+
if (!timeoutMs) return { signal, timedOut: () => false, dispose: () => {
|
|
963
|
+
} };
|
|
966
964
|
const controller = new AbortController();
|
|
967
965
|
let fired = false;
|
|
968
966
|
const timer = setTimeout(() => {
|
|
969
967
|
fired = true;
|
|
970
968
|
controller.abort();
|
|
971
969
|
}, timeoutMs);
|
|
972
|
-
|
|
970
|
+
const onAbort = () => controller.abort(signal?.reason);
|
|
971
|
+
const dispose = () => {
|
|
972
|
+
clearTimeout(timer);
|
|
973
|
+
signal?.removeEventListener("abort", onAbort);
|
|
974
|
+
};
|
|
975
|
+
controller.signal.addEventListener("abort", dispose, { once: true });
|
|
973
976
|
if (signal) {
|
|
974
|
-
if (signal.aborted)
|
|
975
|
-
else signal.addEventListener("abort",
|
|
977
|
+
if (signal.aborted) onAbort();
|
|
978
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
976
979
|
}
|
|
977
|
-
return { signal: controller.signal, timedOut: () => fired };
|
|
980
|
+
return { signal: controller.signal, timedOut: () => fired, dispose };
|
|
981
|
+
}
|
|
982
|
+
function waitWithSignal(operation, signal) {
|
|
983
|
+
if (!signal) return Promise.resolve().then(operation);
|
|
984
|
+
return new Promise((resolve, reject) => {
|
|
985
|
+
const onAbort = () => reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
|
|
986
|
+
if (signal.aborted) {
|
|
987
|
+
onAbort();
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
991
|
+
Promise.resolve().then(() => {
|
|
992
|
+
signal.throwIfAborted();
|
|
993
|
+
return operation();
|
|
994
|
+
}).then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
995
|
+
});
|
|
978
996
|
}
|
|
979
997
|
|
|
980
998
|
// src/deep-research.ts
|
|
@@ -989,6 +1007,7 @@ function createDeepResearchNamespace(transport) {
|
|
|
989
1007
|
`/deep_research/runs/${encodeURIComponent(input.runId)}`,
|
|
990
1008
|
input.token,
|
|
991
1009
|
{
|
|
1010
|
+
signal: input.signal,
|
|
992
1011
|
requiredScopes: ["webagent.deep_research:read"]
|
|
993
1012
|
}
|
|
994
1013
|
),
|
|
@@ -1034,6 +1053,7 @@ function createDeepResearchNamespace(transport) {
|
|
|
1034
1053
|
`/deep_research/runs/${encodeURIComponent(input.runId)}/artifacts`,
|
|
1035
1054
|
input.token,
|
|
1036
1055
|
{
|
|
1056
|
+
signal: input.signal,
|
|
1037
1057
|
requiredScopes: ["webagent.deep_research:read"]
|
|
1038
1058
|
}
|
|
1039
1059
|
),
|
|
@@ -1048,7 +1068,7 @@ function createDeepResearchNamespace(transport) {
|
|
|
1048
1068
|
};
|
|
1049
1069
|
function buildOps(token, runId) {
|
|
1050
1070
|
return {
|
|
1051
|
-
getDetail: async () => asRecord((await api.get({ token, runId })).data),
|
|
1071
|
+
getDetail: async (signal) => asRecord((await api.get({ token, runId, signal })).data),
|
|
1052
1072
|
streamEvents: (opts) => api.events({
|
|
1053
1073
|
token,
|
|
1054
1074
|
runId,
|
|
@@ -1068,8 +1088,8 @@ function createDeepResearchNamespace(transport) {
|
|
|
1068
1088
|
);
|
|
1069
1089
|
},
|
|
1070
1090
|
cancel: async () => asRecord((await api.cancel({ token, runId })).data),
|
|
1071
|
-
listArtifacts: async () => {
|
|
1072
|
-
const res = await api.listArtifacts({ token, runId });
|
|
1091
|
+
listArtifacts: async (signal) => {
|
|
1092
|
+
const res = await api.listArtifacts({ token, runId, signal });
|
|
1073
1093
|
const items = Array.isArray(res.data?.items) ? res.data.items : [];
|
|
1074
1094
|
return items.filter(isJsonObject).map((item) => toArtifact(item, token, runId));
|
|
1075
1095
|
}
|
|
@@ -1189,6 +1209,7 @@ function createDoAnythingNamespace(transport) {
|
|
|
1189
1209
|
`/do_anything/runs/${encodeURIComponent(input.runId)}`,
|
|
1190
1210
|
input.token,
|
|
1191
1211
|
{
|
|
1212
|
+
signal: input.signal,
|
|
1192
1213
|
requiredScopes: ["webagent.do_anything:read"]
|
|
1193
1214
|
}
|
|
1194
1215
|
),
|
|
@@ -1246,7 +1267,7 @@ function createDoAnythingNamespace(transport) {
|
|
|
1246
1267
|
};
|
|
1247
1268
|
function buildOps(token, runId, capture) {
|
|
1248
1269
|
return {
|
|
1249
|
-
getDetail: async () => asRecord2((await api.getRun({ token, runId })).data),
|
|
1270
|
+
getDetail: async (signal) => asRecord2((await api.getRun({ token, runId, signal })).data),
|
|
1250
1271
|
streamEvents: (opts) => api.events({
|
|
1251
1272
|
token,
|
|
1252
1273
|
runId,
|
|
@@ -1840,6 +1861,7 @@ function createWebSearchNamespace(transport) {
|
|
|
1840
1861
|
`/web_search/runs/${encodeURIComponent(input.runId)}`,
|
|
1841
1862
|
input.token,
|
|
1842
1863
|
{
|
|
1864
|
+
signal: input.signal,
|
|
1843
1865
|
requiredScopes: ["webagent.web_search:read"]
|
|
1844
1866
|
}
|
|
1845
1867
|
),
|
|
@@ -1865,7 +1887,7 @@ function createWebSearchNamespace(transport) {
|
|
|
1865
1887
|
};
|
|
1866
1888
|
function buildOps(token, runId) {
|
|
1867
1889
|
return {
|
|
1868
|
-
getDetail: async () => asRecord4((await api.get({ token, runId })).data),
|
|
1890
|
+
getDetail: async (signal) => asRecord4((await api.get({ token, runId, signal })).data),
|
|
1869
1891
|
streamEvents: (opts) => api.events({
|
|
1870
1892
|
token,
|
|
1871
1893
|
runId,
|
|
@@ -1958,8 +1980,8 @@ function renameKeys5(value, mapping) {
|
|
|
1958
1980
|
}
|
|
1959
1981
|
|
|
1960
1982
|
// src/client.ts
|
|
1961
|
-
var DEFAULT_QONI_HOST = "https://
|
|
1962
|
-
var
|
|
1983
|
+
var DEFAULT_QONI_HOST = "https://dashboard.qoni.ai";
|
|
1984
|
+
var Qoni = class {
|
|
1963
1985
|
constructor(options) {
|
|
1964
1986
|
this.options = options;
|
|
1965
1987
|
const accessKey = options.accessKey ?? options.accessKeyId;
|
|
@@ -2138,7 +2160,9 @@ var QoniAgentKit = class {
|
|
|
2138
2160
|
}
|
|
2139
2161
|
}
|
|
2140
2162
|
async webAgentJson(method, path, token, payload = {}) {
|
|
2163
|
+
payload.signal?.throwIfAborted();
|
|
2141
2164
|
const runtimeToken = await this.productTokenFor("webagent", token, payload.requiredScopes);
|
|
2165
|
+
payload.signal?.throwIfAborted();
|
|
2142
2166
|
const baseUrl = await this.baseUrlFor("webagent");
|
|
2143
2167
|
return this.jsonRequest(
|
|
2144
2168
|
baseUrl,
|
|
@@ -2149,9 +2173,11 @@ var QoniAgentKit = class {
|
|
|
2149
2173
|
// Binary GET against the WebAgent API — artifact content downloads. JSON
|
|
2150
2174
|
// error payloads still map to typed QoniErrors.
|
|
2151
2175
|
async webAgentBytes(path, token, payload = {}) {
|
|
2176
|
+
payload.signal?.throwIfAborted();
|
|
2152
2177
|
const runtimeToken = await this.productTokenFor("webagent", token, payload.requiredScopes);
|
|
2178
|
+
payload.signal?.throwIfAborted();
|
|
2153
2179
|
const baseUrl = await this.baseUrlFor("webagent");
|
|
2154
|
-
|
|
2180
|
+
return this.fetchWithTimeout(
|
|
2155
2181
|
urlWithBasePath(baseUrl, this.webAgentPath(runtimeToken, path), payload.query),
|
|
2156
2182
|
{
|
|
2157
2183
|
method: "GET",
|
|
@@ -2160,20 +2186,22 @@ var QoniAgentKit = class {
|
|
|
2160
2186
|
authorization: `Bearer ${runtimeToken}`,
|
|
2161
2187
|
...payload.headers || {}
|
|
2162
2188
|
}
|
|
2163
|
-
}
|
|
2189
|
+
},
|
|
2190
|
+
async (response, signal) => {
|
|
2191
|
+
if (!response.ok) {
|
|
2192
|
+
throw errorFromPayload(
|
|
2193
|
+
response.status,
|
|
2194
|
+
await readJson(response, signal),
|
|
2195
|
+
`Qoni request failed with HTTP ${response.status}`
|
|
2196
|
+
);
|
|
2197
|
+
}
|
|
2198
|
+
return {
|
|
2199
|
+
bytes: await readBody(response, signal),
|
|
2200
|
+
mime: response.headers.get("content-type") || "application/octet-stream"
|
|
2201
|
+
};
|
|
2202
|
+
},
|
|
2203
|
+
payload.signal
|
|
2164
2204
|
);
|
|
2165
|
-
if (!response.ok) {
|
|
2166
|
-
throw errorFromPayload(
|
|
2167
|
-
response.status,
|
|
2168
|
-
await readJson(response),
|
|
2169
|
-
`Qoni request failed with HTTP ${response.status}`
|
|
2170
|
-
);
|
|
2171
|
-
}
|
|
2172
|
-
const buffer = await response.arrayBuffer();
|
|
2173
|
-
return {
|
|
2174
|
-
bytes: new Uint8Array(buffer),
|
|
2175
|
-
mime: response.headers.get("content-type") || "application/octet-stream"
|
|
2176
|
-
};
|
|
2177
2205
|
}
|
|
2178
2206
|
async *webAgentSSE(path, token, payload = {}) {
|
|
2179
2207
|
const runtimeToken = await this.productTokenFor("webagent", token, payload.requiredScopes);
|
|
@@ -2213,15 +2241,16 @@ var QoniAgentKit = class {
|
|
|
2213
2241
|
});
|
|
2214
2242
|
}
|
|
2215
2243
|
async jsonRequest(baseUrl, pathname, options) {
|
|
2216
|
-
const response = await this.fetchWithTimeout(
|
|
2244
|
+
const { response, payload } = await this.fetchWithTimeout(
|
|
2217
2245
|
urlWithBasePath(baseUrl, pathname, options.query),
|
|
2218
2246
|
{
|
|
2219
2247
|
method: options.method,
|
|
2220
2248
|
headers: requestHeaders(options),
|
|
2221
2249
|
body: requestBody(options.body)
|
|
2222
|
-
}
|
|
2250
|
+
},
|
|
2251
|
+
async (response2, signal) => ({ response: response2, payload: await readJson(response2, signal) }),
|
|
2252
|
+
options.signal
|
|
2223
2253
|
);
|
|
2224
|
-
const payload = await readJson(response);
|
|
2225
2254
|
if (!response.ok) {
|
|
2226
2255
|
throw errorFromPayload(
|
|
2227
2256
|
response.status,
|
|
@@ -2271,45 +2300,55 @@ var QoniAgentKit = class {
|
|
|
2271
2300
|
}
|
|
2272
2301
|
}
|
|
2273
2302
|
async *sseConnectOnce(baseUrl, pathname, options) {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
accept: "text/event-stream",
|
|
2280
|
-
authorization: `Bearer ${options.token}`,
|
|
2281
|
-
...options.headers || {},
|
|
2282
|
-
...options.lastEventId ? { "last-event-id": options.lastEventId } : {}
|
|
2283
|
-
}
|
|
2284
|
-
},
|
|
2285
|
-
options.signal,
|
|
2286
|
-
{ streamBody: true }
|
|
2287
|
-
);
|
|
2288
|
-
if (!response.ok) {
|
|
2289
|
-
throw errorFromPayload(
|
|
2290
|
-
response.status,
|
|
2291
|
-
await readJson(response),
|
|
2292
|
-
`Qoni stream failed with HTTP ${response.status}`
|
|
2293
|
-
);
|
|
2294
|
-
}
|
|
2295
|
-
if (!response.body) {
|
|
2296
|
-
throw errorFromPayload(502, void 0, "Qoni stream response has no body");
|
|
2297
|
-
}
|
|
2298
|
-
const reader = response.body.getReader();
|
|
2303
|
+
let cleanup;
|
|
2304
|
+
let reader;
|
|
2305
|
+
const onAbort = () => {
|
|
2306
|
+
void reader?.cancel(options.signal?.reason).catch(() => void 0);
|
|
2307
|
+
};
|
|
2299
2308
|
const decoder = new TextDecoder();
|
|
2300
2309
|
let buffer = "";
|
|
2301
2310
|
try {
|
|
2311
|
+
const response = await this.fetchWithTimeout(
|
|
2312
|
+
urlWithBasePath(baseUrl, pathname, options.query),
|
|
2313
|
+
{
|
|
2314
|
+
method: "GET",
|
|
2315
|
+
headers: {
|
|
2316
|
+
accept: "text/event-stream",
|
|
2317
|
+
authorization: `Bearer ${options.token}`,
|
|
2318
|
+
...options.headers || {},
|
|
2319
|
+
...options.lastEventId ? { "last-event-id": options.lastEventId } : {}
|
|
2320
|
+
}
|
|
2321
|
+
},
|
|
2322
|
+
async (response2, signal) => {
|
|
2323
|
+
if (!response2.ok) {
|
|
2324
|
+
throw errorFromPayload(
|
|
2325
|
+
response2.status,
|
|
2326
|
+
await readJson(response2, signal),
|
|
2327
|
+
`Qoni stream failed with HTTP ${response2.status}`
|
|
2328
|
+
);
|
|
2329
|
+
}
|
|
2330
|
+
return response2;
|
|
2331
|
+
},
|
|
2332
|
+
options.signal,
|
|
2333
|
+
{ streamCleanup: (dispose) => {
|
|
2334
|
+
cleanup = dispose;
|
|
2335
|
+
} }
|
|
2336
|
+
);
|
|
2337
|
+
if (!response.body) {
|
|
2338
|
+
throw errorFromPayload(502, void 0, "Qoni stream response has no body");
|
|
2339
|
+
}
|
|
2340
|
+
reader = response.body.getReader();
|
|
2341
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
2302
2342
|
while (true) {
|
|
2303
|
-
|
|
2304
|
-
await reader.cancel().catch(() => void 0);
|
|
2305
|
-
throw options.signal.reason || new DOMException("Aborted", "AbortError");
|
|
2306
|
-
}
|
|
2343
|
+
options.signal?.throwIfAborted();
|
|
2307
2344
|
const { done, value } = await reader.read();
|
|
2345
|
+
options.signal?.throwIfAborted();
|
|
2308
2346
|
if (done) break;
|
|
2309
2347
|
buffer += decoder.decode(value, { stream: true });
|
|
2310
2348
|
const chunks = buffer.split(/\r?\n\r?\n/);
|
|
2311
2349
|
buffer = chunks.pop() || "";
|
|
2312
2350
|
for (const chunk of chunks) {
|
|
2351
|
+
options.signal?.throwIfAborted();
|
|
2313
2352
|
const event = parseSSEEvent(chunk);
|
|
2314
2353
|
if (event) yield event;
|
|
2315
2354
|
}
|
|
@@ -2317,10 +2356,16 @@ var QoniAgentKit = class {
|
|
|
2317
2356
|
const finalEvent = parseSSEEvent(buffer);
|
|
2318
2357
|
if (finalEvent) yield finalEvent;
|
|
2319
2358
|
} finally {
|
|
2320
|
-
|
|
2359
|
+
cleanup?.();
|
|
2360
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
2361
|
+
void reader?.cancel().catch(() => void 0);
|
|
2362
|
+
try {
|
|
2363
|
+
reader?.releaseLock();
|
|
2364
|
+
} catch {
|
|
2365
|
+
}
|
|
2321
2366
|
}
|
|
2322
2367
|
}
|
|
2323
|
-
async fetchWithTimeout(input, init, signal, opts) {
|
|
2368
|
+
async fetchWithTimeout(input, init, consume, signal, opts) {
|
|
2324
2369
|
if (signal?.aborted) throw signal.reason || new DOMException("Aborted", "AbortError");
|
|
2325
2370
|
const controller = new AbortController();
|
|
2326
2371
|
const resolved = resolveLocalGenauthRequest(input);
|
|
@@ -2335,24 +2380,46 @@ var QoniAgentKit = class {
|
|
|
2335
2380
|
didTimeout = true;
|
|
2336
2381
|
controller.abort();
|
|
2337
2382
|
}, this.timeoutMs);
|
|
2383
|
+
let response;
|
|
2338
2384
|
try {
|
|
2339
|
-
|
|
2385
|
+
response = await new Promise((resolve, reject) => {
|
|
2386
|
+
const onAbort = () => reject(controller.signal.reason);
|
|
2387
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
2388
|
+
Promise.resolve().then(() => {
|
|
2389
|
+
controller.signal.throwIfAborted();
|
|
2390
|
+
return this.fetchImpl(resolved.url, { ...requestInit, signal: controller.signal });
|
|
2391
|
+
}).then((response2) => {
|
|
2392
|
+
if (controller.signal.aborted) {
|
|
2393
|
+
void response2.body?.cancel(controller.signal.reason).catch(() => void 0);
|
|
2394
|
+
reject(controller.signal.reason);
|
|
2395
|
+
} else {
|
|
2396
|
+
resolve(response2);
|
|
2397
|
+
}
|
|
2398
|
+
}, reject).finally(() => controller.signal.removeEventListener("abort", onAbort));
|
|
2399
|
+
});
|
|
2400
|
+
const result = await consume(response, controller.signal);
|
|
2401
|
+
controller.signal.throwIfAborted();
|
|
2402
|
+
return result;
|
|
2340
2403
|
} catch (error) {
|
|
2341
|
-
|
|
2404
|
+
void response?.body?.cancel().catch(() => void 0);
|
|
2405
|
+
if (signal?.aborted) throw signal.reason;
|
|
2406
|
+
if (didTimeout || isConnectTimeoutError(error)) {
|
|
2342
2407
|
throw timeoutError(error);
|
|
2343
2408
|
}
|
|
2344
2409
|
if (isFetchNetworkError(error)) throw networkError(error);
|
|
2345
2410
|
throw error;
|
|
2346
2411
|
} finally {
|
|
2347
2412
|
clearTimeout(timeout);
|
|
2348
|
-
|
|
2413
|
+
const cleanup = () => signal?.removeEventListener("abort", abortFromSignal);
|
|
2414
|
+
if (opts?.streamCleanup) opts.streamCleanup(cleanup);
|
|
2415
|
+
else cleanup();
|
|
2349
2416
|
}
|
|
2350
2417
|
}
|
|
2351
2418
|
async baseUrlFor(service) {
|
|
2352
2419
|
const explicit = this.explicitBaseUrlFor(service);
|
|
2353
2420
|
if (explicit) return explicit;
|
|
2354
|
-
const runtime = await this.runtimeConfig();
|
|
2355
2421
|
if (service === "qoni") return this.host;
|
|
2422
|
+
const runtime = await this.runtimeConfig();
|
|
2356
2423
|
const hostOrigin = originBaseUrl(this.host);
|
|
2357
2424
|
if (service === "genauth") return runtime.genauthBaseUrl ?? hostOrigin;
|
|
2358
2425
|
if (service === "gumem") return runtime.gumemBaseUrl ?? hostOrigin;
|
|
@@ -2401,7 +2468,7 @@ var QoniAgentKit = class {
|
|
|
2401
2468
|
pathname,
|
|
2402
2469
|
{}
|
|
2403
2470
|
);
|
|
2404
|
-
const response = await this.fetchWithTimeout(
|
|
2471
|
+
const { response, payload } = await this.fetchWithTimeout(
|
|
2405
2472
|
urlWithBasePath(this.host, pathname),
|
|
2406
2473
|
{
|
|
2407
2474
|
method: "GET",
|
|
@@ -2409,9 +2476,9 @@ var QoniAgentKit = class {
|
|
|
2409
2476
|
accept: "application/json",
|
|
2410
2477
|
...headers
|
|
2411
2478
|
}
|
|
2412
|
-
}
|
|
2479
|
+
},
|
|
2480
|
+
async (response2, signal) => ({ response: response2, payload: await readJson(response2, signal) })
|
|
2413
2481
|
);
|
|
2414
|
-
const payload = await readJson(response);
|
|
2415
2482
|
if (!response.ok) {
|
|
2416
2483
|
throw errorFromPayload(
|
|
2417
2484
|
response.status,
|
|
@@ -2505,18 +2572,52 @@ function requestBody(body) {
|
|
|
2505
2572
|
function isBodyInit(value) {
|
|
2506
2573
|
return typeof value === "string" || value instanceof ArrayBuffer || value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams;
|
|
2507
2574
|
}
|
|
2508
|
-
async function
|
|
2575
|
+
async function readBody(response, signal) {
|
|
2576
|
+
if (!response.body) {
|
|
2577
|
+
signal.throwIfAborted();
|
|
2578
|
+
return new Uint8Array();
|
|
2579
|
+
}
|
|
2580
|
+
const reader = response.body.getReader();
|
|
2581
|
+
const onAbort = () => {
|
|
2582
|
+
void reader.cancel(signal.reason).catch(() => void 0);
|
|
2583
|
+
};
|
|
2584
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2585
|
+
try {
|
|
2586
|
+
const chunks = [];
|
|
2587
|
+
let size = 0;
|
|
2588
|
+
for (; ; ) {
|
|
2589
|
+
signal.throwIfAborted();
|
|
2590
|
+
const { done, value } = await reader.read();
|
|
2591
|
+
signal.throwIfAborted();
|
|
2592
|
+
if (done) break;
|
|
2593
|
+
chunks.push(value);
|
|
2594
|
+
size += value.byteLength;
|
|
2595
|
+
}
|
|
2596
|
+
const bytes = new Uint8Array(size);
|
|
2597
|
+
let offset = 0;
|
|
2598
|
+
for (const chunk of chunks) {
|
|
2599
|
+
bytes.set(chunk, offset);
|
|
2600
|
+
offset += chunk.byteLength;
|
|
2601
|
+
}
|
|
2602
|
+
return bytes;
|
|
2603
|
+
} finally {
|
|
2604
|
+
signal.removeEventListener("abort", onAbort);
|
|
2605
|
+
void reader.cancel().catch(() => void 0);
|
|
2606
|
+
reader.releaseLock();
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
async function readJson(response, signal) {
|
|
2509
2610
|
const contentType = response.headers.get("content-type")?.toLowerCase() || "";
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
if (
|
|
2513
|
-
|
|
2611
|
+
const body = new TextDecoder().decode(await readBody(response, signal));
|
|
2612
|
+
try {
|
|
2613
|
+
if (contentType.includes("ndjson") || contentType.includes("jsonl")) {
|
|
2614
|
+
if (!body.trim()) return [];
|
|
2514
2615
|
return body.split(/\r?\n/).filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
|
|
2515
|
-
} catch {
|
|
2516
|
-
return void 0;
|
|
2517
2616
|
}
|
|
2617
|
+
return JSON.parse(body);
|
|
2618
|
+
} catch {
|
|
2619
|
+
return void 0;
|
|
2518
2620
|
}
|
|
2519
|
-
return response.json().catch(() => void 0);
|
|
2520
2621
|
}
|
|
2521
2622
|
function normalizeResponse(payload, _service) {
|
|
2522
2623
|
if (isJsonObject(payload) && ("data" in payload || "meta" in payload)) {
|
|
@@ -2759,6 +2860,7 @@ function isRetryableStreamError(err) {
|
|
|
2759
2860
|
if (err && typeof err === "object") {
|
|
2760
2861
|
const e = err;
|
|
2761
2862
|
if (e.name === "AbortError") return false;
|
|
2863
|
+
if (e.status === 408) return true;
|
|
2762
2864
|
if (typeof e.retryable === "boolean") return e.retryable;
|
|
2763
2865
|
if (typeof e.status === "number") {
|
|
2764
2866
|
return e.status >= 500 || e.status === 408 || e.status === 429;
|
|
@@ -2865,9 +2967,6 @@ function normalizeDelegateAgentTokenResponse(response) {
|
|
|
2865
2967
|
}
|
|
2866
2968
|
};
|
|
2867
2969
|
}
|
|
2868
|
-
function isAbortError(error) {
|
|
2869
|
-
return error instanceof DOMException && error.name === "AbortError";
|
|
2870
|
-
}
|
|
2871
2970
|
function isConnectTimeoutError(error) {
|
|
2872
2971
|
const cause = errorCause(error);
|
|
2873
2972
|
return errorCode(cause) === "UND_ERR_CONNECT_TIMEOUT" || errorName(cause) === "ConnectTimeoutError";
|
|
@@ -2894,7 +2993,6 @@ function errorName(error) {
|
|
|
2894
2993
|
InteractionTypes,
|
|
2895
2994
|
MonitorHandle,
|
|
2896
2995
|
Qoni,
|
|
2897
|
-
QoniAgentKit,
|
|
2898
2996
|
QoniAuthError,
|
|
2899
2997
|
QoniDelegationRequiredError,
|
|
2900
2998
|
QoniError,
|