@chipmobilesdk/rn-ai 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -20
- package/README.md +99 -82
- package/package.json +36 -43
- package/skills/sdk-rn-ai/SKILL.md +1 -2
- package/src/config/behaviorConfig.ts +200 -183
- package/src/core/aiClient.ts +278 -230
- package/src/diagnostics/errors.ts +74 -71
- package/src/diagnostics/messageKeys.ts +27 -27
- package/src/index.ts +31 -34
- package/src/react/hooks.ts +123 -113
- package/src/transport/sseClient.ts +143 -106
- package/src/transport/timeouts.ts +53 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time limits for every network call the client makes (AI-04).
|
|
3
|
+
*
|
|
4
|
+
* Without them a stalled mobile connection left `useAiChat` in `loading` or
|
|
5
|
+
* `streaming`, and `useAiQuota` in `loading`, until the user gave up.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface AiTimeouts {
|
|
9
|
+
/** Request sent → response headers received, for the chat stream. */
|
|
10
|
+
connectMs: number;
|
|
11
|
+
/** Longest silence allowed between two chunks of the chat stream. */
|
|
12
|
+
idleMs: number;
|
|
13
|
+
/** Behavior-config fetch, including reading the body. */
|
|
14
|
+
configMs: number;
|
|
15
|
+
/** Quota fetch, including reading the body. */
|
|
16
|
+
quotaMs: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The gateway sends headers only once the model has answered, so `connectMs`
|
|
21
|
+
* also covers time to first token on a large image prompt.
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_AI_TIMEOUTS: AiTimeouts = {
|
|
24
|
+
connectMs: 30_000,
|
|
25
|
+
idleMs: 30_000,
|
|
26
|
+
configMs: 10_000,
|
|
27
|
+
quotaMs: 10_000,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Runs `run` with an abort signal and rejects with `onTimeout()` after `ms`.
|
|
32
|
+
* The race matters as much as the signal: an injected `fetchFn` (or an old
|
|
33
|
+
* polyfill) may ignore the signal entirely.
|
|
34
|
+
*/
|
|
35
|
+
export async function withTimeout<T>(
|
|
36
|
+
ms: number,
|
|
37
|
+
run: (signal: AbortSignal | undefined) => Promise<T>,
|
|
38
|
+
onTimeout: () => Error,
|
|
39
|
+
): Promise<T> {
|
|
40
|
+
const controller = typeof AbortController === 'undefined' ? undefined : new AbortController();
|
|
41
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
42
|
+
const expired = new Promise<never>((_, reject) => {
|
|
43
|
+
timer = setTimeout(() => {
|
|
44
|
+
controller?.abort();
|
|
45
|
+
reject(onTimeout());
|
|
46
|
+
}, ms);
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
return await Promise.race([run(controller?.signal), expired]);
|
|
50
|
+
} finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
53
|
+
}
|