@anuma/sdk 10.5.4 → 10.6.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/expo/index.cjs +30 -12
- package/dist/expo/index.d.mts +2 -0
- package/dist/expo/index.d.ts +2 -0
- package/dist/expo/index.mjs +29 -12
- package/dist/react/index.cjs +172 -24
- package/dist/react/index.d.mts +24 -5
- package/dist/react/index.d.ts +24 -5
- package/dist/react/index.mjs +171 -24
- package/dist/server/index.cjs +30 -12
- package/dist/server/index.d.mts +2 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.mjs +29 -12
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -6818,6 +6818,7 @@ function count(value) {
|
|
|
6818
6818
|
|
|
6819
6819
|
// src/lib/chat/resumeStream.ts
|
|
6820
6820
|
init_clientConfig();
|
|
6821
|
+
init_redactor();
|
|
6821
6822
|
|
|
6822
6823
|
// src/lib/chat/toolLoop.ts
|
|
6823
6824
|
init_clientConfig();
|
|
@@ -11164,16 +11165,34 @@ async function resumeStream(options) {
|
|
|
11164
11165
|
onData,
|
|
11165
11166
|
onThinking,
|
|
11166
11167
|
onFinish,
|
|
11167
|
-
onError
|
|
11168
|
+
onError,
|
|
11169
|
+
piiRedactor
|
|
11168
11170
|
} = options;
|
|
11169
11171
|
const strategy = getStrategy(handle.apiType);
|
|
11170
11172
|
const accumulator = createStreamAccumulator(handle.model || void 0);
|
|
11173
|
+
const contentDeAnon = piiRedactor && onData ? createStreamingDeAnonymizer(piiRedactor, onData) : null;
|
|
11174
|
+
const thinkingDeAnon = piiRedactor && onThinking ? createStreamingDeAnonymizer(piiRedactor, onThinking) : null;
|
|
11171
11175
|
const contentSmoother = new StreamSmoother((text16) => {
|
|
11172
|
-
if (
|
|
11176
|
+
if (contentDeAnon) contentDeAnon.push(text16);
|
|
11177
|
+
else if (onData) onData(text16);
|
|
11173
11178
|
}, smoothing);
|
|
11174
11179
|
const thinkingSmoother = new StreamSmoother((text16) => {
|
|
11175
|
-
if (
|
|
11180
|
+
if (thinkingDeAnon) thinkingDeAnon.push(text16);
|
|
11181
|
+
else if (onThinking) onThinking(text16);
|
|
11176
11182
|
}, smoothing);
|
|
11183
|
+
const flushOutput = () => {
|
|
11184
|
+
contentSmoother.flush();
|
|
11185
|
+
thinkingSmoother.flush();
|
|
11186
|
+
contentDeAnon?.flush();
|
|
11187
|
+
thinkingDeAnon?.flush();
|
|
11188
|
+
};
|
|
11189
|
+
const buildFinal = () => strategy.buildFinalResponse(
|
|
11190
|
+
piiRedactor ? {
|
|
11191
|
+
...accumulator,
|
|
11192
|
+
content: piiRedactor.deAnonymize(accumulator.content),
|
|
11193
|
+
thinking: piiRedactor.deAnonymize(accumulator.thinking)
|
|
11194
|
+
} : accumulator
|
|
11195
|
+
);
|
|
11177
11196
|
const idleController = new AbortController();
|
|
11178
11197
|
let watchdog;
|
|
11179
11198
|
let idleFired = false;
|
|
@@ -11218,9 +11237,8 @@ async function resumeStream(options) {
|
|
|
11218
11237
|
if (signal) signal.removeEventListener("abort", onCallerAbort);
|
|
11219
11238
|
};
|
|
11220
11239
|
const buildInterrupted = (message) => {
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(strategy.buildFinalResponse(accumulator)) : strategy.buildFinalResponse(accumulator);
|
|
11240
|
+
flushOutput();
|
|
11241
|
+
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(buildFinal()) : buildFinal();
|
|
11224
11242
|
return { data, error: message, interrupted: true };
|
|
11225
11243
|
};
|
|
11226
11244
|
if (combinedSignal.aborted) {
|
|
@@ -11268,18 +11286,16 @@ async function resumeStream(options) {
|
|
|
11268
11286
|
const err = replayErr instanceof Error ? replayErr : new Error(String(replayErr));
|
|
11269
11287
|
const statusCode = parseSseStatusCode(err);
|
|
11270
11288
|
if (statusCode === 410) {
|
|
11271
|
-
|
|
11272
|
-
thinkingSmoother.flush();
|
|
11289
|
+
flushOutput();
|
|
11273
11290
|
throw new StreamExpiredError(handle.inferenceId);
|
|
11274
11291
|
}
|
|
11275
11292
|
if (err.name === "AbortError" || combinedSignal.aborted) {
|
|
11276
11293
|
return buildInterrupted(abortMessage());
|
|
11277
11294
|
}
|
|
11278
|
-
|
|
11279
|
-
thinkingSmoother.flush();
|
|
11295
|
+
flushOutput();
|
|
11280
11296
|
if (onError) onError(err);
|
|
11281
11297
|
return {
|
|
11282
|
-
data:
|
|
11298
|
+
data: buildFinal(),
|
|
11283
11299
|
error: err.message,
|
|
11284
11300
|
interrupted: false,
|
|
11285
11301
|
statusCode
|
|
@@ -11295,7 +11311,9 @@ async function resumeStream(options) {
|
|
|
11295
11311
|
draining = true;
|
|
11296
11312
|
await Promise.all([contentSmoother.drain(), thinkingSmoother.drain()]);
|
|
11297
11313
|
if (playbackAborted) return buildInterrupted(abortMessage());
|
|
11298
|
-
|
|
11314
|
+
contentDeAnon?.flush();
|
|
11315
|
+
thinkingDeAnon?.flush();
|
|
11316
|
+
const response = buildFinal();
|
|
11299
11317
|
const deliveredOutput = emittedOutput || (accumulator.toolCallEvents?.length ?? 0) > 0;
|
|
11300
11318
|
if (onFinish && deliveredOutput) onFinish(response);
|
|
11301
11319
|
return { data: response, error: null, interrupted: false, empty: !deliveredOutput };
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -2753,6 +2753,8 @@ interface ResumeStreamOptions {
|
|
|
2753
2753
|
onData?: (chunk: string) => void;
|
|
2754
2754
|
/** Thinking/reasoning deltas as they replay. */
|
|
2755
2755
|
onThinking?: (chunk: string) => void;
|
|
2756
|
+
/** Restores the placeholders this redactor assigned when the original request was sent. */
|
|
2757
|
+
piiRedactor?: PiiRedactor;
|
|
2756
2758
|
/** Called once on a clean completion. Never called for 410 nor interrupted terminals. */
|
|
2757
2759
|
onFinish?: (response: ApiResponse) => void;
|
|
2758
2760
|
/** Called on a transient/unexpected failure. Never called for 410 (throws) nor interrupted terminals. */
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -2753,6 +2753,8 @@ interface ResumeStreamOptions {
|
|
|
2753
2753
|
onData?: (chunk: string) => void;
|
|
2754
2754
|
/** Thinking/reasoning deltas as they replay. */
|
|
2755
2755
|
onThinking?: (chunk: string) => void;
|
|
2756
|
+
/** Restores the placeholders this redactor assigned when the original request was sent. */
|
|
2757
|
+
piiRedactor?: PiiRedactor;
|
|
2756
2758
|
/** Called once on a clean completion. Never called for 410 nor interrupted terminals. */
|
|
2757
2759
|
onFinish?: (response: ApiResponse) => void;
|
|
2758
2760
|
/** Called on a transient/unexpected failure. Never called for 410 (throws) nor interrupted terminals. */
|
package/dist/expo/index.mjs
CHANGED
|
@@ -9497,16 +9497,34 @@ async function resumeStream(options) {
|
|
|
9497
9497
|
onData,
|
|
9498
9498
|
onThinking,
|
|
9499
9499
|
onFinish,
|
|
9500
|
-
onError
|
|
9500
|
+
onError,
|
|
9501
|
+
piiRedactor
|
|
9501
9502
|
} = options;
|
|
9502
9503
|
const strategy = getStrategy(handle.apiType);
|
|
9503
9504
|
const accumulator = createStreamAccumulator(handle.model || void 0);
|
|
9505
|
+
const contentDeAnon = piiRedactor && onData ? createStreamingDeAnonymizer(piiRedactor, onData) : null;
|
|
9506
|
+
const thinkingDeAnon = piiRedactor && onThinking ? createStreamingDeAnonymizer(piiRedactor, onThinking) : null;
|
|
9504
9507
|
const contentSmoother = new StreamSmoother((text16) => {
|
|
9505
|
-
if (
|
|
9508
|
+
if (contentDeAnon) contentDeAnon.push(text16);
|
|
9509
|
+
else if (onData) onData(text16);
|
|
9506
9510
|
}, smoothing);
|
|
9507
9511
|
const thinkingSmoother = new StreamSmoother((text16) => {
|
|
9508
|
-
if (
|
|
9512
|
+
if (thinkingDeAnon) thinkingDeAnon.push(text16);
|
|
9513
|
+
else if (onThinking) onThinking(text16);
|
|
9509
9514
|
}, smoothing);
|
|
9515
|
+
const flushOutput = () => {
|
|
9516
|
+
contentSmoother.flush();
|
|
9517
|
+
thinkingSmoother.flush();
|
|
9518
|
+
contentDeAnon?.flush();
|
|
9519
|
+
thinkingDeAnon?.flush();
|
|
9520
|
+
};
|
|
9521
|
+
const buildFinal = () => strategy.buildFinalResponse(
|
|
9522
|
+
piiRedactor ? {
|
|
9523
|
+
...accumulator,
|
|
9524
|
+
content: piiRedactor.deAnonymize(accumulator.content),
|
|
9525
|
+
thinking: piiRedactor.deAnonymize(accumulator.thinking)
|
|
9526
|
+
} : accumulator
|
|
9527
|
+
);
|
|
9510
9528
|
const idleController = new AbortController();
|
|
9511
9529
|
let watchdog;
|
|
9512
9530
|
let idleFired = false;
|
|
@@ -9551,9 +9569,8 @@ async function resumeStream(options) {
|
|
|
9551
9569
|
if (signal) signal.removeEventListener("abort", onCallerAbort);
|
|
9552
9570
|
};
|
|
9553
9571
|
const buildInterrupted = (message) => {
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(strategy.buildFinalResponse(accumulator)) : strategy.buildFinalResponse(accumulator);
|
|
9572
|
+
flushOutput();
|
|
9573
|
+
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(buildFinal()) : buildFinal();
|
|
9557
9574
|
return { data, error: message, interrupted: true };
|
|
9558
9575
|
};
|
|
9559
9576
|
if (combinedSignal.aborted) {
|
|
@@ -9601,18 +9618,16 @@ async function resumeStream(options) {
|
|
|
9601
9618
|
const err = replayErr instanceof Error ? replayErr : new Error(String(replayErr));
|
|
9602
9619
|
const statusCode = parseSseStatusCode(err);
|
|
9603
9620
|
if (statusCode === 410) {
|
|
9604
|
-
|
|
9605
|
-
thinkingSmoother.flush();
|
|
9621
|
+
flushOutput();
|
|
9606
9622
|
throw new StreamExpiredError(handle.inferenceId);
|
|
9607
9623
|
}
|
|
9608
9624
|
if (err.name === "AbortError" || combinedSignal.aborted) {
|
|
9609
9625
|
return buildInterrupted(abortMessage());
|
|
9610
9626
|
}
|
|
9611
|
-
|
|
9612
|
-
thinkingSmoother.flush();
|
|
9627
|
+
flushOutput();
|
|
9613
9628
|
if (onError) onError(err);
|
|
9614
9629
|
return {
|
|
9615
|
-
data:
|
|
9630
|
+
data: buildFinal(),
|
|
9616
9631
|
error: err.message,
|
|
9617
9632
|
interrupted: false,
|
|
9618
9633
|
statusCode
|
|
@@ -9628,7 +9643,9 @@ async function resumeStream(options) {
|
|
|
9628
9643
|
draining = true;
|
|
9629
9644
|
await Promise.all([contentSmoother.drain(), thinkingSmoother.drain()]);
|
|
9630
9645
|
if (playbackAborted) return buildInterrupted(abortMessage());
|
|
9631
|
-
|
|
9646
|
+
contentDeAnon?.flush();
|
|
9647
|
+
thinkingDeAnon?.flush();
|
|
9648
|
+
const response = buildFinal();
|
|
9632
9649
|
const deliveredOutput = emittedOutput || (accumulator.toolCallEvents?.length ?? 0) > 0;
|
|
9633
9650
|
if (onFinish && deliveredOutput) onFinish(response);
|
|
9634
9651
|
return { data: response, error: null, interrupted: false, empty: !deliveredOutput };
|
package/dist/react/index.cjs
CHANGED
|
@@ -7605,6 +7605,7 @@ function count(value) {
|
|
|
7605
7605
|
|
|
7606
7606
|
// src/lib/chat/resumeStream.ts
|
|
7607
7607
|
init_clientConfig();
|
|
7608
|
+
init_redactor();
|
|
7608
7609
|
|
|
7609
7610
|
// src/lib/chat/toolLoop.ts
|
|
7610
7611
|
init_clientConfig();
|
|
@@ -12076,16 +12077,34 @@ async function resumeStream(options) {
|
|
|
12076
12077
|
onData,
|
|
12077
12078
|
onThinking,
|
|
12078
12079
|
onFinish,
|
|
12079
|
-
onError
|
|
12080
|
+
onError,
|
|
12081
|
+
piiRedactor
|
|
12080
12082
|
} = options;
|
|
12081
12083
|
const strategy = getStrategy(handle.apiType);
|
|
12082
12084
|
const accumulator = createStreamAccumulator(handle.model || void 0);
|
|
12085
|
+
const contentDeAnon = piiRedactor && onData ? createStreamingDeAnonymizer(piiRedactor, onData) : null;
|
|
12086
|
+
const thinkingDeAnon = piiRedactor && onThinking ? createStreamingDeAnonymizer(piiRedactor, onThinking) : null;
|
|
12083
12087
|
const contentSmoother = new StreamSmoother((text16) => {
|
|
12084
|
-
if (
|
|
12088
|
+
if (contentDeAnon) contentDeAnon.push(text16);
|
|
12089
|
+
else if (onData) onData(text16);
|
|
12085
12090
|
}, smoothing);
|
|
12086
12091
|
const thinkingSmoother = new StreamSmoother((text16) => {
|
|
12087
|
-
if (
|
|
12092
|
+
if (thinkingDeAnon) thinkingDeAnon.push(text16);
|
|
12093
|
+
else if (onThinking) onThinking(text16);
|
|
12088
12094
|
}, smoothing);
|
|
12095
|
+
const flushOutput = () => {
|
|
12096
|
+
contentSmoother.flush();
|
|
12097
|
+
thinkingSmoother.flush();
|
|
12098
|
+
contentDeAnon?.flush();
|
|
12099
|
+
thinkingDeAnon?.flush();
|
|
12100
|
+
};
|
|
12101
|
+
const buildFinal = () => strategy.buildFinalResponse(
|
|
12102
|
+
piiRedactor ? {
|
|
12103
|
+
...accumulator,
|
|
12104
|
+
content: piiRedactor.deAnonymize(accumulator.content),
|
|
12105
|
+
thinking: piiRedactor.deAnonymize(accumulator.thinking)
|
|
12106
|
+
} : accumulator
|
|
12107
|
+
);
|
|
12089
12108
|
const idleController = new AbortController();
|
|
12090
12109
|
let watchdog;
|
|
12091
12110
|
let idleFired = false;
|
|
@@ -12130,9 +12149,8 @@ async function resumeStream(options) {
|
|
|
12130
12149
|
if (signal) signal.removeEventListener("abort", onCallerAbort);
|
|
12131
12150
|
};
|
|
12132
12151
|
const buildInterrupted = (message) => {
|
|
12133
|
-
|
|
12134
|
-
|
|
12135
|
-
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(strategy.buildFinalResponse(accumulator)) : strategy.buildFinalResponse(accumulator);
|
|
12152
|
+
flushOutput();
|
|
12153
|
+
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(buildFinal()) : buildFinal();
|
|
12136
12154
|
return { data, error: message, interrupted: true };
|
|
12137
12155
|
};
|
|
12138
12156
|
if (combinedSignal.aborted) {
|
|
@@ -12180,18 +12198,16 @@ async function resumeStream(options) {
|
|
|
12180
12198
|
const err = replayErr instanceof Error ? replayErr : new Error(String(replayErr));
|
|
12181
12199
|
const statusCode = parseSseStatusCode(err);
|
|
12182
12200
|
if (statusCode === 410) {
|
|
12183
|
-
|
|
12184
|
-
thinkingSmoother.flush();
|
|
12201
|
+
flushOutput();
|
|
12185
12202
|
throw new StreamExpiredError(handle.inferenceId);
|
|
12186
12203
|
}
|
|
12187
12204
|
if (err.name === "AbortError" || combinedSignal.aborted) {
|
|
12188
12205
|
return buildInterrupted(abortMessage());
|
|
12189
12206
|
}
|
|
12190
|
-
|
|
12191
|
-
thinkingSmoother.flush();
|
|
12207
|
+
flushOutput();
|
|
12192
12208
|
if (onError) onError(err);
|
|
12193
12209
|
return {
|
|
12194
|
-
data:
|
|
12210
|
+
data: buildFinal(),
|
|
12195
12211
|
error: err.message,
|
|
12196
12212
|
interrupted: false,
|
|
12197
12213
|
statusCode
|
|
@@ -12207,7 +12223,9 @@ async function resumeStream(options) {
|
|
|
12207
12223
|
draining = true;
|
|
12208
12224
|
await Promise.all([contentSmoother.drain(), thinkingSmoother.drain()]);
|
|
12209
12225
|
if (playbackAborted) return buildInterrupted(abortMessage());
|
|
12210
|
-
|
|
12226
|
+
contentDeAnon?.flush();
|
|
12227
|
+
thinkingDeAnon?.flush();
|
|
12228
|
+
const response = buildFinal();
|
|
12211
12229
|
const deliveredOutput = emittedOutput || (accumulator.toolCallEvents?.length ?? 0) > 0;
|
|
12212
12230
|
if (onFinish && deliveredOutput) onFinish(response);
|
|
12213
12231
|
return { data: response, error: null, interrupted: false, empty: !deliveredOutput };
|
|
@@ -36366,6 +36384,7 @@ function useChat(options) {
|
|
|
36366
36384
|
onToolCallArgumentsDelta,
|
|
36367
36385
|
onStepFinish,
|
|
36368
36386
|
resumable,
|
|
36387
|
+
background = false,
|
|
36369
36388
|
onStreamMeta,
|
|
36370
36389
|
apiType: defaultApiType = "auto",
|
|
36371
36390
|
smoothing,
|
|
@@ -36374,12 +36393,12 @@ function useChat(options) {
|
|
|
36374
36393
|
piiRedaction,
|
|
36375
36394
|
onPiiRedacted
|
|
36376
36395
|
} = options || {};
|
|
36396
|
+
const keepAlive = resumable === true && background;
|
|
36377
36397
|
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
36378
36398
|
const abortControllerRef = (0, import_react4.useRef)(null);
|
|
36379
36399
|
const requestIdRef = (0, import_react4.useRef)(0);
|
|
36380
|
-
const
|
|
36381
|
-
|
|
36382
|
-
);
|
|
36400
|
+
const detachControllerRef = (0, import_react4.useRef)(null);
|
|
36401
|
+
const pendingInferenceRef = (0, import_react4.useRef)(null);
|
|
36383
36402
|
const cancelInference = (0, import_react4.useCallback)(
|
|
36384
36403
|
(inferenceId, requestToken) => {
|
|
36385
36404
|
void (async () => {
|
|
@@ -36407,7 +36426,95 @@ function useChat(options) {
|
|
|
36407
36426
|
abortControllerRef.current = null;
|
|
36408
36427
|
}
|
|
36409
36428
|
}, []);
|
|
36410
|
-
(0, import_react4.
|
|
36429
|
+
const keepAliveRef = (0, import_react4.useRef)(keepAlive);
|
|
36430
|
+
keepAliveRef.current = keepAlive;
|
|
36431
|
+
(0, import_react4.useEffect)(
|
|
36432
|
+
() => () => {
|
|
36433
|
+
if (keepAliveRef.current) {
|
|
36434
|
+
if (detachControllerRef.current) {
|
|
36435
|
+
detachControllerRef.current.abort();
|
|
36436
|
+
return;
|
|
36437
|
+
}
|
|
36438
|
+
pendingInferenceRef.current = null;
|
|
36439
|
+
abortControllerRef.current?.abort();
|
|
36440
|
+
abortControllerRef.current = null;
|
|
36441
|
+
return;
|
|
36442
|
+
}
|
|
36443
|
+
stop();
|
|
36444
|
+
},
|
|
36445
|
+
[stop]
|
|
36446
|
+
);
|
|
36447
|
+
const resumeStream2 = (0, import_react4.useCallback)(
|
|
36448
|
+
async (handle, opts) => {
|
|
36449
|
+
const getterValidation = validateTokenGetter(getToken);
|
|
36450
|
+
if (!getterValidation.valid) {
|
|
36451
|
+
return { data: null, error: getterValidation.message, interrupted: false };
|
|
36452
|
+
}
|
|
36453
|
+
const { headless, ...resumeOpts } = opts ?? {};
|
|
36454
|
+
if (!headless && abortControllerRef.current) {
|
|
36455
|
+
return { data: null, error: "A request is already in progress", interrupted: false };
|
|
36456
|
+
}
|
|
36457
|
+
const abortController = new AbortController();
|
|
36458
|
+
const requestId = headless ? null : ++requestIdRef.current;
|
|
36459
|
+
if (!headless) {
|
|
36460
|
+
abortControllerRef.current = abortController;
|
|
36461
|
+
pendingInferenceRef.current = {
|
|
36462
|
+
id: handle.inferenceId,
|
|
36463
|
+
round: -1,
|
|
36464
|
+
cancel: () => cancelInference(handle.inferenceId),
|
|
36465
|
+
handle
|
|
36466
|
+
};
|
|
36467
|
+
setIsLoading(true);
|
|
36468
|
+
}
|
|
36469
|
+
const ownsForeground = () => requestId !== null && requestIdRef.current === requestId;
|
|
36470
|
+
try {
|
|
36471
|
+
let token;
|
|
36472
|
+
try {
|
|
36473
|
+
token = await getToken();
|
|
36474
|
+
} catch (err) {
|
|
36475
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
36476
|
+
if (!headless) onError?.(error);
|
|
36477
|
+
return { data: null, error: error.message, interrupted: false };
|
|
36478
|
+
}
|
|
36479
|
+
const tokenValidation = validateToken(token);
|
|
36480
|
+
if (!tokenValidation.valid) {
|
|
36481
|
+
return { data: null, error: tokenValidation.message, interrupted: false };
|
|
36482
|
+
}
|
|
36483
|
+
return await resumeStream({
|
|
36484
|
+
handle,
|
|
36485
|
+
token,
|
|
36486
|
+
baseUrl,
|
|
36487
|
+
smoothing,
|
|
36488
|
+
signal: abortController.signal,
|
|
36489
|
+
piiRedactor: typeof resolvedPiiRedaction === "object" ? resolvedPiiRedaction : void 0,
|
|
36490
|
+
...headless ? {} : {
|
|
36491
|
+
onData: (chunk) => globalOnData?.(chunk),
|
|
36492
|
+
onThinking: (chunk) => globalOnThinking?.(chunk),
|
|
36493
|
+
onFinish,
|
|
36494
|
+
onError
|
|
36495
|
+
},
|
|
36496
|
+
...resumeOpts
|
|
36497
|
+
});
|
|
36498
|
+
} finally {
|
|
36499
|
+
if (ownsForeground()) {
|
|
36500
|
+
setIsLoading(false);
|
|
36501
|
+
if (abortControllerRef.current === abortController) abortControllerRef.current = null;
|
|
36502
|
+
if (pendingInferenceRef.current?.round === -1) pendingInferenceRef.current = null;
|
|
36503
|
+
}
|
|
36504
|
+
}
|
|
36505
|
+
},
|
|
36506
|
+
[
|
|
36507
|
+
getToken,
|
|
36508
|
+
baseUrl,
|
|
36509
|
+
smoothing,
|
|
36510
|
+
cancelInference,
|
|
36511
|
+
resolvedPiiRedaction,
|
|
36512
|
+
globalOnData,
|
|
36513
|
+
globalOnThinking,
|
|
36514
|
+
onFinish,
|
|
36515
|
+
onError
|
|
36516
|
+
]
|
|
36517
|
+
);
|
|
36411
36518
|
const sendMessage = (0, import_react4.useCallback)(
|
|
36412
36519
|
async ({
|
|
36413
36520
|
messages,
|
|
@@ -36435,9 +36542,12 @@ function useChat(options) {
|
|
|
36435
36542
|
stop();
|
|
36436
36543
|
const abortController = new AbortController();
|
|
36437
36544
|
abortControllerRef.current = abortController;
|
|
36545
|
+
const detachController = keepAlive ? new AbortController() : null;
|
|
36546
|
+
detachControllerRef.current = detachController;
|
|
36438
36547
|
const requestId = ++requestIdRef.current;
|
|
36439
36548
|
setIsLoading(true);
|
|
36440
|
-
let
|
|
36549
|
+
let keepServerStream = false;
|
|
36550
|
+
const deferredErrors = [];
|
|
36441
36551
|
try {
|
|
36442
36552
|
const tokenGetterValidation = validateTokenGetter(getToken);
|
|
36443
36553
|
if (!tokenGetterValidation.valid) {
|
|
@@ -36501,6 +36611,7 @@ function useChat(options) {
|
|
|
36501
36611
|
apiType: requestApiType ?? defaultApiType,
|
|
36502
36612
|
endpointOverride,
|
|
36503
36613
|
resumable,
|
|
36614
|
+
detachSignal: detachController?.signal,
|
|
36504
36615
|
onStreamMeta: resumable || onStreamMeta ? (meta) => {
|
|
36505
36616
|
if (requestId !== requestIdRef.current || abortController.signal.aborted) {
|
|
36506
36617
|
if (resumable) cancelInference(meta.inferenceId, token);
|
|
@@ -36509,12 +36620,19 @@ function useChat(options) {
|
|
|
36509
36620
|
const previous = pendingInferenceRef.current;
|
|
36510
36621
|
if (previous && previous.round === meta.round && previous.id !== meta.inferenceId)
|
|
36511
36622
|
previous.cancel();
|
|
36623
|
+
const handle2 = {
|
|
36624
|
+
inferenceId: meta.inferenceId,
|
|
36625
|
+
apiType: resolveApiType(requestApiType ?? defaultApiType, model),
|
|
36626
|
+
model,
|
|
36627
|
+
conversationId
|
|
36628
|
+
};
|
|
36512
36629
|
pendingInferenceRef.current = {
|
|
36513
36630
|
id: meta.inferenceId,
|
|
36514
36631
|
round: meta.round,
|
|
36515
|
-
cancel: resumable ? () => cancelInference(meta.inferenceId, token) : () => void 0
|
|
36632
|
+
cancel: resumable ? () => cancelInference(meta.inferenceId, token) : () => void 0,
|
|
36633
|
+
handle: handle2
|
|
36516
36634
|
};
|
|
36517
|
-
onStreamMeta?.(meta);
|
|
36635
|
+
onStreamMeta?.({ ...handle2, round: meta.round });
|
|
36518
36636
|
} : void 0,
|
|
36519
36637
|
temperature,
|
|
36520
36638
|
maxOutputTokens,
|
|
@@ -36536,17 +36654,44 @@ function useChat(options) {
|
|
|
36536
36654
|
if (globalOnThinking) globalOnThinking(chunk);
|
|
36537
36655
|
},
|
|
36538
36656
|
onFinish,
|
|
36539
|
-
onError,
|
|
36657
|
+
onError: keepAlive ? (error) => deferredErrors.push(error) : onError,
|
|
36540
36658
|
onToolCall,
|
|
36541
36659
|
onServerToolCall,
|
|
36542
36660
|
onToolCallArgumentsDelta,
|
|
36543
|
-
onStepFinish
|
|
36661
|
+
onStepFinish: keepAlive || onStepFinish ? (event) => {
|
|
36662
|
+
const pending2 = pendingInferenceRef.current;
|
|
36663
|
+
if (keepAlive && pending2 && requestIdRef.current === requestId) {
|
|
36664
|
+
pendingInferenceRef.current = { ...pending2, settled: true };
|
|
36665
|
+
}
|
|
36666
|
+
onStepFinish?.(event);
|
|
36667
|
+
} : void 0,
|
|
36544
36668
|
preProcessors,
|
|
36545
36669
|
hooks,
|
|
36546
36670
|
piiRedaction: requestPiiRedaction ?? resolvedPiiRedaction,
|
|
36547
36671
|
onPiiRedacted
|
|
36548
36672
|
});
|
|
36549
|
-
|
|
36673
|
+
const pending = pendingInferenceRef.current;
|
|
36674
|
+
const handle = pending && !pending.settled ? pending.handle : null;
|
|
36675
|
+
const detach = result.error !== null && keepAlive && handle && result.error !== "Request aborted";
|
|
36676
|
+
if (!detach) deferredErrors.forEach((error) => onError?.(error));
|
|
36677
|
+
if (result.error === null) {
|
|
36678
|
+
keepServerStream = true;
|
|
36679
|
+
return result;
|
|
36680
|
+
}
|
|
36681
|
+
if (detach) {
|
|
36682
|
+
keepServerStream = true;
|
|
36683
|
+
return {
|
|
36684
|
+
data: result.data,
|
|
36685
|
+
error: "Request detached",
|
|
36686
|
+
detached: true,
|
|
36687
|
+
resume: handle,
|
|
36688
|
+
toolsChecksum: result.toolsChecksum
|
|
36689
|
+
};
|
|
36690
|
+
}
|
|
36691
|
+
if ("detached" in result && result.detached) {
|
|
36692
|
+
keepServerStream = true;
|
|
36693
|
+
return { ...result, resume: null };
|
|
36694
|
+
}
|
|
36550
36695
|
return result;
|
|
36551
36696
|
} catch (err) {
|
|
36552
36697
|
return createErrorResult(
|
|
@@ -36557,7 +36702,8 @@ function useChat(options) {
|
|
|
36557
36702
|
if (requestIdRef.current === requestId) {
|
|
36558
36703
|
setIsLoading(false);
|
|
36559
36704
|
abortControllerRef.current = null;
|
|
36560
|
-
if (
|
|
36705
|
+
if (detachControllerRef.current === detachController) detachControllerRef.current = null;
|
|
36706
|
+
if (!keepServerStream) pendingInferenceRef.current?.cancel();
|
|
36561
36707
|
pendingInferenceRef.current = null;
|
|
36562
36708
|
}
|
|
36563
36709
|
}
|
|
@@ -36576,6 +36722,7 @@ function useChat(options) {
|
|
|
36576
36722
|
onToolCallArgumentsDelta,
|
|
36577
36723
|
onStepFinish,
|
|
36578
36724
|
resumable,
|
|
36725
|
+
keepAlive,
|
|
36579
36726
|
onStreamMeta,
|
|
36580
36727
|
defaultApiType,
|
|
36581
36728
|
smoothing,
|
|
@@ -36588,7 +36735,8 @@ function useChat(options) {
|
|
|
36588
36735
|
return {
|
|
36589
36736
|
isLoading,
|
|
36590
36737
|
sendMessage,
|
|
36591
|
-
stop
|
|
36738
|
+
stop,
|
|
36739
|
+
resumeStream: resumeStream2
|
|
36592
36740
|
};
|
|
36593
36741
|
}
|
|
36594
36742
|
|
package/dist/react/index.d.mts
CHANGED
|
@@ -2890,6 +2890,8 @@ interface ResumeStreamOptions {
|
|
|
2890
2890
|
onData?: (chunk: string) => void;
|
|
2891
2891
|
/** Thinking/reasoning deltas as they replay. */
|
|
2892
2892
|
onThinking?: (chunk: string) => void;
|
|
2893
|
+
/** Restores the placeholders this redactor assigned when the original request was sent. */
|
|
2894
|
+
piiRedactor?: PiiRedactor;
|
|
2893
2895
|
/** Called once on a clean completion. Never called for 410 nor interrupted terminals. */
|
|
2894
2896
|
onFinish?: (response: ApiResponse) => void;
|
|
2895
2897
|
/** Called on a transient/unexpected failure. Never called for 410 (throws) nor interrupted terminals. */
|
|
@@ -14633,6 +14635,10 @@ type SendMessageResult = {
|
|
|
14633
14635
|
error: string;
|
|
14634
14636
|
/** Checksum of tools used to generate this response */
|
|
14635
14637
|
toolsChecksum?: string;
|
|
14638
|
+
/** True when a background stream was left running; `error` is "Request detached". */
|
|
14639
|
+
detached?: true;
|
|
14640
|
+
/** Pass to `resumeStream`; null when no inference id was issued before the detach. */
|
|
14641
|
+
resume?: StreamResumeHandle | null;
|
|
14636
14642
|
};
|
|
14637
14643
|
/**
|
|
14638
14644
|
* @inline
|
|
@@ -14640,11 +14646,13 @@ type SendMessageResult = {
|
|
|
14640
14646
|
interface UseChatOptions extends BaseUseChatOptions {
|
|
14641
14647
|
/** Buffer streamed rounds so a service can verify their canonical output. */
|
|
14642
14648
|
resumable?: boolean;
|
|
14643
|
-
/**
|
|
14644
|
-
|
|
14645
|
-
|
|
14646
|
-
|
|
14647
|
-
|
|
14649
|
+
/**
|
|
14650
|
+
* Keep a resumable generation running server-side when the request fails or
|
|
14651
|
+
* the hook unmounts; only `stop()` cancels it. Replay it with `resumeStream`.
|
|
14652
|
+
*/
|
|
14653
|
+
background?: boolean;
|
|
14654
|
+
/** Stream handle for each HTTP round, including client-tool continuations. */
|
|
14655
|
+
onStreamMeta?: (meta: StreamMeta) => void;
|
|
14648
14656
|
/**
|
|
14649
14657
|
* Which API endpoint to use. Default: "auto"
|
|
14650
14658
|
* - "auto": automatically selects the best API based on model support
|
|
@@ -14653,8 +14661,19 @@ interface UseChatOptions extends BaseUseChatOptions {
|
|
|
14653
14661
|
*/
|
|
14654
14662
|
apiType?: ApiType;
|
|
14655
14663
|
}
|
|
14664
|
+
/**
|
|
14665
|
+
* A resumable stream handle plus the tool-loop round that issued it.
|
|
14666
|
+
* @inline
|
|
14667
|
+
*/
|
|
14668
|
+
type StreamMeta = StreamResumeHandle & {
|
|
14669
|
+
round: number;
|
|
14670
|
+
};
|
|
14656
14671
|
type UseChatResult = BaseUseChatResult & {
|
|
14657
14672
|
sendMessage: (args: SendMessageArgs) => Promise<SendMessageResult>;
|
|
14673
|
+
/** Replay a resumable stream from the portal buffer, from its first frame. */
|
|
14674
|
+
resumeStream: (handle: StreamResumeHandle, opts?: Pick<ResumeStreamOptions, "idleTimeoutMs" | "smoothing"> & {
|
|
14675
|
+
headless?: boolean;
|
|
14676
|
+
}) => Promise<ResumeStreamResult>;
|
|
14658
14677
|
};
|
|
14659
14678
|
/**
|
|
14660
14679
|
* A React hook for managing chat completions with authentication.
|
package/dist/react/index.d.ts
CHANGED
|
@@ -2890,6 +2890,8 @@ interface ResumeStreamOptions {
|
|
|
2890
2890
|
onData?: (chunk: string) => void;
|
|
2891
2891
|
/** Thinking/reasoning deltas as they replay. */
|
|
2892
2892
|
onThinking?: (chunk: string) => void;
|
|
2893
|
+
/** Restores the placeholders this redactor assigned when the original request was sent. */
|
|
2894
|
+
piiRedactor?: PiiRedactor;
|
|
2893
2895
|
/** Called once on a clean completion. Never called for 410 nor interrupted terminals. */
|
|
2894
2896
|
onFinish?: (response: ApiResponse) => void;
|
|
2895
2897
|
/** Called on a transient/unexpected failure. Never called for 410 (throws) nor interrupted terminals. */
|
|
@@ -14633,6 +14635,10 @@ type SendMessageResult = {
|
|
|
14633
14635
|
error: string;
|
|
14634
14636
|
/** Checksum of tools used to generate this response */
|
|
14635
14637
|
toolsChecksum?: string;
|
|
14638
|
+
/** True when a background stream was left running; `error` is "Request detached". */
|
|
14639
|
+
detached?: true;
|
|
14640
|
+
/** Pass to `resumeStream`; null when no inference id was issued before the detach. */
|
|
14641
|
+
resume?: StreamResumeHandle | null;
|
|
14636
14642
|
};
|
|
14637
14643
|
/**
|
|
14638
14644
|
* @inline
|
|
@@ -14640,11 +14646,13 @@ type SendMessageResult = {
|
|
|
14640
14646
|
interface UseChatOptions extends BaseUseChatOptions {
|
|
14641
14647
|
/** Buffer streamed rounds so a service can verify their canonical output. */
|
|
14642
14648
|
resumable?: boolean;
|
|
14643
|
-
/**
|
|
14644
|
-
|
|
14645
|
-
|
|
14646
|
-
|
|
14647
|
-
|
|
14649
|
+
/**
|
|
14650
|
+
* Keep a resumable generation running server-side when the request fails or
|
|
14651
|
+
* the hook unmounts; only `stop()` cancels it. Replay it with `resumeStream`.
|
|
14652
|
+
*/
|
|
14653
|
+
background?: boolean;
|
|
14654
|
+
/** Stream handle for each HTTP round, including client-tool continuations. */
|
|
14655
|
+
onStreamMeta?: (meta: StreamMeta) => void;
|
|
14648
14656
|
/**
|
|
14649
14657
|
* Which API endpoint to use. Default: "auto"
|
|
14650
14658
|
* - "auto": automatically selects the best API based on model support
|
|
@@ -14653,8 +14661,19 @@ interface UseChatOptions extends BaseUseChatOptions {
|
|
|
14653
14661
|
*/
|
|
14654
14662
|
apiType?: ApiType;
|
|
14655
14663
|
}
|
|
14664
|
+
/**
|
|
14665
|
+
* A resumable stream handle plus the tool-loop round that issued it.
|
|
14666
|
+
* @inline
|
|
14667
|
+
*/
|
|
14668
|
+
type StreamMeta = StreamResumeHandle & {
|
|
14669
|
+
round: number;
|
|
14670
|
+
};
|
|
14656
14671
|
type UseChatResult = BaseUseChatResult & {
|
|
14657
14672
|
sendMessage: (args: SendMessageArgs) => Promise<SendMessageResult>;
|
|
14673
|
+
/** Replay a resumable stream from the portal buffer, from its first frame. */
|
|
14674
|
+
resumeStream: (handle: StreamResumeHandle, opts?: Pick<ResumeStreamOptions, "idleTimeoutMs" | "smoothing"> & {
|
|
14675
|
+
headless?: boolean;
|
|
14676
|
+
}) => Promise<ResumeStreamResult>;
|
|
14658
14677
|
};
|
|
14659
14678
|
/**
|
|
14660
14679
|
* A React hook for managing chat completions with authentication.
|
package/dist/react/index.mjs
CHANGED
|
@@ -10208,16 +10208,34 @@ async function resumeStream(options) {
|
|
|
10208
10208
|
onData,
|
|
10209
10209
|
onThinking,
|
|
10210
10210
|
onFinish,
|
|
10211
|
-
onError
|
|
10211
|
+
onError,
|
|
10212
|
+
piiRedactor
|
|
10212
10213
|
} = options;
|
|
10213
10214
|
const strategy = getStrategy(handle.apiType);
|
|
10214
10215
|
const accumulator = createStreamAccumulator(handle.model || void 0);
|
|
10216
|
+
const contentDeAnon = piiRedactor && onData ? createStreamingDeAnonymizer(piiRedactor, onData) : null;
|
|
10217
|
+
const thinkingDeAnon = piiRedactor && onThinking ? createStreamingDeAnonymizer(piiRedactor, onThinking) : null;
|
|
10215
10218
|
const contentSmoother = new StreamSmoother((text16) => {
|
|
10216
|
-
if (
|
|
10219
|
+
if (contentDeAnon) contentDeAnon.push(text16);
|
|
10220
|
+
else if (onData) onData(text16);
|
|
10217
10221
|
}, smoothing);
|
|
10218
10222
|
const thinkingSmoother = new StreamSmoother((text16) => {
|
|
10219
|
-
if (
|
|
10223
|
+
if (thinkingDeAnon) thinkingDeAnon.push(text16);
|
|
10224
|
+
else if (onThinking) onThinking(text16);
|
|
10220
10225
|
}, smoothing);
|
|
10226
|
+
const flushOutput = () => {
|
|
10227
|
+
contentSmoother.flush();
|
|
10228
|
+
thinkingSmoother.flush();
|
|
10229
|
+
contentDeAnon?.flush();
|
|
10230
|
+
thinkingDeAnon?.flush();
|
|
10231
|
+
};
|
|
10232
|
+
const buildFinal = () => strategy.buildFinalResponse(
|
|
10233
|
+
piiRedactor ? {
|
|
10234
|
+
...accumulator,
|
|
10235
|
+
content: piiRedactor.deAnonymize(accumulator.content),
|
|
10236
|
+
thinking: piiRedactor.deAnonymize(accumulator.thinking)
|
|
10237
|
+
} : accumulator
|
|
10238
|
+
);
|
|
10221
10239
|
const idleController = new AbortController();
|
|
10222
10240
|
let watchdog;
|
|
10223
10241
|
let idleFired = false;
|
|
@@ -10262,9 +10280,8 @@ async function resumeStream(options) {
|
|
|
10262
10280
|
if (signal) signal.removeEventListener("abort", onCallerAbort);
|
|
10263
10281
|
};
|
|
10264
10282
|
const buildInterrupted = (message) => {
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(strategy.buildFinalResponse(accumulator)) : strategy.buildFinalResponse(accumulator);
|
|
10283
|
+
flushOutput();
|
|
10284
|
+
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(buildFinal()) : buildFinal();
|
|
10268
10285
|
return { data, error: message, interrupted: true };
|
|
10269
10286
|
};
|
|
10270
10287
|
if (combinedSignal.aborted) {
|
|
@@ -10312,18 +10329,16 @@ async function resumeStream(options) {
|
|
|
10312
10329
|
const err = replayErr instanceof Error ? replayErr : new Error(String(replayErr));
|
|
10313
10330
|
const statusCode = parseSseStatusCode(err);
|
|
10314
10331
|
if (statusCode === 410) {
|
|
10315
|
-
|
|
10316
|
-
thinkingSmoother.flush();
|
|
10332
|
+
flushOutput();
|
|
10317
10333
|
throw new StreamExpiredError(handle.inferenceId);
|
|
10318
10334
|
}
|
|
10319
10335
|
if (err.name === "AbortError" || combinedSignal.aborted) {
|
|
10320
10336
|
return buildInterrupted(abortMessage());
|
|
10321
10337
|
}
|
|
10322
|
-
|
|
10323
|
-
thinkingSmoother.flush();
|
|
10338
|
+
flushOutput();
|
|
10324
10339
|
if (onError) onError(err);
|
|
10325
10340
|
return {
|
|
10326
|
-
data:
|
|
10341
|
+
data: buildFinal(),
|
|
10327
10342
|
error: err.message,
|
|
10328
10343
|
interrupted: false,
|
|
10329
10344
|
statusCode
|
|
@@ -10339,7 +10354,9 @@ async function resumeStream(options) {
|
|
|
10339
10354
|
draining = true;
|
|
10340
10355
|
await Promise.all([contentSmoother.drain(), thinkingSmoother.drain()]);
|
|
10341
10356
|
if (playbackAborted) return buildInterrupted(abortMessage());
|
|
10342
|
-
|
|
10357
|
+
contentDeAnon?.flush();
|
|
10358
|
+
thinkingDeAnon?.flush();
|
|
10359
|
+
const response = buildFinal();
|
|
10343
10360
|
const deliveredOutput = emittedOutput || (accumulator.toolCallEvents?.length ?? 0) > 0;
|
|
10344
10361
|
if (onFinish && deliveredOutput) onFinish(response);
|
|
10345
10362
|
return { data: response, error: null, interrupted: false, empty: !deliveredOutput };
|
|
@@ -34438,6 +34455,7 @@ function useChat(options) {
|
|
|
34438
34455
|
onToolCallArgumentsDelta,
|
|
34439
34456
|
onStepFinish,
|
|
34440
34457
|
resumable,
|
|
34458
|
+
background = false,
|
|
34441
34459
|
onStreamMeta,
|
|
34442
34460
|
apiType: defaultApiType = "auto",
|
|
34443
34461
|
smoothing,
|
|
@@ -34446,12 +34464,12 @@ function useChat(options) {
|
|
|
34446
34464
|
piiRedaction,
|
|
34447
34465
|
onPiiRedacted
|
|
34448
34466
|
} = options || {};
|
|
34467
|
+
const keepAlive = resumable === true && background;
|
|
34449
34468
|
const [isLoading, setIsLoading] = useState4(false);
|
|
34450
34469
|
const abortControllerRef = useRef3(null);
|
|
34451
34470
|
const requestIdRef = useRef3(0);
|
|
34452
|
-
const
|
|
34453
|
-
|
|
34454
|
-
);
|
|
34471
|
+
const detachControllerRef = useRef3(null);
|
|
34472
|
+
const pendingInferenceRef = useRef3(null);
|
|
34455
34473
|
const cancelInference = useCallback3(
|
|
34456
34474
|
(inferenceId, requestToken) => {
|
|
34457
34475
|
void (async () => {
|
|
@@ -34479,7 +34497,95 @@ function useChat(options) {
|
|
|
34479
34497
|
abortControllerRef.current = null;
|
|
34480
34498
|
}
|
|
34481
34499
|
}, []);
|
|
34482
|
-
|
|
34500
|
+
const keepAliveRef = useRef3(keepAlive);
|
|
34501
|
+
keepAliveRef.current = keepAlive;
|
|
34502
|
+
useEffect3(
|
|
34503
|
+
() => () => {
|
|
34504
|
+
if (keepAliveRef.current) {
|
|
34505
|
+
if (detachControllerRef.current) {
|
|
34506
|
+
detachControllerRef.current.abort();
|
|
34507
|
+
return;
|
|
34508
|
+
}
|
|
34509
|
+
pendingInferenceRef.current = null;
|
|
34510
|
+
abortControllerRef.current?.abort();
|
|
34511
|
+
abortControllerRef.current = null;
|
|
34512
|
+
return;
|
|
34513
|
+
}
|
|
34514
|
+
stop();
|
|
34515
|
+
},
|
|
34516
|
+
[stop]
|
|
34517
|
+
);
|
|
34518
|
+
const resumeStream2 = useCallback3(
|
|
34519
|
+
async (handle, opts) => {
|
|
34520
|
+
const getterValidation = validateTokenGetter(getToken);
|
|
34521
|
+
if (!getterValidation.valid) {
|
|
34522
|
+
return { data: null, error: getterValidation.message, interrupted: false };
|
|
34523
|
+
}
|
|
34524
|
+
const { headless, ...resumeOpts } = opts ?? {};
|
|
34525
|
+
if (!headless && abortControllerRef.current) {
|
|
34526
|
+
return { data: null, error: "A request is already in progress", interrupted: false };
|
|
34527
|
+
}
|
|
34528
|
+
const abortController = new AbortController();
|
|
34529
|
+
const requestId = headless ? null : ++requestIdRef.current;
|
|
34530
|
+
if (!headless) {
|
|
34531
|
+
abortControllerRef.current = abortController;
|
|
34532
|
+
pendingInferenceRef.current = {
|
|
34533
|
+
id: handle.inferenceId,
|
|
34534
|
+
round: -1,
|
|
34535
|
+
cancel: () => cancelInference(handle.inferenceId),
|
|
34536
|
+
handle
|
|
34537
|
+
};
|
|
34538
|
+
setIsLoading(true);
|
|
34539
|
+
}
|
|
34540
|
+
const ownsForeground = () => requestId !== null && requestIdRef.current === requestId;
|
|
34541
|
+
try {
|
|
34542
|
+
let token;
|
|
34543
|
+
try {
|
|
34544
|
+
token = await getToken();
|
|
34545
|
+
} catch (err) {
|
|
34546
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
34547
|
+
if (!headless) onError?.(error);
|
|
34548
|
+
return { data: null, error: error.message, interrupted: false };
|
|
34549
|
+
}
|
|
34550
|
+
const tokenValidation = validateToken(token);
|
|
34551
|
+
if (!tokenValidation.valid) {
|
|
34552
|
+
return { data: null, error: tokenValidation.message, interrupted: false };
|
|
34553
|
+
}
|
|
34554
|
+
return await resumeStream({
|
|
34555
|
+
handle,
|
|
34556
|
+
token,
|
|
34557
|
+
baseUrl,
|
|
34558
|
+
smoothing,
|
|
34559
|
+
signal: abortController.signal,
|
|
34560
|
+
piiRedactor: typeof resolvedPiiRedaction === "object" ? resolvedPiiRedaction : void 0,
|
|
34561
|
+
...headless ? {} : {
|
|
34562
|
+
onData: (chunk) => globalOnData?.(chunk),
|
|
34563
|
+
onThinking: (chunk) => globalOnThinking?.(chunk),
|
|
34564
|
+
onFinish,
|
|
34565
|
+
onError
|
|
34566
|
+
},
|
|
34567
|
+
...resumeOpts
|
|
34568
|
+
});
|
|
34569
|
+
} finally {
|
|
34570
|
+
if (ownsForeground()) {
|
|
34571
|
+
setIsLoading(false);
|
|
34572
|
+
if (abortControllerRef.current === abortController) abortControllerRef.current = null;
|
|
34573
|
+
if (pendingInferenceRef.current?.round === -1) pendingInferenceRef.current = null;
|
|
34574
|
+
}
|
|
34575
|
+
}
|
|
34576
|
+
},
|
|
34577
|
+
[
|
|
34578
|
+
getToken,
|
|
34579
|
+
baseUrl,
|
|
34580
|
+
smoothing,
|
|
34581
|
+
cancelInference,
|
|
34582
|
+
resolvedPiiRedaction,
|
|
34583
|
+
globalOnData,
|
|
34584
|
+
globalOnThinking,
|
|
34585
|
+
onFinish,
|
|
34586
|
+
onError
|
|
34587
|
+
]
|
|
34588
|
+
);
|
|
34483
34589
|
const sendMessage = useCallback3(
|
|
34484
34590
|
async ({
|
|
34485
34591
|
messages,
|
|
@@ -34507,9 +34613,12 @@ function useChat(options) {
|
|
|
34507
34613
|
stop();
|
|
34508
34614
|
const abortController = new AbortController();
|
|
34509
34615
|
abortControllerRef.current = abortController;
|
|
34616
|
+
const detachController = keepAlive ? new AbortController() : null;
|
|
34617
|
+
detachControllerRef.current = detachController;
|
|
34510
34618
|
const requestId = ++requestIdRef.current;
|
|
34511
34619
|
setIsLoading(true);
|
|
34512
|
-
let
|
|
34620
|
+
let keepServerStream = false;
|
|
34621
|
+
const deferredErrors = [];
|
|
34513
34622
|
try {
|
|
34514
34623
|
const tokenGetterValidation = validateTokenGetter(getToken);
|
|
34515
34624
|
if (!tokenGetterValidation.valid) {
|
|
@@ -34573,6 +34682,7 @@ function useChat(options) {
|
|
|
34573
34682
|
apiType: requestApiType ?? defaultApiType,
|
|
34574
34683
|
endpointOverride,
|
|
34575
34684
|
resumable,
|
|
34685
|
+
detachSignal: detachController?.signal,
|
|
34576
34686
|
onStreamMeta: resumable || onStreamMeta ? (meta) => {
|
|
34577
34687
|
if (requestId !== requestIdRef.current || abortController.signal.aborted) {
|
|
34578
34688
|
if (resumable) cancelInference(meta.inferenceId, token);
|
|
@@ -34581,12 +34691,19 @@ function useChat(options) {
|
|
|
34581
34691
|
const previous = pendingInferenceRef.current;
|
|
34582
34692
|
if (previous && previous.round === meta.round && previous.id !== meta.inferenceId)
|
|
34583
34693
|
previous.cancel();
|
|
34694
|
+
const handle2 = {
|
|
34695
|
+
inferenceId: meta.inferenceId,
|
|
34696
|
+
apiType: resolveApiType(requestApiType ?? defaultApiType, model),
|
|
34697
|
+
model,
|
|
34698
|
+
conversationId
|
|
34699
|
+
};
|
|
34584
34700
|
pendingInferenceRef.current = {
|
|
34585
34701
|
id: meta.inferenceId,
|
|
34586
34702
|
round: meta.round,
|
|
34587
|
-
cancel: resumable ? () => cancelInference(meta.inferenceId, token) : () => void 0
|
|
34703
|
+
cancel: resumable ? () => cancelInference(meta.inferenceId, token) : () => void 0,
|
|
34704
|
+
handle: handle2
|
|
34588
34705
|
};
|
|
34589
|
-
onStreamMeta?.(meta);
|
|
34706
|
+
onStreamMeta?.({ ...handle2, round: meta.round });
|
|
34590
34707
|
} : void 0,
|
|
34591
34708
|
temperature,
|
|
34592
34709
|
maxOutputTokens,
|
|
@@ -34608,17 +34725,44 @@ function useChat(options) {
|
|
|
34608
34725
|
if (globalOnThinking) globalOnThinking(chunk);
|
|
34609
34726
|
},
|
|
34610
34727
|
onFinish,
|
|
34611
|
-
onError,
|
|
34728
|
+
onError: keepAlive ? (error) => deferredErrors.push(error) : onError,
|
|
34612
34729
|
onToolCall,
|
|
34613
34730
|
onServerToolCall,
|
|
34614
34731
|
onToolCallArgumentsDelta,
|
|
34615
|
-
onStepFinish
|
|
34732
|
+
onStepFinish: keepAlive || onStepFinish ? (event) => {
|
|
34733
|
+
const pending2 = pendingInferenceRef.current;
|
|
34734
|
+
if (keepAlive && pending2 && requestIdRef.current === requestId) {
|
|
34735
|
+
pendingInferenceRef.current = { ...pending2, settled: true };
|
|
34736
|
+
}
|
|
34737
|
+
onStepFinish?.(event);
|
|
34738
|
+
} : void 0,
|
|
34616
34739
|
preProcessors,
|
|
34617
34740
|
hooks,
|
|
34618
34741
|
piiRedaction: requestPiiRedaction ?? resolvedPiiRedaction,
|
|
34619
34742
|
onPiiRedacted
|
|
34620
34743
|
});
|
|
34621
|
-
|
|
34744
|
+
const pending = pendingInferenceRef.current;
|
|
34745
|
+
const handle = pending && !pending.settled ? pending.handle : null;
|
|
34746
|
+
const detach = result.error !== null && keepAlive && handle && result.error !== "Request aborted";
|
|
34747
|
+
if (!detach) deferredErrors.forEach((error) => onError?.(error));
|
|
34748
|
+
if (result.error === null) {
|
|
34749
|
+
keepServerStream = true;
|
|
34750
|
+
return result;
|
|
34751
|
+
}
|
|
34752
|
+
if (detach) {
|
|
34753
|
+
keepServerStream = true;
|
|
34754
|
+
return {
|
|
34755
|
+
data: result.data,
|
|
34756
|
+
error: "Request detached",
|
|
34757
|
+
detached: true,
|
|
34758
|
+
resume: handle,
|
|
34759
|
+
toolsChecksum: result.toolsChecksum
|
|
34760
|
+
};
|
|
34761
|
+
}
|
|
34762
|
+
if ("detached" in result && result.detached) {
|
|
34763
|
+
keepServerStream = true;
|
|
34764
|
+
return { ...result, resume: null };
|
|
34765
|
+
}
|
|
34622
34766
|
return result;
|
|
34623
34767
|
} catch (err) {
|
|
34624
34768
|
return createErrorResult(
|
|
@@ -34629,7 +34773,8 @@ function useChat(options) {
|
|
|
34629
34773
|
if (requestIdRef.current === requestId) {
|
|
34630
34774
|
setIsLoading(false);
|
|
34631
34775
|
abortControllerRef.current = null;
|
|
34632
|
-
if (
|
|
34776
|
+
if (detachControllerRef.current === detachController) detachControllerRef.current = null;
|
|
34777
|
+
if (!keepServerStream) pendingInferenceRef.current?.cancel();
|
|
34633
34778
|
pendingInferenceRef.current = null;
|
|
34634
34779
|
}
|
|
34635
34780
|
}
|
|
@@ -34648,6 +34793,7 @@ function useChat(options) {
|
|
|
34648
34793
|
onToolCallArgumentsDelta,
|
|
34649
34794
|
onStepFinish,
|
|
34650
34795
|
resumable,
|
|
34796
|
+
keepAlive,
|
|
34651
34797
|
onStreamMeta,
|
|
34652
34798
|
defaultApiType,
|
|
34653
34799
|
smoothing,
|
|
@@ -34660,7 +34806,8 @@ function useChat(options) {
|
|
|
34660
34806
|
return {
|
|
34661
34807
|
isLoading,
|
|
34662
34808
|
sendMessage,
|
|
34663
|
-
stop
|
|
34809
|
+
stop,
|
|
34810
|
+
resumeStream: resumeStream2
|
|
34664
34811
|
};
|
|
34665
34812
|
}
|
|
34666
34813
|
|
package/dist/server/index.cjs
CHANGED
|
@@ -21163,6 +21163,7 @@ function createCryptoPricePreProcessor(options = {}) {
|
|
|
21163
21163
|
|
|
21164
21164
|
// src/lib/chat/resumeStream.ts
|
|
21165
21165
|
init_clientConfig();
|
|
21166
|
+
init_redactor();
|
|
21166
21167
|
|
|
21167
21168
|
// src/lib/chat/toolLoop.ts
|
|
21168
21169
|
init_clientConfig();
|
|
@@ -25385,16 +25386,34 @@ async function resumeStream(options) {
|
|
|
25385
25386
|
onData,
|
|
25386
25387
|
onThinking,
|
|
25387
25388
|
onFinish,
|
|
25388
|
-
onError
|
|
25389
|
+
onError,
|
|
25390
|
+
piiRedactor
|
|
25389
25391
|
} = options;
|
|
25390
25392
|
const strategy = getStrategy(handle.apiType);
|
|
25391
25393
|
const accumulator = createStreamAccumulator(handle.model || void 0);
|
|
25394
|
+
const contentDeAnon = piiRedactor && onData ? createStreamingDeAnonymizer(piiRedactor, onData) : null;
|
|
25395
|
+
const thinkingDeAnon = piiRedactor && onThinking ? createStreamingDeAnonymizer(piiRedactor, onThinking) : null;
|
|
25392
25396
|
const contentSmoother = new StreamSmoother((text12) => {
|
|
25393
|
-
if (
|
|
25397
|
+
if (contentDeAnon) contentDeAnon.push(text12);
|
|
25398
|
+
else if (onData) onData(text12);
|
|
25394
25399
|
}, smoothing);
|
|
25395
25400
|
const thinkingSmoother = new StreamSmoother((text12) => {
|
|
25396
|
-
if (
|
|
25401
|
+
if (thinkingDeAnon) thinkingDeAnon.push(text12);
|
|
25402
|
+
else if (onThinking) onThinking(text12);
|
|
25397
25403
|
}, smoothing);
|
|
25404
|
+
const flushOutput = () => {
|
|
25405
|
+
contentSmoother.flush();
|
|
25406
|
+
thinkingSmoother.flush();
|
|
25407
|
+
contentDeAnon?.flush();
|
|
25408
|
+
thinkingDeAnon?.flush();
|
|
25409
|
+
};
|
|
25410
|
+
const buildFinal = () => strategy.buildFinalResponse(
|
|
25411
|
+
piiRedactor ? {
|
|
25412
|
+
...accumulator,
|
|
25413
|
+
content: piiRedactor.deAnonymize(accumulator.content),
|
|
25414
|
+
thinking: piiRedactor.deAnonymize(accumulator.thinking)
|
|
25415
|
+
} : accumulator
|
|
25416
|
+
);
|
|
25398
25417
|
const idleController = new AbortController();
|
|
25399
25418
|
let watchdog;
|
|
25400
25419
|
let idleFired = false;
|
|
@@ -25439,9 +25458,8 @@ async function resumeStream(options) {
|
|
|
25439
25458
|
if (signal) signal.removeEventListener("abort", onCallerAbort);
|
|
25440
25459
|
};
|
|
25441
25460
|
const buildInterrupted = (message) => {
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(strategy.buildFinalResponse(accumulator)) : strategy.buildFinalResponse(accumulator);
|
|
25461
|
+
flushOutput();
|
|
25462
|
+
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(buildFinal()) : buildFinal();
|
|
25445
25463
|
return { data, error: message, interrupted: true };
|
|
25446
25464
|
};
|
|
25447
25465
|
if (combinedSignal.aborted) {
|
|
@@ -25489,18 +25507,16 @@ async function resumeStream(options) {
|
|
|
25489
25507
|
const err = replayErr instanceof Error ? replayErr : new Error(String(replayErr));
|
|
25490
25508
|
const statusCode = parseSseStatusCode(err);
|
|
25491
25509
|
if (statusCode === 410) {
|
|
25492
|
-
|
|
25493
|
-
thinkingSmoother.flush();
|
|
25510
|
+
flushOutput();
|
|
25494
25511
|
throw new StreamExpiredError(handle.inferenceId);
|
|
25495
25512
|
}
|
|
25496
25513
|
if (err.name === "AbortError" || combinedSignal.aborted) {
|
|
25497
25514
|
return buildInterrupted(abortMessage());
|
|
25498
25515
|
}
|
|
25499
|
-
|
|
25500
|
-
thinkingSmoother.flush();
|
|
25516
|
+
flushOutput();
|
|
25501
25517
|
if (onError) onError(err);
|
|
25502
25518
|
return {
|
|
25503
|
-
data:
|
|
25519
|
+
data: buildFinal(),
|
|
25504
25520
|
error: err.message,
|
|
25505
25521
|
interrupted: false,
|
|
25506
25522
|
statusCode
|
|
@@ -25516,7 +25532,9 @@ async function resumeStream(options) {
|
|
|
25516
25532
|
draining = true;
|
|
25517
25533
|
await Promise.all([contentSmoother.drain(), thinkingSmoother.drain()]);
|
|
25518
25534
|
if (playbackAborted) return buildInterrupted(abortMessage());
|
|
25519
|
-
|
|
25535
|
+
contentDeAnon?.flush();
|
|
25536
|
+
thinkingDeAnon?.flush();
|
|
25537
|
+
const response = buildFinal();
|
|
25520
25538
|
const deliveredOutput = emittedOutput || (accumulator.toolCallEvents?.length ?? 0) > 0;
|
|
25521
25539
|
if (onFinish && deliveredOutput) onFinish(response);
|
|
25522
25540
|
return { data: response, error: null, interrupted: false, empty: !deliveredOutput };
|
package/dist/server/index.d.mts
CHANGED
|
@@ -2470,6 +2470,8 @@ interface ResumeStreamOptions {
|
|
|
2470
2470
|
onData?: (chunk: string) => void;
|
|
2471
2471
|
/** Thinking/reasoning deltas as they replay. */
|
|
2472
2472
|
onThinking?: (chunk: string) => void;
|
|
2473
|
+
/** Restores the placeholders this redactor assigned when the original request was sent. */
|
|
2474
|
+
piiRedactor?: PiiRedactor;
|
|
2473
2475
|
/** Called once on a clean completion. Never called for 410 nor interrupted terminals. */
|
|
2474
2476
|
onFinish?: (response: ApiResponse) => void;
|
|
2475
2477
|
/** Called on a transient/unexpected failure. Never called for 410 (throws) nor interrupted terminals. */
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2470,6 +2470,8 @@ interface ResumeStreamOptions {
|
|
|
2470
2470
|
onData?: (chunk: string) => void;
|
|
2471
2471
|
/** Thinking/reasoning deltas as they replay. */
|
|
2472
2472
|
onThinking?: (chunk: string) => void;
|
|
2473
|
+
/** Restores the placeholders this redactor assigned when the original request was sent. */
|
|
2474
|
+
piiRedactor?: PiiRedactor;
|
|
2473
2475
|
/** Called once on a clean completion. Never called for 410 nor interrupted terminals. */
|
|
2474
2476
|
onFinish?: (response: ApiResponse) => void;
|
|
2475
2477
|
/** Called on a transient/unexpected failure. Never called for 410 (throws) nor interrupted terminals. */
|
package/dist/server/index.mjs
CHANGED
|
@@ -23655,16 +23655,34 @@ async function resumeStream(options) {
|
|
|
23655
23655
|
onData,
|
|
23656
23656
|
onThinking,
|
|
23657
23657
|
onFinish,
|
|
23658
|
-
onError
|
|
23658
|
+
onError,
|
|
23659
|
+
piiRedactor
|
|
23659
23660
|
} = options;
|
|
23660
23661
|
const strategy = getStrategy(handle.apiType);
|
|
23661
23662
|
const accumulator = createStreamAccumulator(handle.model || void 0);
|
|
23663
|
+
const contentDeAnon = piiRedactor && onData ? createStreamingDeAnonymizer(piiRedactor, onData) : null;
|
|
23664
|
+
const thinkingDeAnon = piiRedactor && onThinking ? createStreamingDeAnonymizer(piiRedactor, onThinking) : null;
|
|
23662
23665
|
const contentSmoother = new StreamSmoother((text12) => {
|
|
23663
|
-
if (
|
|
23666
|
+
if (contentDeAnon) contentDeAnon.push(text12);
|
|
23667
|
+
else if (onData) onData(text12);
|
|
23664
23668
|
}, smoothing);
|
|
23665
23669
|
const thinkingSmoother = new StreamSmoother((text12) => {
|
|
23666
|
-
if (
|
|
23670
|
+
if (thinkingDeAnon) thinkingDeAnon.push(text12);
|
|
23671
|
+
else if (onThinking) onThinking(text12);
|
|
23667
23672
|
}, smoothing);
|
|
23673
|
+
const flushOutput = () => {
|
|
23674
|
+
contentSmoother.flush();
|
|
23675
|
+
thinkingSmoother.flush();
|
|
23676
|
+
contentDeAnon?.flush();
|
|
23677
|
+
thinkingDeAnon?.flush();
|
|
23678
|
+
};
|
|
23679
|
+
const buildFinal = () => strategy.buildFinalResponse(
|
|
23680
|
+
piiRedactor ? {
|
|
23681
|
+
...accumulator,
|
|
23682
|
+
content: piiRedactor.deAnonymize(accumulator.content),
|
|
23683
|
+
thinking: piiRedactor.deAnonymize(accumulator.thinking)
|
|
23684
|
+
} : accumulator
|
|
23685
|
+
);
|
|
23668
23686
|
const idleController = new AbortController();
|
|
23669
23687
|
let watchdog;
|
|
23670
23688
|
let idleFired = false;
|
|
@@ -23709,9 +23727,8 @@ async function resumeStream(options) {
|
|
|
23709
23727
|
if (signal) signal.removeEventListener("abort", onCallerAbort);
|
|
23710
23728
|
};
|
|
23711
23729
|
const buildInterrupted = (message) => {
|
|
23712
|
-
|
|
23713
|
-
|
|
23714
|
-
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(strategy.buildFinalResponse(accumulator)) : strategy.buildFinalResponse(accumulator);
|
|
23730
|
+
flushOutput();
|
|
23731
|
+
const data = accumulator.toolCalls.size > 0 ? stripToolCalls(buildFinal()) : buildFinal();
|
|
23715
23732
|
return { data, error: message, interrupted: true };
|
|
23716
23733
|
};
|
|
23717
23734
|
if (combinedSignal.aborted) {
|
|
@@ -23759,18 +23776,16 @@ async function resumeStream(options) {
|
|
|
23759
23776
|
const err = replayErr instanceof Error ? replayErr : new Error(String(replayErr));
|
|
23760
23777
|
const statusCode = parseSseStatusCode(err);
|
|
23761
23778
|
if (statusCode === 410) {
|
|
23762
|
-
|
|
23763
|
-
thinkingSmoother.flush();
|
|
23779
|
+
flushOutput();
|
|
23764
23780
|
throw new StreamExpiredError(handle.inferenceId);
|
|
23765
23781
|
}
|
|
23766
23782
|
if (err.name === "AbortError" || combinedSignal.aborted) {
|
|
23767
23783
|
return buildInterrupted(abortMessage());
|
|
23768
23784
|
}
|
|
23769
|
-
|
|
23770
|
-
thinkingSmoother.flush();
|
|
23785
|
+
flushOutput();
|
|
23771
23786
|
if (onError) onError(err);
|
|
23772
23787
|
return {
|
|
23773
|
-
data:
|
|
23788
|
+
data: buildFinal(),
|
|
23774
23789
|
error: err.message,
|
|
23775
23790
|
interrupted: false,
|
|
23776
23791
|
statusCode
|
|
@@ -23786,7 +23801,9 @@ async function resumeStream(options) {
|
|
|
23786
23801
|
draining = true;
|
|
23787
23802
|
await Promise.all([contentSmoother.drain(), thinkingSmoother.drain()]);
|
|
23788
23803
|
if (playbackAborted) return buildInterrupted(abortMessage());
|
|
23789
|
-
|
|
23804
|
+
contentDeAnon?.flush();
|
|
23805
|
+
thinkingDeAnon?.flush();
|
|
23806
|
+
const response = buildFinal();
|
|
23790
23807
|
const deliveredOutput = emittedOutput || (accumulator.toolCallEvents?.length ?? 0) > 0;
|
|
23791
23808
|
if (onFinish && deliveredOutput) onFinish(response);
|
|
23792
23809
|
return { data: response, error: null, interrupted: false, empty: !deliveredOutput };
|