@cadraos/sdk 0.3.12 → 0.3.14-p46.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/dist/board-host/index.d.cts +172 -2
- package/dist/board-host/index.d.ts +172 -2
- package/dist/board-host/server/index.d.cts +174 -2
- package/dist/board-host/server/index.d.ts +174 -2
- package/dist/chat/index.cjs +524 -46
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +10 -0
- package/dist/chat/index.d.ts +10 -0
- package/dist/chat/index.js +524 -46
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +453 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +453 -38
- package/dist/index.js.map +1 -1
- package/dist/kanban/engine/index.cjs +1041 -39
- package/dist/kanban/engine/index.cjs.map +1 -1
- package/dist/kanban/engine/index.d.cts +537 -6
- package/dist/kanban/engine/index.d.ts +537 -6
- package/dist/kanban/engine/index.js +1027 -40
- package/dist/kanban/engine/index.js.map +1 -1
- package/dist/kanban/index.cjs +593 -38
- package/dist/kanban/index.cjs.map +1 -1
- package/dist/kanban/index.d.cts +376 -5
- package/dist/kanban/index.d.ts +376 -5
- package/dist/kanban/index.js +589 -39
- package/dist/kanban/index.js.map +1 -1
- package/dist/teams/index.cjs +453 -38
- package/dist/teams/index.cjs.map +1 -1
- package/dist/teams/index.d.cts +10 -0
- package/dist/teams/index.d.ts +10 -0
- package/dist/teams/index.js +453 -38
- package/dist/teams/index.js.map +1 -1
- package/package.json +1 -1
package/dist/chat/index.cjs
CHANGED
|
@@ -447,7 +447,8 @@ var SSEClient = class {
|
|
|
447
447
|
"Authorization": this.config.authHeader,
|
|
448
448
|
"X-Org-Id": String(this.config.orgId),
|
|
449
449
|
"Accept": "text/event-stream",
|
|
450
|
-
"Cache-Control": "no-cache"
|
|
450
|
+
"Cache-Control": "no-cache",
|
|
451
|
+
...this.config.lastEventId ? { "Last-Event-ID": this.config.lastEventId } : {}
|
|
451
452
|
},
|
|
452
453
|
signal: this.abortController.signal
|
|
453
454
|
});
|
|
@@ -673,13 +674,167 @@ function normalizeUrl(url) {
|
|
|
673
674
|
return url;
|
|
674
675
|
}
|
|
675
676
|
|
|
677
|
+
// src/streaming/poll-policy.ts
|
|
678
|
+
var UNNAMED_RATE_LIMIT_WAIT_MS = 6e4;
|
|
679
|
+
function asDict(value) {
|
|
680
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
681
|
+
}
|
|
682
|
+
var RATE_LIMIT_CODES = /* @__PURE__ */ new Set([
|
|
683
|
+
"rate_limit_error",
|
|
684
|
+
"rate_limited",
|
|
685
|
+
"rate_limit_exceeded",
|
|
686
|
+
"too_many_requests"
|
|
687
|
+
]);
|
|
688
|
+
function isRateLimited(error) {
|
|
689
|
+
if (typeof error === "string") return /\b429\b/.test(error);
|
|
690
|
+
const err = asDict(error);
|
|
691
|
+
if (!err) return false;
|
|
692
|
+
for (const key of ["status", "statusCode", "httpStatus", "code"]) {
|
|
693
|
+
if (err[key] === 429 || err[key] === "429") return true;
|
|
694
|
+
}
|
|
695
|
+
const response = asDict(err.response);
|
|
696
|
+
if (response && (response.status === 429 || response.statusCode === 429)) return true;
|
|
697
|
+
if (typeof err.code === "string" && RATE_LIMIT_CODES.has(err.code.toLowerCase())) return true;
|
|
698
|
+
if (err.name === "RateLimitError") return true;
|
|
699
|
+
const message = typeof err.message === "string" ? err.message : "";
|
|
700
|
+
return /\b429\b/.test(message) || /rate[\s_-]?limit/i.test(message) || /too many requests/i.test(message);
|
|
701
|
+
}
|
|
702
|
+
function readHeader(bag, name) {
|
|
703
|
+
if (bag === null || bag === void 0) return null;
|
|
704
|
+
const getter = bag.get;
|
|
705
|
+
if (typeof getter === "function") {
|
|
706
|
+
try {
|
|
707
|
+
const value = getter.call(bag, name);
|
|
708
|
+
if (value !== null && value !== void 0) return String(value);
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
const dict = asDict(bag);
|
|
713
|
+
if (!dict) return null;
|
|
714
|
+
const wanted = name.toLowerCase();
|
|
715
|
+
for (const [key, value] of Object.entries(dict)) {
|
|
716
|
+
if (key.toLowerCase() === wanted && value !== null && value !== void 0) {
|
|
717
|
+
return String(value);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return null;
|
|
721
|
+
}
|
|
722
|
+
function parseRetryAfter(raw, now) {
|
|
723
|
+
if (raw === null || raw === void 0) return null;
|
|
724
|
+
if (typeof raw === "number") {
|
|
725
|
+
return Number.isFinite(raw) && raw >= 0 ? raw * 1e3 : null;
|
|
726
|
+
}
|
|
727
|
+
if (typeof raw !== "string") return null;
|
|
728
|
+
const trimmed = raw.trim();
|
|
729
|
+
if (trimmed === "") return null;
|
|
730
|
+
if (/^\d+(\.\d+)?$/.test(trimmed)) return Number(trimmed) * 1e3;
|
|
731
|
+
const at = Date.parse(trimmed);
|
|
732
|
+
return Number.isNaN(at) ? null : Math.max(0, at - now);
|
|
733
|
+
}
|
|
734
|
+
function parseResetAt(raw, now) {
|
|
735
|
+
if (raw === null || raw === void 0) return null;
|
|
736
|
+
const numeric = typeof raw === "number" ? raw : typeof raw === "string" && /^\d+(\.\d+)?$/.test(raw.trim()) ? Number(raw.trim()) : null;
|
|
737
|
+
if (numeric !== null) {
|
|
738
|
+
if (!Number.isFinite(numeric) || numeric < 0) return null;
|
|
739
|
+
if (numeric > 1e11) return Math.max(0, numeric - now);
|
|
740
|
+
if (numeric > 1e9) return Math.max(0, numeric * 1e3 - now);
|
|
741
|
+
return numeric * 1e3;
|
|
742
|
+
}
|
|
743
|
+
if (typeof raw !== "string") return null;
|
|
744
|
+
const at = Date.parse(raw.trim());
|
|
745
|
+
return Number.isNaN(at) ? null : Math.max(0, at - now);
|
|
746
|
+
}
|
|
747
|
+
function getRetryAfterMs(error, now = Date.now()) {
|
|
748
|
+
const err = asDict(error);
|
|
749
|
+
if (!err) return null;
|
|
750
|
+
const details = asDict(err.details);
|
|
751
|
+
const response = asDict(err.response);
|
|
752
|
+
const body = asDict(err.body) ?? asDict(response?.data);
|
|
753
|
+
const bodyError = asDict(body?.error);
|
|
754
|
+
const bodyDetails = asDict(bodyError?.details) ?? asDict(body?.details);
|
|
755
|
+
for (const source of [err, details, bodyDetails]) {
|
|
756
|
+
const ms = source?.retryAfterMs;
|
|
757
|
+
if (typeof ms === "number" && Number.isFinite(ms) && ms >= 0) return ms;
|
|
758
|
+
}
|
|
759
|
+
for (const source of [err, details, bodyDetails, bodyError]) {
|
|
760
|
+
const parsed = parseRetryAfter(source?.retryAfter, now);
|
|
761
|
+
if (parsed !== null) return parsed;
|
|
762
|
+
}
|
|
763
|
+
const headerBags = [err.headers, response?.headers, details?.headers, body?.headers];
|
|
764
|
+
for (const bag of headerBags) {
|
|
765
|
+
const parsed = parseRetryAfter(readHeader(bag, "retry-after"), now);
|
|
766
|
+
if (parsed !== null) return parsed;
|
|
767
|
+
}
|
|
768
|
+
for (const source of [details, bodyDetails, err]) {
|
|
769
|
+
for (const key of ["resetAt", "reset", "rateLimitReset"]) {
|
|
770
|
+
const parsed = parseResetAt(source?.[key], now);
|
|
771
|
+
if (parsed !== null) return parsed;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
for (const bag of headerBags) {
|
|
775
|
+
for (const header of ["x-ratelimit-reset", "ratelimit-reset"]) {
|
|
776
|
+
const parsed = parseResetAt(readHeader(bag, header), now);
|
|
777
|
+
if (parsed !== null) return parsed;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return null;
|
|
781
|
+
}
|
|
782
|
+
function getHttpStatus(error) {
|
|
783
|
+
const err = asDict(error);
|
|
784
|
+
if (!err) return null;
|
|
785
|
+
for (const key of ["status", "statusCode", "httpStatus"]) {
|
|
786
|
+
const value = err[key];
|
|
787
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
788
|
+
if (typeof value === "string" && /^\d{3}$/.test(value)) return Number(value);
|
|
789
|
+
}
|
|
790
|
+
const response = asDict(err.response);
|
|
791
|
+
for (const key of ["status", "statusCode"]) {
|
|
792
|
+
const value = response?.[key];
|
|
793
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
794
|
+
}
|
|
795
|
+
return null;
|
|
796
|
+
}
|
|
797
|
+
function isTerminalClientError(error) {
|
|
798
|
+
const status = getHttpStatus(error);
|
|
799
|
+
if (status === null) return false;
|
|
800
|
+
return status >= 400 && status < 500 && status !== 429 && status !== 408;
|
|
801
|
+
}
|
|
802
|
+
var FAILURE_GROWTH_FACTOR = 2;
|
|
803
|
+
var IDLE_GROWTH_FACTOR = 1.5;
|
|
804
|
+
function nextFailureDelayMs(currentMs, maxMs) {
|
|
805
|
+
return Math.min(Math.max(currentMs, 1) * FAILURE_GROWTH_FACTOR, maxMs);
|
|
806
|
+
}
|
|
807
|
+
function nextIdleDelayMs(currentMs, maxMs) {
|
|
808
|
+
return Math.min(Math.ceil(Math.max(currentMs, 1) * IDLE_GROWTH_FACTOR), maxMs);
|
|
809
|
+
}
|
|
810
|
+
function applyJitter(delayMs, ratio, random = Math.random) {
|
|
811
|
+
if (ratio <= 0) return delayMs;
|
|
812
|
+
return Math.round(delayMs * (1 + random() * ratio));
|
|
813
|
+
}
|
|
814
|
+
|
|
676
815
|
// src/streaming/stream-controller.ts
|
|
677
816
|
var DEFAULT_STREAMING_CONFIG = {
|
|
678
817
|
maxReconnectAttempts: 5,
|
|
679
818
|
reconnectBaseDelayMs: 1e3,
|
|
680
819
|
reconnectMaxDelayMs: 1e4,
|
|
820
|
+
// NOTE (unchanged, deliberately): this watchdog force-disconnects a HEALTHY
|
|
821
|
+
// SSE connection after 30s of silence and routes it through the same
|
|
822
|
+
// handleConnectionError path as a real transport failure. Ordinary LLM
|
|
823
|
+
// latency exceeds 30s routinely, so it fires against working streams — that
|
|
824
|
+
// is what drives sessions into the polling fallback in the first place. The
|
|
825
|
+
// fix is a server-side SSE heartbeat, not a bigger number here; raising this
|
|
826
|
+
// is a guess against a moving target. Everything below only bounds what the
|
|
827
|
+
// fallback costs once it has been entered.
|
|
681
828
|
activityTimeoutMs: 3e4,
|
|
682
|
-
pollingIntervalMs:
|
|
829
|
+
pollingIntervalMs: 5e3,
|
|
830
|
+
pollingMaxIntervalMs: 3e4,
|
|
831
|
+
pollingMaxConsecutiveFailures: 10,
|
|
832
|
+
pollingMaxConsecutiveRateLimits: 3,
|
|
833
|
+
pollingMaxConsecutiveClientErrors: 3,
|
|
834
|
+
pollingMaxDurationMs: 18e5,
|
|
835
|
+
pollingMaxRetryAfterMs: 3e5,
|
|
836
|
+
pollingJitterRatio: 0.1,
|
|
837
|
+
sseRetryIntervalMs: 6e4
|
|
683
838
|
};
|
|
684
839
|
var DEFAULT_POLLING_ENABLED = true;
|
|
685
840
|
var ExecutionStreamControllerImpl = class {
|
|
@@ -692,9 +847,24 @@ var ExecutionStreamControllerImpl = class {
|
|
|
692
847
|
seenEventIds = /* @__PURE__ */ new Set();
|
|
693
848
|
_lastEventId = null;
|
|
694
849
|
activityTimeoutId = null;
|
|
695
|
-
pollingIntervalId = null;
|
|
696
850
|
finalExecution = null;
|
|
697
851
|
finalError = null;
|
|
852
|
+
// --- Fallback polling state ---
|
|
853
|
+
// A self-rescheduling timeout, not setInterval: the delay has to change
|
|
854
|
+
// between ticks (that is what backoff IS), and a timeout chain also cannot
|
|
855
|
+
// stack overlapping requests the way a fixed interval does when the API is
|
|
856
|
+
// slow to answer.
|
|
857
|
+
pollTimeoutId = null;
|
|
858
|
+
pollDelayMs = 0;
|
|
859
|
+
pollConsecutiveFailures = 0;
|
|
860
|
+
pollConsecutiveRateLimits = 0;
|
|
861
|
+
pollConsecutiveClientErrors = 0;
|
|
862
|
+
/** When the loop last observed anything new — the clock the give-up bound runs on. */
|
|
863
|
+
pollLastProgressAt = 0;
|
|
864
|
+
pollInFlight = false;
|
|
865
|
+
lastPolledStatus = null;
|
|
866
|
+
sseRetryTimeoutId = null;
|
|
867
|
+
sseRetryInFlight = false;
|
|
698
868
|
// Event callbacks
|
|
699
869
|
listeners = {
|
|
700
870
|
log: [],
|
|
@@ -723,6 +893,39 @@ var ExecutionStreamControllerImpl = class {
|
|
|
723
893
|
this.config = { ...DEFAULT_STREAMING_CONFIG, ...options.config };
|
|
724
894
|
this.pollingEnabled = options.pollingEnabled ?? DEFAULT_POLLING_ENABLED;
|
|
725
895
|
}
|
|
896
|
+
// Resolved fallback-poll settings. Read through `??` rather than off the
|
|
897
|
+
// spread config so an explicit `undefined` in a caller's partial config still
|
|
898
|
+
// lands on the default instead of NaN-ing the arithmetic.
|
|
899
|
+
get pollBaseIntervalMs() {
|
|
900
|
+
return this.config.pollingIntervalMs ?? DEFAULT_STREAMING_CONFIG.pollingIntervalMs;
|
|
901
|
+
}
|
|
902
|
+
get pollMaxIntervalMs() {
|
|
903
|
+
return Math.max(
|
|
904
|
+
this.config.pollingMaxIntervalMs ?? DEFAULT_STREAMING_CONFIG.pollingMaxIntervalMs,
|
|
905
|
+
this.pollBaseIntervalMs
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
get pollMaxConsecutiveFailures() {
|
|
909
|
+
return this.config.pollingMaxConsecutiveFailures ?? DEFAULT_STREAMING_CONFIG.pollingMaxConsecutiveFailures;
|
|
910
|
+
}
|
|
911
|
+
get pollMaxConsecutiveRateLimits() {
|
|
912
|
+
return this.config.pollingMaxConsecutiveRateLimits ?? DEFAULT_STREAMING_CONFIG.pollingMaxConsecutiveRateLimits;
|
|
913
|
+
}
|
|
914
|
+
get pollMaxConsecutiveClientErrors() {
|
|
915
|
+
return this.config.pollingMaxConsecutiveClientErrors ?? DEFAULT_STREAMING_CONFIG.pollingMaxConsecutiveClientErrors;
|
|
916
|
+
}
|
|
917
|
+
get pollMaxDurationMs() {
|
|
918
|
+
return this.config.pollingMaxDurationMs ?? DEFAULT_STREAMING_CONFIG.pollingMaxDurationMs;
|
|
919
|
+
}
|
|
920
|
+
get pollMaxRetryAfterMs() {
|
|
921
|
+
return this.config.pollingMaxRetryAfterMs ?? DEFAULT_STREAMING_CONFIG.pollingMaxRetryAfterMs;
|
|
922
|
+
}
|
|
923
|
+
get pollJitterRatio() {
|
|
924
|
+
return this.config.pollingJitterRatio ?? DEFAULT_STREAMING_CONFIG.pollingJitterRatio;
|
|
925
|
+
}
|
|
926
|
+
get sseRetryIntervalMs() {
|
|
927
|
+
return this.config.sseRetryIntervalMs ?? DEFAULT_STREAMING_CONFIG.sseRetryIntervalMs;
|
|
928
|
+
}
|
|
726
929
|
/**
|
|
727
930
|
* Get the last event ID (for resume support)
|
|
728
931
|
*/
|
|
@@ -813,28 +1016,45 @@ var ExecutionStreamControllerImpl = class {
|
|
|
813
1016
|
console.log("[SDK:StreamController] executionId:", this.options.executionId);
|
|
814
1017
|
console.log("[SDK:StreamController] orgId:", this.options.orgId);
|
|
815
1018
|
console.log("[SDK:StreamController] apiKey:", authToken ? `${authToken.substring(0, 20)}...` : "MISSING");
|
|
816
|
-
this.sseClient
|
|
1019
|
+
if (this.sseClient) {
|
|
1020
|
+
this.sseClient.disconnect();
|
|
1021
|
+
this.sseClient = null;
|
|
1022
|
+
}
|
|
1023
|
+
const client = new SSEClient({
|
|
817
1024
|
url,
|
|
818
1025
|
authHeader: `Bearer ${authToken}`,
|
|
819
1026
|
orgId: this.options.orgId,
|
|
820
1027
|
fetch: this.options.fetch,
|
|
821
|
-
|
|
1028
|
+
// Resume from where this session left off. On a first connect this is
|
|
1029
|
+
// null and the header is omitted.
|
|
1030
|
+
lastEventId: this._lastEventId,
|
|
1031
|
+
onEvent: (event) => {
|
|
1032
|
+
if (this.sseClient !== client) return;
|
|
1033
|
+
this.handleEvent(event);
|
|
1034
|
+
},
|
|
822
1035
|
onError: (error) => {
|
|
1036
|
+
if (this.sseClient !== client) return;
|
|
823
1037
|
console.error("[SDK:StreamController] SSE error:", error);
|
|
824
1038
|
this.handleConnectionError(error);
|
|
825
1039
|
},
|
|
826
1040
|
onConnectionChange: (connected) => {
|
|
1041
|
+
if (this.sseClient !== client) return;
|
|
827
1042
|
console.log("[SDK:StreamController] SSE connection change:", connected);
|
|
828
1043
|
if (connected) {
|
|
829
1044
|
this.status = "connected";
|
|
830
1045
|
this.reconnectAttempts = 0;
|
|
1046
|
+
this.stopPolling();
|
|
831
1047
|
this.resetActivityTimeout();
|
|
832
1048
|
}
|
|
833
|
-
this.emit("connectionChange", {
|
|
1049
|
+
this.emit("connectionChange", {
|
|
1050
|
+
connected,
|
|
1051
|
+
usingFallback: this.status === "fallback_polling"
|
|
1052
|
+
});
|
|
834
1053
|
}
|
|
835
1054
|
});
|
|
1055
|
+
this.sseClient = client;
|
|
836
1056
|
try {
|
|
837
|
-
await
|
|
1057
|
+
await client.connect();
|
|
838
1058
|
console.log("[SDK:StreamController] SSE connect() completed");
|
|
839
1059
|
} catch (error) {
|
|
840
1060
|
console.error("[SDK:StreamController] SSE connect() threw:", error);
|
|
@@ -1073,6 +1293,7 @@ var ExecutionStreamControllerImpl = class {
|
|
|
1073
1293
|
handleComplete(data) {
|
|
1074
1294
|
this.status = "closed";
|
|
1075
1295
|
this.stopActivityTimeout();
|
|
1296
|
+
this.stopPolling();
|
|
1076
1297
|
const sessionId = data.sessionId ?? this.options.sessionId;
|
|
1077
1298
|
const execution = {
|
|
1078
1299
|
uuid: this.options.executionId,
|
|
@@ -1099,6 +1320,7 @@ var ExecutionStreamControllerImpl = class {
|
|
|
1099
1320
|
handleError(error) {
|
|
1100
1321
|
this.status = "closed";
|
|
1101
1322
|
this.stopActivityTimeout();
|
|
1323
|
+
this.stopPolling();
|
|
1102
1324
|
this.finalError = error;
|
|
1103
1325
|
this.emit("error", error);
|
|
1104
1326
|
if (this.waitReject) {
|
|
@@ -1125,6 +1347,10 @@ var ExecutionStreamControllerImpl = class {
|
|
|
1125
1347
|
this.handleError({ error: msg, errorCode: "stream_unrecoverable" });
|
|
1126
1348
|
return;
|
|
1127
1349
|
}
|
|
1350
|
+
if (this.status === "fallback_polling") {
|
|
1351
|
+
this.startPolling();
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1128
1354
|
if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
|
|
1129
1355
|
this.status = "reconnecting";
|
|
1130
1356
|
this.reconnectAttempts++;
|
|
@@ -1194,41 +1420,215 @@ var ExecutionStreamControllerImpl = class {
|
|
|
1194
1420
|
}
|
|
1195
1421
|
}
|
|
1196
1422
|
/**
|
|
1197
|
-
* Start polling fallback
|
|
1423
|
+
* Start polling fallback.
|
|
1424
|
+
*
|
|
1425
|
+
* Idempotent — calling it while a loop is already running is a no-op, so no
|
|
1426
|
+
* path can end up with two loops racing the same execution.
|
|
1198
1427
|
*/
|
|
1199
1428
|
startPolling() {
|
|
1200
|
-
this.
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1429
|
+
if (this.pollTimeoutId !== null || this.pollInFlight) {
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
this.pollLastProgressAt = Date.now();
|
|
1433
|
+
this.pollDelayMs = this.pollBaseIntervalMs;
|
|
1434
|
+
this.pollConsecutiveFailures = 0;
|
|
1435
|
+
this.pollConsecutiveRateLimits = 0;
|
|
1436
|
+
this.pollConsecutiveClientErrors = 0;
|
|
1437
|
+
this.lastPolledStatus = null;
|
|
1438
|
+
this.stopActivityTimeout();
|
|
1439
|
+
this.scheduleSSERetry();
|
|
1440
|
+
this.schedulePoll(this.pollDelayMs);
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Queue the next poll tick.
|
|
1444
|
+
*/
|
|
1445
|
+
schedulePoll(delayMs) {
|
|
1446
|
+
if (this.status !== "fallback_polling") {
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
this.pollTimeoutId = setTimeout(() => {
|
|
1450
|
+
this.pollTimeoutId = null;
|
|
1451
|
+
void this.runPoll();
|
|
1452
|
+
}, Math.max(0, Math.round(delayMs)));
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* One poll tick: fetch state, emit what is new, then decide how long to wait
|
|
1456
|
+
* before the next one — or whether there should be a next one at all.
|
|
1457
|
+
*/
|
|
1458
|
+
async runPoll() {
|
|
1459
|
+
if (this.status !== "fallback_polling") {
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
if (Date.now() - this.pollLastProgressAt >= this.pollMaxDurationMs) {
|
|
1463
|
+
this.failPolling(
|
|
1464
|
+
`Streaming fallback gave up: no execution progress for ${Math.round(this.pollMaxDurationMs / 1e3)}s`,
|
|
1465
|
+
"polling_timeout"
|
|
1466
|
+
);
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
this.pollInFlight = true;
|
|
1470
|
+
try {
|
|
1471
|
+
const execution = await this.options.getExecution(this.options.executionId);
|
|
1472
|
+
this.pollConsecutiveFailures = 0;
|
|
1473
|
+
this.pollConsecutiveRateLimits = 0;
|
|
1474
|
+
this.pollConsecutiveClientErrors = 0;
|
|
1475
|
+
let sawNewInfo = false;
|
|
1476
|
+
for (const log of execution.logs ?? []) {
|
|
1477
|
+
if (!this.seenEventIds.has(log.uuid)) {
|
|
1478
|
+
this.seenEventIds.add(log.uuid);
|
|
1479
|
+
this.emit("log", log);
|
|
1480
|
+
sawNewInfo = true;
|
|
1218
1481
|
}
|
|
1219
|
-
} catch (error) {
|
|
1220
|
-
console.error("Polling error:", error);
|
|
1221
1482
|
}
|
|
1222
|
-
|
|
1483
|
+
if (execution.status !== this.lastPolledStatus) {
|
|
1484
|
+
this.lastPolledStatus = execution.status;
|
|
1485
|
+
sawNewInfo = true;
|
|
1486
|
+
}
|
|
1487
|
+
if (sawNewInfo) {
|
|
1488
|
+
this.pollLastProgressAt = Date.now();
|
|
1489
|
+
}
|
|
1490
|
+
if (execution.status === "completed") {
|
|
1491
|
+
this.stopPolling();
|
|
1492
|
+
this.handleComplete(execution);
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
if (execution.status === "failed" || execution.status === "cancelled") {
|
|
1496
|
+
this.stopPolling();
|
|
1497
|
+
this.handleError({
|
|
1498
|
+
error: execution.error ?? `Execution ${execution.status}`,
|
|
1499
|
+
errorCode: execution.status
|
|
1500
|
+
});
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
this.pollDelayMs = sawNewInfo ? this.pollBaseIntervalMs : nextIdleDelayMs(this.pollDelayMs, this.pollMaxIntervalMs);
|
|
1504
|
+
} catch (error) {
|
|
1505
|
+
if (!this.handlePollError(error)) {
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
} finally {
|
|
1509
|
+
this.pollInFlight = false;
|
|
1510
|
+
}
|
|
1511
|
+
this.schedulePoll(applyJitter(this.pollDelayMs, this.pollJitterRatio));
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Apply backpressure for a failed poll.
|
|
1515
|
+
*
|
|
1516
|
+
* @returns `true` to keep polling (with `pollDelayMs` updated), `false` when
|
|
1517
|
+
* the loop has been terminated.
|
|
1518
|
+
*/
|
|
1519
|
+
handlePollError(error) {
|
|
1520
|
+
const retryAfterMs = getRetryAfterMs(error);
|
|
1521
|
+
const rateLimited = isRateLimited(error) || retryAfterMs !== null;
|
|
1522
|
+
if (rateLimited) {
|
|
1523
|
+
this.pollConsecutiveRateLimits++;
|
|
1524
|
+
console.warn(
|
|
1525
|
+
"[SDK:StreamController] Poll rate-limited",
|
|
1526
|
+
retryAfterMs !== null ? `(server asked for ${Math.round(retryAfterMs / 1e3)}s)` : "(no reset named)"
|
|
1527
|
+
);
|
|
1528
|
+
if (retryAfterMs !== null && retryAfterMs > this.pollMaxRetryAfterMs) {
|
|
1529
|
+
this.failPolling(
|
|
1530
|
+
`Rate limited: the API asked for ${Math.round(retryAfterMs / 1e3)}s, longer than this stream will wait`,
|
|
1531
|
+
"rate_limited"
|
|
1532
|
+
);
|
|
1533
|
+
return false;
|
|
1534
|
+
}
|
|
1535
|
+
if (this.pollConsecutiveRateLimits >= this.pollMaxConsecutiveRateLimits) {
|
|
1536
|
+
this.failPolling(
|
|
1537
|
+
"Rate limited by the API; stopped the streaming fallback rather than keep spending the key quota",
|
|
1538
|
+
"rate_limited"
|
|
1539
|
+
);
|
|
1540
|
+
return false;
|
|
1541
|
+
}
|
|
1542
|
+
this.pollDelayMs = Math.max(retryAfterMs ?? UNNAMED_RATE_LIMIT_WAIT_MS, this.pollDelayMs);
|
|
1543
|
+
return true;
|
|
1544
|
+
}
|
|
1545
|
+
if (isTerminalClientError(error)) {
|
|
1546
|
+
this.pollConsecutiveClientErrors++;
|
|
1547
|
+
const status = getHttpStatus(error);
|
|
1548
|
+
console.warn(
|
|
1549
|
+
`[SDK:StreamController] Poll got HTTP ${status} (${this.pollConsecutiveClientErrors}/${this.pollMaxConsecutiveClientErrors})`
|
|
1550
|
+
);
|
|
1551
|
+
if (this.pollConsecutiveClientErrors >= this.pollMaxConsecutiveClientErrors) {
|
|
1552
|
+
this.failPolling(
|
|
1553
|
+
`Execution status endpoint returned HTTP ${status} ${this.pollConsecutiveClientErrors} times \u2014 cannot track this run`,
|
|
1554
|
+
"polling_unrecoverable"
|
|
1555
|
+
);
|
|
1556
|
+
return false;
|
|
1557
|
+
}
|
|
1558
|
+
this.pollDelayMs = nextFailureDelayMs(this.pollDelayMs, this.pollMaxIntervalMs);
|
|
1559
|
+
return true;
|
|
1560
|
+
}
|
|
1561
|
+
this.pollConsecutiveFailures++;
|
|
1562
|
+
console.warn(
|
|
1563
|
+
`[SDK:StreamController] Poll failed (${this.pollConsecutiveFailures}/${this.pollMaxConsecutiveFailures}):`,
|
|
1564
|
+
error
|
|
1565
|
+
);
|
|
1566
|
+
if (this.pollConsecutiveFailures >= this.pollMaxConsecutiveFailures) {
|
|
1567
|
+
this.failPolling(
|
|
1568
|
+
`Streaming fallback failed ${this.pollConsecutiveFailures} times in a row`,
|
|
1569
|
+
"polling_failed"
|
|
1570
|
+
);
|
|
1571
|
+
return false;
|
|
1572
|
+
}
|
|
1573
|
+
this.pollDelayMs = nextFailureDelayMs(this.pollDelayMs, this.pollMaxIntervalMs);
|
|
1574
|
+
return true;
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Terminate the fallback loop and surface the reason.
|
|
1578
|
+
*/
|
|
1579
|
+
failPolling(error, errorCode) {
|
|
1580
|
+
this.stopPolling();
|
|
1581
|
+
this.handleError({ error, errorCode });
|
|
1223
1582
|
}
|
|
1224
1583
|
/**
|
|
1225
|
-
* Stop polling
|
|
1584
|
+
* Stop polling, including the periodic SSE re-attempt that belongs to it.
|
|
1226
1585
|
*/
|
|
1227
1586
|
stopPolling() {
|
|
1228
|
-
if (this.
|
|
1229
|
-
|
|
1230
|
-
this.
|
|
1587
|
+
if (this.pollTimeoutId !== null) {
|
|
1588
|
+
clearTimeout(this.pollTimeoutId);
|
|
1589
|
+
this.pollTimeoutId = null;
|
|
1590
|
+
}
|
|
1591
|
+
if (this.sseRetryTimeoutId !== null) {
|
|
1592
|
+
clearTimeout(this.sseRetryTimeoutId);
|
|
1593
|
+
this.sseRetryTimeoutId = null;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Queue the next attempt to get the real stream back.
|
|
1598
|
+
*/
|
|
1599
|
+
scheduleSSERetry() {
|
|
1600
|
+
if (this.sseRetryTimeoutId !== null || this.status !== "fallback_polling") {
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
this.sseRetryTimeoutId = setTimeout(() => {
|
|
1604
|
+
this.sseRetryTimeoutId = null;
|
|
1605
|
+
this.attemptSSERecovery();
|
|
1606
|
+
}, this.sseRetryIntervalMs);
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Re-attempt SSE from inside the fallback, so a transient outage costs the
|
|
1610
|
+
* session a few polls rather than its stream for the lifetime of the tab.
|
|
1611
|
+
*
|
|
1612
|
+
* Success is NOT observed here: `SSEClient.connect()` resolves when the
|
|
1613
|
+
* stream ENDS, not when it opens. The open is observed by
|
|
1614
|
+
* `onConnectionChange(true)`, which flips status and stops this loop. The
|
|
1615
|
+
* promise below only tells us the attempt is over so the next one can be
|
|
1616
|
+
* queued.
|
|
1617
|
+
*/
|
|
1618
|
+
attemptSSERecovery() {
|
|
1619
|
+
if (this.status !== "fallback_polling") {
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
if (this.sseRetryInFlight) {
|
|
1623
|
+
this.scheduleSSERetry();
|
|
1624
|
+
return;
|
|
1231
1625
|
}
|
|
1626
|
+
this.sseRetryInFlight = true;
|
|
1627
|
+
void this.connectSSE().catch(() => {
|
|
1628
|
+
}).finally(() => {
|
|
1629
|
+
this.sseRetryInFlight = false;
|
|
1630
|
+
this.scheduleSSERetry();
|
|
1631
|
+
});
|
|
1232
1632
|
}
|
|
1233
1633
|
/**
|
|
1234
1634
|
* Reset activity timeout
|
|
@@ -1360,12 +1760,23 @@ async function collectImagesFromStream(stream, options = {}) {
|
|
|
1360
1760
|
});
|
|
1361
1761
|
}
|
|
1362
1762
|
|
|
1763
|
+
// src/utils/api-paths.ts
|
|
1764
|
+
var API_V1 = "/api/v1";
|
|
1765
|
+
var EXECUTION_PATH = `${API_V1}/executions`;
|
|
1766
|
+
function executionPath(executionId) {
|
|
1767
|
+
return `${EXECUTION_PATH}/${executionId}`;
|
|
1768
|
+
}
|
|
1769
|
+
function executionCancelPath(executionId) {
|
|
1770
|
+
return `${EXECUTION_PATH}/${executionId}/cancel`;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1363
1773
|
// src/resources/agents.ts
|
|
1364
1774
|
var AgentsAPI = class extends BaseResourceAPI {
|
|
1365
1775
|
constructor(http, getStreamConfig) {
|
|
1366
1776
|
super(http, "/api/v1/agents");
|
|
1367
1777
|
this.getStreamConfig = getStreamConfig;
|
|
1368
1778
|
}
|
|
1779
|
+
getStreamConfig;
|
|
1369
1780
|
// ===== LIST Operations =====
|
|
1370
1781
|
/**
|
|
1371
1782
|
* List all agents in the organization
|
|
@@ -1622,7 +2033,7 @@ var AgentsAPI = class extends BaseResourceAPI {
|
|
|
1622
2033
|
* ```
|
|
1623
2034
|
*/
|
|
1624
2035
|
async getExecution(executionId) {
|
|
1625
|
-
return this.http.get(
|
|
2036
|
+
return this.http.get(executionPath(executionId));
|
|
1626
2037
|
}
|
|
1627
2038
|
// ===== EDIT Operations =====
|
|
1628
2039
|
/**
|
|
@@ -1677,7 +2088,7 @@ var AgentsAPI = class extends BaseResourceAPI {
|
|
|
1677
2088
|
*/
|
|
1678
2089
|
async cancelExecution(executionId) {
|
|
1679
2090
|
return this.http.post(
|
|
1680
|
-
|
|
2091
|
+
executionCancelPath(executionId),
|
|
1681
2092
|
void 0,
|
|
1682
2093
|
{ skipRetry: true }
|
|
1683
2094
|
);
|
|
@@ -2178,6 +2589,7 @@ var ArtifactsAPI = class extends BaseResourceAPI {
|
|
|
2178
2589
|
}
|
|
2179
2590
|
return this.http.request({
|
|
2180
2591
|
method: "POST",
|
|
2592
|
+
// KNOWN BROKEN — same missing `/api/v1` prefix as listArtifacts above.
|
|
2181
2593
|
path: `/executions/${executionId}/artifacts`,
|
|
2182
2594
|
body: formData,
|
|
2183
2595
|
headers: {
|
|
@@ -2271,6 +2683,7 @@ var SessionsAPI = class extends BaseResourceAPI {
|
|
|
2271
2683
|
super(http, "/api/v1/sessions");
|
|
2272
2684
|
this.getStreamConfig = getStreamConfig;
|
|
2273
2685
|
}
|
|
2686
|
+
getStreamConfig;
|
|
2274
2687
|
// ===== LIST Operations =====
|
|
2275
2688
|
/**
|
|
2276
2689
|
* List all sessions in the organization
|
|
@@ -2450,7 +2863,7 @@ var SessionsAPI = class extends BaseResourceAPI {
|
|
|
2450
2863
|
* Get execution result
|
|
2451
2864
|
*/
|
|
2452
2865
|
async getExecution(executionId) {
|
|
2453
|
-
return this.http.get(
|
|
2866
|
+
return this.http.get(executionPath(executionId));
|
|
2454
2867
|
}
|
|
2455
2868
|
// ===== EDIT Operations =====
|
|
2456
2869
|
/**
|
|
@@ -2590,6 +3003,7 @@ var KanbanAPI = class extends BaseResourceAPI {
|
|
|
2590
3003
|
super(http, "/api/v1/kanban");
|
|
2591
3004
|
this.getStreamConfig = getStreamConfig;
|
|
2592
3005
|
}
|
|
3006
|
+
getStreamConfig;
|
|
2593
3007
|
// ===== BOARD =====
|
|
2594
3008
|
/**
|
|
2595
3009
|
* Get the current org's board (lanes in declared order). Auto-provisions
|
|
@@ -2724,7 +3138,7 @@ var KanbanAPI = class extends BaseResourceAPI {
|
|
|
2724
3138
|
* @returns Execution details.
|
|
2725
3139
|
*/
|
|
2726
3140
|
async getCardRun(executionId) {
|
|
2727
|
-
return this.http.get(
|
|
3141
|
+
return this.http.get(executionPath(executionId));
|
|
2728
3142
|
}
|
|
2729
3143
|
/**
|
|
2730
3144
|
* Create a stream controller for a card's run, keyed on the card's
|
|
@@ -2791,6 +3205,7 @@ var RemoteAgentsAPI = class extends BaseResourceAPI {
|
|
|
2791
3205
|
super(http, "/api/v1/remote-agents");
|
|
2792
3206
|
this.getStreamConfig = getStreamConfig;
|
|
2793
3207
|
}
|
|
3208
|
+
getStreamConfig;
|
|
2794
3209
|
/**
|
|
2795
3210
|
* List all remote agents in the organization
|
|
2796
3211
|
*
|
|
@@ -2924,7 +3339,7 @@ var RemoteAgentsAPI = class extends BaseResourceAPI {
|
|
|
2924
3339
|
apiKey: config.apiKey,
|
|
2925
3340
|
tokenProvider: config.tokenProvider,
|
|
2926
3341
|
orgId: config.orgId,
|
|
2927
|
-
getExecution: (id) => this.http.get(
|
|
3342
|
+
getExecution: (id) => this.http.get(executionPath(id))
|
|
2928
3343
|
});
|
|
2929
3344
|
return controller;
|
|
2930
3345
|
}
|
|
@@ -4005,6 +4420,13 @@ function initialState() {
|
|
|
4005
4420
|
|
|
4006
4421
|
// src/chat/hooks/useAgentChat.ts
|
|
4007
4422
|
var __DEV__ = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
4423
|
+
var LEGACY_POLL_BASE_INTERVAL_MS = 5e3;
|
|
4424
|
+
var LEGACY_POLL_MAX_INTERVAL_MS = 3e4;
|
|
4425
|
+
var LEGACY_POLL_MAX_FAILURES = 10;
|
|
4426
|
+
var LEGACY_POLL_MAX_RATE_LIMITS = 3;
|
|
4427
|
+
var LEGACY_POLL_MAX_IDLE_MS = 18e5;
|
|
4428
|
+
var LEGACY_POLL_MAX_RETRY_AFTER_MS = 3e5;
|
|
4429
|
+
var LEGACY_POLL_JITTER_RATIO = 0.1;
|
|
4008
4430
|
var SILENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
4009
4431
|
"check_delegations"
|
|
4010
4432
|
]);
|
|
@@ -4592,12 +5014,17 @@ function useAgentChat(options) {
|
|
|
4592
5014
|
}
|
|
4593
5015
|
}
|
|
4594
5016
|
});
|
|
4595
|
-
const
|
|
5017
|
+
const pollingTimeoutRef = react.useRef(null);
|
|
4596
5018
|
const pollingExecutionIdRef = react.useRef(null);
|
|
5019
|
+
const pollDelayRef = react.useRef(0);
|
|
5020
|
+
const pollFailuresRef = react.useRef(0);
|
|
5021
|
+
const pollRateLimitsRef = react.useRef(0);
|
|
5022
|
+
const pollLastProgressRef = react.useRef(0);
|
|
5023
|
+
const pollLastStatusRef = react.useRef(null);
|
|
4597
5024
|
const stopPolling = react.useCallback(() => {
|
|
4598
|
-
if (
|
|
4599
|
-
|
|
4600
|
-
|
|
5025
|
+
if (pollingTimeoutRef.current) {
|
|
5026
|
+
clearTimeout(pollingTimeoutRef.current);
|
|
5027
|
+
pollingTimeoutRef.current = null;
|
|
4601
5028
|
}
|
|
4602
5029
|
pollingExecutionIdRef.current = null;
|
|
4603
5030
|
}, []);
|
|
@@ -4605,26 +5032,77 @@ function useAgentChat(options) {
|
|
|
4605
5032
|
if (pollingExecutionIdRef.current === executionId) return;
|
|
4606
5033
|
stopPolling();
|
|
4607
5034
|
pollingExecutionIdRef.current = executionId;
|
|
5035
|
+
const baseDelayMs = pollingInterval ?? LEGACY_POLL_BASE_INTERVAL_MS;
|
|
5036
|
+
pollDelayRef.current = baseDelayMs;
|
|
5037
|
+
pollFailuresRef.current = 0;
|
|
5038
|
+
pollRateLimitsRef.current = 0;
|
|
5039
|
+
pollLastProgressRef.current = Date.now();
|
|
5040
|
+
pollLastStatusRef.current = null;
|
|
4608
5041
|
if (__DEV__) console.log("[useAgentChat] Starting polling fallback for:", executionId);
|
|
5042
|
+
const schedule = (delayMs) => {
|
|
5043
|
+
if (pollingExecutionIdRef.current !== executionId) return;
|
|
5044
|
+
pollingTimeoutRef.current = setTimeout(() => {
|
|
5045
|
+
pollingTimeoutRef.current = null;
|
|
5046
|
+
void poll();
|
|
5047
|
+
}, Math.max(0, Math.round(delayMs)));
|
|
5048
|
+
};
|
|
5049
|
+
const giveUp = (message) => {
|
|
5050
|
+
if (__DEV__) console.warn("[useAgentChat] Polling gave up:", message);
|
|
5051
|
+
stopPolling();
|
|
5052
|
+
handleError(message);
|
|
5053
|
+
};
|
|
4609
5054
|
const poll = async () => {
|
|
4610
5055
|
if (pollingExecutionIdRef.current !== executionId) return;
|
|
5056
|
+
if (Date.now() - pollLastProgressRef.current >= LEGACY_POLL_MAX_IDLE_MS) {
|
|
5057
|
+
giveUp("Lost the live connection and stopped receiving updates for this run");
|
|
5058
|
+
return;
|
|
5059
|
+
}
|
|
4611
5060
|
try {
|
|
4612
5061
|
const execution = await adapter.getExecution(executionId);
|
|
5062
|
+
pollFailuresRef.current = 0;
|
|
5063
|
+
pollRateLimitsRef.current = 0;
|
|
5064
|
+
if (execution.status !== pollLastStatusRef.current) {
|
|
5065
|
+
pollLastStatusRef.current = execution.status;
|
|
5066
|
+
pollLastProgressRef.current = Date.now();
|
|
5067
|
+
pollDelayRef.current = baseDelayMs;
|
|
5068
|
+
} else {
|
|
5069
|
+
pollDelayRef.current = nextIdleDelayMs(pollDelayRef.current, LEGACY_POLL_MAX_INTERVAL_MS);
|
|
5070
|
+
}
|
|
4613
5071
|
if (execution.status === "completed") {
|
|
4614
5072
|
if (__DEV__) console.log("[useAgentChat] Polling: execution completed");
|
|
4615
5073
|
stopPolling();
|
|
4616
5074
|
handleComplete(execution.result || void 0);
|
|
4617
|
-
|
|
5075
|
+
return;
|
|
5076
|
+
}
|
|
5077
|
+
if (execution.status === "failed") {
|
|
4618
5078
|
if (__DEV__) console.log("[useAgentChat] Polling: execution failed");
|
|
4619
5079
|
stopPolling();
|
|
4620
5080
|
handleError(execution.error || "Execution failed");
|
|
5081
|
+
return;
|
|
4621
5082
|
}
|
|
4622
5083
|
} catch (err) {
|
|
4623
|
-
|
|
5084
|
+
const retryAfterMs = getRetryAfterMs(err);
|
|
5085
|
+
if (isRateLimited(err) || retryAfterMs !== null) {
|
|
5086
|
+
pollRateLimitsRef.current++;
|
|
5087
|
+
const resetTooFarOut = retryAfterMs !== null && retryAfterMs > LEGACY_POLL_MAX_RETRY_AFTER_MS;
|
|
5088
|
+
if (resetTooFarOut || pollRateLimitsRef.current >= LEGACY_POLL_MAX_RATE_LIMITS) {
|
|
5089
|
+
giveUp("Rate limited by the API \u2014 stopped polling for updates on this run");
|
|
5090
|
+
return;
|
|
5091
|
+
}
|
|
5092
|
+
pollDelayRef.current = Math.max(retryAfterMs ?? UNNAMED_RATE_LIMIT_WAIT_MS, pollDelayRef.current);
|
|
5093
|
+
} else {
|
|
5094
|
+
pollFailuresRef.current++;
|
|
5095
|
+
if (__DEV__) console.warn("[useAgentChat] Polling error (will retry):", err);
|
|
5096
|
+
if (pollFailuresRef.current >= LEGACY_POLL_MAX_FAILURES) {
|
|
5097
|
+
giveUp("Lost connection to the agent \u2014 stopped polling for updates on this run");
|
|
5098
|
+
return;
|
|
5099
|
+
}
|
|
5100
|
+
pollDelayRef.current = nextFailureDelayMs(pollDelayRef.current, LEGACY_POLL_MAX_INTERVAL_MS);
|
|
5101
|
+
}
|
|
4624
5102
|
}
|
|
5103
|
+
schedule(applyJitter(pollDelayRef.current, LEGACY_POLL_JITTER_RATIO));
|
|
4625
5104
|
};
|
|
4626
|
-
poll();
|
|
4627
|
-
pollingIntervalRef.current = setInterval(poll, pollingInterval ?? 2e3);
|
|
5105
|
+
void poll();
|
|
4628
5106
|
}, [adapter, stopPolling, handleComplete, handleError, pollingInterval]);
|
|
4629
5107
|
react.useEffect(() => {
|
|
4630
5108
|
if (!useStreamController && isUsingFallback && currentExecutionId && isLoading && pollingEnabled !== false) {
|