@chipmobilesdk/rn-ai 0.4.0 → 0.5.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/CHANGELOG.md +120 -0
- package/README.md +5 -2
- package/lib/commonjs/config/behaviorConfig.js +283 -0
- package/lib/commonjs/config/behaviorConfig.js.map +1 -0
- package/lib/commonjs/contract/gateway.js +60 -0
- package/lib/commonjs/contract/gateway.js.map +1 -0
- package/lib/commonjs/core/aiClient.js +330 -0
- package/lib/commonjs/core/aiClient.js.map +1 -0
- package/lib/commonjs/core/quotaRequest.js +105 -0
- package/lib/commonjs/core/quotaRequest.js.map +1 -0
- package/lib/commonjs/diagnostics/errors.js +108 -0
- package/lib/commonjs/diagnostics/errors.js.map +1 -0
- package/lib/commonjs/diagnostics/messageKeys.js +68 -0
- package/lib/commonjs/diagnostics/messageKeys.js.map +1 -0
- package/lib/commonjs/index.js +102 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/react/hooks.js +170 -0
- package/lib/commonjs/react/hooks.js.map +1 -0
- package/lib/commonjs/transport/sseClient.js +151 -0
- package/lib/commonjs/transport/sseClient.js.map +1 -0
- package/lib/commonjs/transport/timeouts.js +46 -0
- package/lib/commonjs/transport/timeouts.js.map +1 -0
- package/lib/module/config/behaviorConfig.js +275 -0
- package/lib/module/config/behaviorConfig.js.map +1 -0
- package/lib/module/contract/gateway.js +56 -0
- package/lib/module/contract/gateway.js.map +1 -0
- package/lib/module/core/aiClient.js +327 -0
- package/lib/module/core/aiClient.js.map +1 -0
- package/lib/module/core/quotaRequest.js +102 -0
- package/lib/module/core/quotaRequest.js.map +1 -0
- package/lib/module/diagnostics/errors.js +99 -0
- package/lib/module/diagnostics/errors.js.map +1 -0
- package/lib/module/diagnostics/messageKeys.js +61 -0
- package/lib/module/diagnostics/messageKeys.js.map +1 -0
- package/lib/module/index.js +19 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/react/hooks.js +164 -0
- package/lib/module/react/hooks.js.map +1 -0
- package/lib/module/transport/sseClient.js +146 -0
- package/lib/module/transport/sseClient.js.map +1 -0
- package/lib/module/transport/timeouts.js +41 -0
- package/lib/module/transport/timeouts.js.map +1 -0
- package/lib/typescript/commonjs/config/behaviorConfig.d.ts +119 -0
- package/lib/typescript/commonjs/config/behaviorConfig.d.ts.map +1 -0
- package/lib/typescript/commonjs/contract/gateway.d.ts +64 -0
- package/lib/typescript/commonjs/contract/gateway.d.ts.map +1 -0
- package/lib/typescript/commonjs/core/aiClient.d.ts +104 -0
- package/lib/typescript/commonjs/core/aiClient.d.ts.map +1 -0
- package/lib/typescript/commonjs/core/quotaRequest.d.ts +45 -0
- package/lib/typescript/commonjs/core/quotaRequest.d.ts.map +1 -0
- package/lib/typescript/commonjs/diagnostics/errors.d.ts +38 -0
- package/lib/typescript/commonjs/diagnostics/errors.d.ts.map +1 -0
- package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts +46 -0
- package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +21 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/react/hooks.d.ts +37 -0
- package/lib/typescript/commonjs/react/hooks.d.ts.map +1 -0
- package/lib/typescript/commonjs/transport/sseClient.d.ts +57 -0
- package/lib/typescript/commonjs/transport/sseClient.d.ts.map +1 -0
- package/lib/typescript/commonjs/transport/timeouts.d.ts +28 -0
- package/lib/typescript/commonjs/transport/timeouts.d.ts.map +1 -0
- package/lib/typescript/module/config/behaviorConfig.d.ts +119 -0
- package/lib/typescript/module/config/behaviorConfig.d.ts.map +1 -0
- package/lib/typescript/module/contract/gateway.d.ts +64 -0
- package/lib/typescript/module/contract/gateway.d.ts.map +1 -0
- package/lib/typescript/module/core/aiClient.d.ts +104 -0
- package/lib/typescript/module/core/aiClient.d.ts.map +1 -0
- package/lib/typescript/module/core/quotaRequest.d.ts +45 -0
- package/lib/typescript/module/core/quotaRequest.d.ts.map +1 -0
- package/lib/typescript/module/diagnostics/errors.d.ts +38 -0
- package/lib/typescript/module/diagnostics/errors.d.ts.map +1 -0
- package/lib/typescript/module/diagnostics/messageKeys.d.ts +46 -0
- package/lib/typescript/module/diagnostics/messageKeys.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +21 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/react/hooks.d.ts +37 -0
- package/lib/typescript/module/react/hooks.d.ts.map +1 -0
- package/lib/typescript/module/transport/sseClient.d.ts +57 -0
- package/lib/typescript/module/transport/sseClient.d.ts.map +1 -0
- package/lib/typescript/module/transport/timeouts.d.ts +28 -0
- package/lib/typescript/module/transport/timeouts.d.ts.map +1 -0
- package/package.json +40 -12
- package/skills/sdk-rn-ai/SKILL.md +8 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal SSE reader over XMLHttpRequest (research R2).
|
|
5
|
+
*
|
|
6
|
+
* React Native's fetch does not reliably expose ReadableStream on Hermes, so
|
|
7
|
+
* we use XHR incremental text delivery (readyState LOADING + onprogress) —
|
|
8
|
+
* the same mechanism community SSE libraries use — with zero dependencies.
|
|
9
|
+
* The gateway never compresses SSE responses (contract), which keeps
|
|
10
|
+
* incremental delivery intact on both platforms.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** What the response said besides its body. Absent for a failure with no response. */
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The transport port: how this package makes a streaming request.
|
|
17
|
+
*
|
|
18
|
+
* A published port rather than `typeof requestSse`, so the default reader's
|
|
19
|
+
* own signature is not part of the public API (AI-18): an app may inject its
|
|
20
|
+
* own transport, and this package may change how `requestSse` is written
|
|
21
|
+
* without that being a breaking change.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse complete `data:` events out of `text` starting at `fromIndex`.
|
|
26
|
+
*
|
|
27
|
+
* Both line endings are accepted. A proxy that normalises to CRLF — an API
|
|
28
|
+
* gateway or a corporate middlebox — used to make every event invisible until
|
|
29
|
+
* the stream closed, because only `\n\n` counted as a separator (AI-22).
|
|
30
|
+
*/
|
|
31
|
+
export function drainSseEvents(text, fromIndex, emit) {
|
|
32
|
+
let cursor = fromIndex;
|
|
33
|
+
for (;;) {
|
|
34
|
+
const separator = /\r\n\r\n|\n\n|\r\r/.exec(text.slice(cursor));
|
|
35
|
+
if (!separator) {
|
|
36
|
+
return cursor; // incomplete event stays buffered
|
|
37
|
+
}
|
|
38
|
+
const rawEvent = text.slice(cursor, cursor + separator.index);
|
|
39
|
+
cursor += separator.index + separator[0].length;
|
|
40
|
+
const dataLines = rawEvent.split(/\r\n|\n|\r/).filter(line => line.startsWith('data:')).map(line => line.slice(5).trimStart());
|
|
41
|
+
if (dataLines.length > 0) {
|
|
42
|
+
emit(dataLines.join('\n'));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function requestSse(request, handlers) {
|
|
47
|
+
const xhr = new XMLHttpRequest();
|
|
48
|
+
let seen = 0;
|
|
49
|
+
let finished = false;
|
|
50
|
+
let cancelled = false;
|
|
51
|
+
|
|
52
|
+
// One timer, re-armed as the request progresses: the connect limit until
|
|
53
|
+
// headers arrive, then the idle limit, restarted by every chunk.
|
|
54
|
+
let stallTimer;
|
|
55
|
+
const disarm = () => {
|
|
56
|
+
if (stallTimer !== undefined) {
|
|
57
|
+
clearTimeout(stallTimer);
|
|
58
|
+
stallTimer = undefined;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** The response's own headers, for `Retry-After` on a 429 (AI-11). */
|
|
63
|
+
const response = {
|
|
64
|
+
getHeader(name) {
|
|
65
|
+
try {
|
|
66
|
+
return xhr.getResponseHeader(name);
|
|
67
|
+
} catch {
|
|
68
|
+
// Headers are unavailable before they arrive, and on some polyfills.
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const finish = fn => {
|
|
74
|
+
disarm();
|
|
75
|
+
if (!finished && !cancelled) {
|
|
76
|
+
finished = true;
|
|
77
|
+
fn();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const stalled = () => {
|
|
81
|
+
stallTimer = undefined;
|
|
82
|
+
if (finished || cancelled) return;
|
|
83
|
+
finished = true;
|
|
84
|
+
try {
|
|
85
|
+
xhr.abort();
|
|
86
|
+
} catch {
|
|
87
|
+
// already settled
|
|
88
|
+
}
|
|
89
|
+
handlers.onError(0, 'timeout');
|
|
90
|
+
};
|
|
91
|
+
const arm = ms => {
|
|
92
|
+
disarm();
|
|
93
|
+
if (ms && !finished && !cancelled) stallTimer = setTimeout(stalled, ms);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Drains whatever has arrived. `onprogress` and `readyState === 3` both fire
|
|
98
|
+
* for the same chunk, and which of the two fires at all has been platform
|
|
99
|
+
* dependent, so both stay registered; the length check makes the second call
|
|
100
|
+
* for one chunk free rather than another full `responseText` drain (AI-V1).
|
|
101
|
+
*/
|
|
102
|
+
let drained = -1;
|
|
103
|
+
const pump = () => {
|
|
104
|
+
if (xhr.status !== 200) return; // error path handled on load/error
|
|
105
|
+
const text = xhr.responseText ?? '';
|
|
106
|
+
if (text.length === drained) return;
|
|
107
|
+
drained = text.length;
|
|
108
|
+
arm(request.idleTimeoutMs);
|
|
109
|
+
seen = drainSseEvents(text, seen, handlers.onData);
|
|
110
|
+
};
|
|
111
|
+
xhr.open(request.method ?? 'POST', request.url, true);
|
|
112
|
+
for (const [k, v] of Object.entries(request.headers ?? {})) {
|
|
113
|
+
xhr.setRequestHeader(k, v);
|
|
114
|
+
}
|
|
115
|
+
xhr.setRequestHeader('Accept', 'text/event-stream');
|
|
116
|
+
if (request.timeoutMs) xhr.timeout = request.timeoutMs;
|
|
117
|
+
xhr.onprogress = pump;
|
|
118
|
+
xhr.onreadystatechange = () => {
|
|
119
|
+
if (xhr.readyState === 2) arm(request.connectTimeoutMs); // HEADERS_RECEIVED
|
|
120
|
+
if (xhr.readyState === 3) pump(); // LOADING: incremental text
|
|
121
|
+
};
|
|
122
|
+
xhr.onload = () => {
|
|
123
|
+
if (xhr.status === 200) {
|
|
124
|
+
pump();
|
|
125
|
+
finish(handlers.onEnd);
|
|
126
|
+
} else {
|
|
127
|
+
finish(() => handlers.onError(xhr.status, xhr.responseText ?? '', response));
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
xhr.onerror = () => finish(() => handlers.onError(0, 'network error'));
|
|
131
|
+
xhr.ontimeout = () => finish(() => handlers.onError(0, 'timeout'));
|
|
132
|
+
xhr.send(request.body);
|
|
133
|
+
arm(request.connectTimeoutMs);
|
|
134
|
+
return {
|
|
135
|
+
cancel() {
|
|
136
|
+
cancelled = true;
|
|
137
|
+
disarm();
|
|
138
|
+
try {
|
|
139
|
+
xhr.abort();
|
|
140
|
+
} catch {
|
|
141
|
+
// aborting a settled XHR is a no-op
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=sseClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["drainSseEvents","text","fromIndex","emit","cursor","separator","exec","slice","rawEvent","index","length","dataLines","split","filter","line","startsWith","map","trimStart","join","requestSse","request","handlers","xhr","XMLHttpRequest","seen","finished","cancelled","stallTimer","disarm","undefined","clearTimeout","response","getHeader","name","getResponseHeader","finish","fn","stalled","abort","onError","arm","ms","setTimeout","drained","pump","status","responseText","idleTimeoutMs","onData","open","method","url","k","v","Object","entries","headers","setRequestHeader","timeoutMs","timeout","onprogress","onreadystatechange","readyState","connectTimeoutMs","onload","onEnd","onerror","ontimeout","send","body","cancel"],"sourceRoot":"../../../src","sources":["transport/sseClient.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Time limits for every network call the client makes (AI-04).
|
|
5
|
+
*
|
|
6
|
+
* Without them a stalled mobile connection left `useAiChat` in `loading` or
|
|
7
|
+
* `streaming`, and `useAiQuota` in `loading`, until the user gave up.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The gateway sends headers only once the model has answered, so `connectMs`
|
|
12
|
+
* also covers time to first token on a large image prompt.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_AI_TIMEOUTS = {
|
|
15
|
+
connectMs: 30_000,
|
|
16
|
+
idleMs: 30_000,
|
|
17
|
+
configMs: 10_000,
|
|
18
|
+
quotaMs: 10_000
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Runs `run` with an abort signal and rejects with `onTimeout()` after `ms`.
|
|
23
|
+
* The race matters as much as the signal: an injected `fetchFn` (or an old
|
|
24
|
+
* polyfill) may ignore the signal entirely.
|
|
25
|
+
*/
|
|
26
|
+
export async function withTimeout(ms, run, onTimeout) {
|
|
27
|
+
const controller = typeof AbortController === 'undefined' ? undefined : new AbortController();
|
|
28
|
+
let timer;
|
|
29
|
+
const expired = new Promise((_, reject) => {
|
|
30
|
+
timer = setTimeout(() => {
|
|
31
|
+
controller?.abort();
|
|
32
|
+
reject(onTimeout());
|
|
33
|
+
}, ms);
|
|
34
|
+
});
|
|
35
|
+
try {
|
|
36
|
+
return await Promise.race([run(controller?.signal), expired]);
|
|
37
|
+
} finally {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=timeouts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DEFAULT_AI_TIMEOUTS","connectMs","idleMs","configMs","quotaMs","withTimeout","ms","run","onTimeout","controller","AbortController","undefined","timer","expired","Promise","_","reject","setTimeout","abort","race","signal","clearTimeout"],"sourceRoot":"../../../src","sources":["transport/timeouts.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;;AAaA;AACA;AACA;AACA;AACA,OAAO,MAAMA,mBAA+B,GAAG;EAC9CC,SAAS,EAAE,MAAM;EACjBC,MAAM,EAAE,MAAM;EACdC,QAAQ,EAAE,MAAM;EAChBC,OAAO,EAAE;AACV,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,WAAWA,CAChCC,EAAU,EACVC,GAAoD,EACpDC,SAAsB,EACT;EACb,MAAMC,UAAU,GAAG,OAAOC,eAAe,KAAK,WAAW,GAAGC,SAAS,GAAG,IAAID,eAAe,CAAC,CAAC;EAC7F,IAAIE,KAAgD;EACpD,MAAMC,OAAO,GAAG,IAAIC,OAAO,CAAQ,CAACC,CAAC,EAAEC,MAAM,KAAK;IACjDJ,KAAK,GAAGK,UAAU,CAAC,MAAM;MACxBR,UAAU,EAAES,KAAK,CAAC,CAAC;MACnBF,MAAM,CAACR,SAAS,CAAC,CAAC,CAAC;IACpB,CAAC,EAAEF,EAAE,CAAC;EACP,CAAC,CAAC;EACF,IAAI;IACH,OAAO,MAAMQ,OAAO,CAACK,IAAI,CAAC,CAACZ,GAAG,CAACE,UAAU,EAAEW,MAAM,CAAC,EAAEP,OAAO,CAAC,CAAC;EAC9D,CAAC,SAAS;IACTQ,YAAY,CAACT,KAAK,CAAC;EACpB;AACD","ignoreList":[]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type KeyValuePort } from '@chipmobilesdk/rn-core';
|
|
2
|
+
/** App behavior configuration (contracts/app-behavior-config.md). */
|
|
3
|
+
export interface AppBehaviorConfig {
|
|
4
|
+
schemaVersion: number;
|
|
5
|
+
appId: string;
|
|
6
|
+
configVersion: number;
|
|
7
|
+
refreshTtlSeconds: number;
|
|
8
|
+
api: {
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
scopes: string[];
|
|
11
|
+
supportsStreaming: boolean;
|
|
12
|
+
};
|
|
13
|
+
limitsDisplay?: {
|
|
14
|
+
requestsPerDay?: number;
|
|
15
|
+
tokensPerDay?: number;
|
|
16
|
+
};
|
|
17
|
+
recovery: {
|
|
18
|
+
reloadOnHttpStatus: number[];
|
|
19
|
+
maxSilentRetries: number;
|
|
20
|
+
retryBackoffMs: number[];
|
|
21
|
+
};
|
|
22
|
+
features: {
|
|
23
|
+
aiEnabled: boolean;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Persistence port; default is in-memory (inject a durable store for offline launch). */
|
|
27
|
+
export interface AiConfigCache {
|
|
28
|
+
get(key: string): Promise<string | null>;
|
|
29
|
+
set(key: string, value: string): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export declare class MemoryConfigCache implements AiConfigCache {
|
|
32
|
+
private map;
|
|
33
|
+
get(key: string): Promise<string | null>;
|
|
34
|
+
set(key: string, value: string): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* An `AiConfigCache` over rn-core's synchronous `KeyValuePort` (AI-10).
|
|
38
|
+
*
|
|
39
|
+
* Without a durable cache every launch waits for the network before the first
|
|
40
|
+
* chat, which is exactly what the cache-first design exists to avoid. Open the
|
|
41
|
+
* port the way the app opens its other durable state, for example
|
|
42
|
+
* `openDurable(() => createMMKV({ id: 'app' }))`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function configCacheFromKeyValue(port: KeyValuePort): AiConfigCache;
|
|
45
|
+
export type BehaviorState = 'unloaded' | 'ready-network' | 'ready-cache' | 'unavailable';
|
|
46
|
+
/** The newest document layout this release understands. */
|
|
47
|
+
export declare const SUPPORTED_SCHEMA_VERSION = 1;
|
|
48
|
+
/** https, or http on a development machine: a bearer token travels to this host. */
|
|
49
|
+
export declare function isTrustedUrl(url: string): boolean;
|
|
50
|
+
export interface ParseBehaviorConfigOptions {
|
|
51
|
+
/** The app this document must be for; a document for another app is refused. */
|
|
52
|
+
expectedAppId?: string;
|
|
53
|
+
/** Hosts `api.baseUrl` may name. Any host is accepted when omitted. */
|
|
54
|
+
allowedHosts?: readonly string[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Parse + validate; unknown fields ignored (forward compatibility).
|
|
58
|
+
*
|
|
59
|
+
* Every field this package acts on is checked here, because the document is
|
|
60
|
+
* remote and the alternative is a TypeError inside an XHR callback, a revalidate
|
|
61
|
+
* on every single request, or a bearer token sent to a host nobody vetted
|
|
62
|
+
* (AI-06, AI-07).
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseBehaviorConfig(json: string, options?: ParseBehaviorConfigOptions): AppBehaviorConfig;
|
|
65
|
+
export interface BehaviorConfigDeps {
|
|
66
|
+
configUrl: string;
|
|
67
|
+
appId: string;
|
|
68
|
+
cache?: AiConfigCache;
|
|
69
|
+
fetchFn?: typeof fetch;
|
|
70
|
+
now?: () => number;
|
|
71
|
+
/** Limit on one config fetch, body included. Defaults to 10 s. */
|
|
72
|
+
timeoutMs?: number;
|
|
73
|
+
/** Hosts the document's `api.baseUrl` may name. */
|
|
74
|
+
allowedHosts?: readonly string[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Cache-first behavior config (FR-018): launch never blocks on the network;
|
|
78
|
+
* TTL revalidation uses ETag; designated errors force a reload.
|
|
79
|
+
*/
|
|
80
|
+
export declare class BehaviorConfigManager {
|
|
81
|
+
private deps;
|
|
82
|
+
private cacheKey;
|
|
83
|
+
private cache;
|
|
84
|
+
private fetchFn;
|
|
85
|
+
private now;
|
|
86
|
+
private current?;
|
|
87
|
+
/**
|
|
88
|
+
* One cache read and one network fetch at a time (AI-08): a cold start makes a
|
|
89
|
+
* chat and a quota call together, and each used to fetch the config itself.
|
|
90
|
+
*/
|
|
91
|
+
private readonly cacheRead;
|
|
92
|
+
private readonly networkFetch;
|
|
93
|
+
private currentState;
|
|
94
|
+
private readonly stateListeners;
|
|
95
|
+
/** Where the config came from, or why there is none. */
|
|
96
|
+
get state(): BehaviorState;
|
|
97
|
+
/** Called whenever `state` changes (AI-09). */
|
|
98
|
+
subscribe(listener: () => void): () => void;
|
|
99
|
+
private setState;
|
|
100
|
+
constructor(deps: BehaviorConfigDeps);
|
|
101
|
+
private parse;
|
|
102
|
+
private isFresh;
|
|
103
|
+
private loadFromCache;
|
|
104
|
+
private readCache;
|
|
105
|
+
private fetchNetwork;
|
|
106
|
+
/** One attempt; `conditional` sends the stored ETag when there is one. */
|
|
107
|
+
private fetchOnce;
|
|
108
|
+
private fetchFromNetwork;
|
|
109
|
+
private persist;
|
|
110
|
+
/**
|
|
111
|
+
* Cache-first read. Fresh cache returns immediately; stale cache returns
|
|
112
|
+
* immediately too while a background revalidation runs; no cache at all
|
|
113
|
+
* falls through to the network (or `config-unavailable`).
|
|
114
|
+
*/
|
|
115
|
+
getConfig(options?: {
|
|
116
|
+
forceReload?: boolean;
|
|
117
|
+
}): Promise<AppBehaviorConfig>;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=behaviorConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behaviorConfig.d.ts","sourceRoot":"","sources":["../../../../src/config/behaviorConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAKlG,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAA;KAAE,CAAC;IACvE,aAAa,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,QAAQ,EAAE;QACT,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IACF,QAAQ,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CACjC;AAED,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,qBAAa,iBAAkB,YAAW,aAAa;IACtD,OAAO,CAAC,GAAG,CAA6B;IAClC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAGxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpD;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CASzE;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,eAAe,GAAG,aAAa,GAAG,aAAa,CAAC;AAEzF,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAiB1C,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAKjD;AASD,MAAM,WAAW,0BAA0B;IAC1C,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,0BAA+B,GACtC,iBAAiB,CAmEnB;AAQD,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IA+BrB,OAAO,CAAC,IAAI;IA9BxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,OAAO,CAAC,CAAyD;IACzE;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2C;IACxE,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2B;IAE1D,wDAAwD;IACxD,IAAI,KAAK,IAAI,aAAa,CAEzB;IAED,+CAA+C;IAC/C,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAI3C,OAAO,CAAC,QAAQ;gBAMI,IAAI,EAAE,kBAAkB;IAY5C,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,aAAa;YAIP,SAAS;IAavB,OAAO,CAAC,YAAY;IAIpB,0EAA0E;YAC5D,SAAS;YAuBT,gBAAgB;YA6BhB,OAAO;IAIrB;;;;OAIG;IACG,SAAS,CAAC,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAgBpF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gateway↔client contract: error codes, quota headers, stream events.
|
|
3
|
+
*
|
|
4
|
+
* One definition, imported by both sides (GW-13). The gateway's own codes and
|
|
5
|
+
* the client's map of them were two hand-maintained lists, and they had already
|
|
6
|
+
* drifted: `BAD_REQUEST`, `ENDPOINT_RETIRED` and `INTERNAL` existed on the
|
|
7
|
+
* server and were unknown to the client, which fell back to a guess from the
|
|
8
|
+
* status. Adding a code now fails to compile on whichever side has not handled
|
|
9
|
+
* it.
|
|
10
|
+
*
|
|
11
|
+
* Types and plain constants only, and no import of anything: the gateway runs
|
|
12
|
+
* on Node and imports this file for its types alone.
|
|
13
|
+
*/
|
|
14
|
+
/** Every error the gateway answers with (`error.code` in the body). */
|
|
15
|
+
export type GatewayErrorCode = 'BAD_REQUEST' | 'AUTH_INVALID' | 'NOT_ENTITLED' | 'USER_BLOCKED' | 'APP_UNKNOWN' | 'ENDPOINT_RETIRED' | 'PAYLOAD_TOO_LARGE' | 'MODALITY_NOT_ALLOWED' | 'RATE_LIMITED' | 'UPSTREAM_BUSY' | 'UPSTREAM_ERROR' | 'INTERNAL';
|
|
16
|
+
/** The HTTP status each code is sent with. */
|
|
17
|
+
export declare const GATEWAY_ERROR_STATUS: Readonly<Record<GatewayErrorCode, number>>;
|
|
18
|
+
/** The error body. `message` is safe to log; it never carries upstream detail. */
|
|
19
|
+
export interface GatewayErrorBody {
|
|
20
|
+
error: {
|
|
21
|
+
code: GatewayErrorCode;
|
|
22
|
+
message: string;
|
|
23
|
+
retryAfterSeconds?: number;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** The quota headers, by name. A rename here breaks both sides' compile. */
|
|
27
|
+
export declare const QUOTA_HEADERS: {
|
|
28
|
+
readonly minuteRemaining: "X-Quota-Minute-Remaining";
|
|
29
|
+
readonly dayRemaining: "X-Quota-Day-Remaining";
|
|
30
|
+
readonly dayTokensRemaining: "X-Quota-Day-Tokens-Remaining";
|
|
31
|
+
};
|
|
32
|
+
/** The names field by field, so a side declaring its own literals is checked exactly. */
|
|
33
|
+
export type QuotaHeaderNames = typeof QUOTA_HEADERS;
|
|
34
|
+
export type QuotaHeaderName = QuotaHeaderNames[keyof QuotaHeaderNames];
|
|
35
|
+
/** What is left of an app's allowance, as the gateway reports it. */
|
|
36
|
+
export interface GatewayQuota {
|
|
37
|
+
minuteRemaining: number;
|
|
38
|
+
dayRemaining: number;
|
|
39
|
+
dayTokensRemaining: number;
|
|
40
|
+
}
|
|
41
|
+
/** What one answer cost. */
|
|
42
|
+
export interface GatewayUsage {
|
|
43
|
+
promptTokens: number;
|
|
44
|
+
completionTokens: number;
|
|
45
|
+
totalTokens: number;
|
|
46
|
+
}
|
|
47
|
+
/** The `data:` payloads of a chat stream, before the `[DONE]` sentinel. */
|
|
48
|
+
export type GatewayStreamEvent = {
|
|
49
|
+
type: 'delta';
|
|
50
|
+
text: string;
|
|
51
|
+
} | {
|
|
52
|
+
type: 'done';
|
|
53
|
+
usage: GatewayUsage;
|
|
54
|
+
quota?: GatewayQuota;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'error';
|
|
57
|
+
code: GatewayErrorCode;
|
|
58
|
+
};
|
|
59
|
+
/** The last `data:` line of a stream that completed. */
|
|
60
|
+
export declare const SSE_DONE_SENTINEL = "[DONE]";
|
|
61
|
+
export type SseDoneSentinel = typeof SSE_DONE_SENTINEL;
|
|
62
|
+
/** The `Retry-After` header, which a 429 always carries. */
|
|
63
|
+
export declare const RETRY_AFTER_HEADER = "Retry-After";
|
|
64
|
+
//# sourceMappingURL=gateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../../src/contract/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GACzB,aAAa,GACb,cAAc,GACd,cAAc,GACd,cAAc,GACd,aAAa,GACb,kBAAkB,GAClB,mBAAmB,GACnB,sBAAsB,GACtB,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,UAAU,CAAC;AAEd,8CAA8C;AAC9C,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAa3E,CAAC;AAEF,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE;QACN,IAAI,EAAE,gBAAgB,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACF;AAED,4EAA4E;AAC5E,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAEX,yFAAyF;AACzF,MAAM,MAAM,gBAAgB,GAAG,OAAO,aAAa,CAAC;AACpD,MAAM,MAAM,eAAe,GAAG,gBAAgB,CAAC,MAAM,gBAAgB,CAAC,CAAC;AAEvE,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AAED,4BAA4B;AAC5B,MAAM,WAAW,YAAY;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAC3B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,YAAY,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE7C,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,MAAM,MAAM,eAAe,GAAG,OAAO,iBAAiB,CAAC;AAEvD,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type Scheduler } from '@chipmobilesdk/rn-core';
|
|
2
|
+
import { type AiConfigCache, type BehaviorState } from '../config/behaviorConfig';
|
|
3
|
+
import { type GatewayQuota, type GatewayUsage } from '../contract/gateway';
|
|
4
|
+
import { AiError } from '../diagnostics/errors';
|
|
5
|
+
import { type StreamTransport } from '../transport/sseClient';
|
|
6
|
+
import { type AiTimeouts } from '../transport/timeouts';
|
|
7
|
+
export interface AccessTokenRequestOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Skip the cached token and ask the provider for a new one. Set after a 401:
|
|
10
|
+
* the cached token is valid by the clock and refused by the server, so asking
|
|
11
|
+
* again without this re-sends the token that was just rejected (AI-01).
|
|
12
|
+
*/
|
|
13
|
+
forceRefresh?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** Minimal slice of the rn-auth `Auth` controller the client needs. */
|
|
16
|
+
export interface TokenProvider {
|
|
17
|
+
requestAccessToken(resourceKey: string, options?: AccessTokenRequestOptions): Promise<{
|
|
18
|
+
status: string;
|
|
19
|
+
token?: string;
|
|
20
|
+
errorCode?: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
export type ContentPart = {
|
|
24
|
+
type: 'text';
|
|
25
|
+
text: string;
|
|
26
|
+
} | {
|
|
27
|
+
type: 'image';
|
|
28
|
+
mimeType: string;
|
|
29
|
+
dataBase64: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'audio';
|
|
32
|
+
format: 'wav' | 'mp3';
|
|
33
|
+
dataBase64: string;
|
|
34
|
+
};
|
|
35
|
+
export interface ChatMessage {
|
|
36
|
+
role: 'system' | 'user' | 'assistant';
|
|
37
|
+
content: ContentPart[];
|
|
38
|
+
}
|
|
39
|
+
export interface ChatRequest {
|
|
40
|
+
messages: ChatMessage[];
|
|
41
|
+
options?: {
|
|
42
|
+
temperature?: number;
|
|
43
|
+
maxOutputTokens?: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** What one answer cost, as the gateway reports it. */
|
|
47
|
+
export type Usage = GatewayUsage;
|
|
48
|
+
/** What is left of the app's allowance. */
|
|
49
|
+
export type QuotaSnapshot = GatewayQuota;
|
|
50
|
+
export interface ChatStreamHandlers {
|
|
51
|
+
onDelta(text: string): void;
|
|
52
|
+
onDone(result: {
|
|
53
|
+
usage: Usage;
|
|
54
|
+
quota?: QuotaSnapshot;
|
|
55
|
+
}): void;
|
|
56
|
+
onError(error: AiError): void;
|
|
57
|
+
}
|
|
58
|
+
export interface ChatHandle {
|
|
59
|
+
cancel(): void;
|
|
60
|
+
}
|
|
61
|
+
export interface AiBehaviorState {
|
|
62
|
+
config: BehaviorState;
|
|
63
|
+
aiEnabled: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface AiClientConfig {
|
|
66
|
+
appId: string;
|
|
67
|
+
configUrl: string;
|
|
68
|
+
auth: TokenProvider;
|
|
69
|
+
/** rn-auth resource key configured for the gateway API scope. */
|
|
70
|
+
resourceKey?: string;
|
|
71
|
+
storage?: AiConfigCache;
|
|
72
|
+
fetchFn?: typeof fetch;
|
|
73
|
+
/** The streaming transport. Injected in tests, or to replace the XHR reader. */
|
|
74
|
+
transport?: StreamTransport;
|
|
75
|
+
/** Overrides for the network time limits; see `AiTimeouts` for the defaults. */
|
|
76
|
+
timeouts?: Partial<AiTimeouts>;
|
|
77
|
+
/** Test seam: how the backoff before a silent retry is waited out. */
|
|
78
|
+
scheduler?: Scheduler;
|
|
79
|
+
/**
|
|
80
|
+
* Hosts the remote config's `api.baseUrl` may name. A config document decides
|
|
81
|
+
* where this client sends its bearer token, so an app with a fixed deployment
|
|
82
|
+
* can pin it (AI-07).
|
|
83
|
+
*/
|
|
84
|
+
allowedHosts?: readonly string[];
|
|
85
|
+
}
|
|
86
|
+
export interface AiClient {
|
|
87
|
+
chat(request: ChatRequest, handlers: ChatStreamHandlers): ChatHandle;
|
|
88
|
+
getQuota(): Promise<QuotaSnapshot>;
|
|
89
|
+
/**
|
|
90
|
+
* The last quota this client saw, from a chat's `done` event or `getQuota`.
|
|
91
|
+
* Optional so an app's own `AiClient` keeps compiling.
|
|
92
|
+
*/
|
|
93
|
+
lastQuota?(): QuotaSnapshot | undefined;
|
|
94
|
+
/** The current behavior state; the same object until it changes. */
|
|
95
|
+
getBehaviorState(): AiBehaviorState;
|
|
96
|
+
/**
|
|
97
|
+
* Called whenever the behavior state or the last quota changes (AI-09, AI-13);
|
|
98
|
+
* returns the unsubscribe. Optional so an app's own `AiClient` keeps compiling.
|
|
99
|
+
*/
|
|
100
|
+
subscribe?(listener: () => void): () => void;
|
|
101
|
+
reloadConfig(): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
export declare function createAiClient(clientConfig: AiClientConfig): AiClient;
|
|
104
|
+
//# sourceMappingURL=aiClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiClient.d.ts","sourceRoot":"","sources":["../../../../src/core/aiClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The quota request, and the recovery it shares with a chat (AI-13).
|
|
3
|
+
*
|
|
4
|
+
* `getQuota` used to be the one call with no recovery at all: a gateway that
|
|
5
|
+
* had moved answered 404 for quota while chats silently re-routed, so the
|
|
6
|
+
* figure on screen failed while the feature worked. It now goes through the
|
|
7
|
+
* same `recover` the chat stream does — a designated status reloads the
|
|
8
|
+
* configuration and retries, a 401 retries once with a token the provider had
|
|
9
|
+
* to fetch again.
|
|
10
|
+
*/
|
|
11
|
+
import type { AppBehaviorConfig } from '../config/behaviorConfig';
|
|
12
|
+
import { AiError } from '../diagnostics/errors';
|
|
13
|
+
import { type AiTimeouts } from '../transport/timeouts';
|
|
14
|
+
/** Where the quota request is in its recovery, shared with the chat path. */
|
|
15
|
+
export interface RecoveryState {
|
|
16
|
+
configReloads: number;
|
|
17
|
+
authRetries: number;
|
|
18
|
+
}
|
|
19
|
+
export interface QuotaRequestDeps {
|
|
20
|
+
fetchFn: typeof fetch;
|
|
21
|
+
timeouts: AiTimeouts;
|
|
22
|
+
acquire: (options?: {
|
|
23
|
+
forceRefresh?: boolean;
|
|
24
|
+
}) => Promise<{
|
|
25
|
+
config: AppBehaviorConfig;
|
|
26
|
+
token: string;
|
|
27
|
+
}>;
|
|
28
|
+
endpoint: (config: AppBehaviorConfig, path: 'chat' | 'quota') => string;
|
|
29
|
+
asQuota: (value: unknown) => QuotaSnapshot | undefined;
|
|
30
|
+
recover: (status: number, bodyText: string, state: RecoveryState, context: {
|
|
31
|
+
getHeader?: (name: string) => string | null;
|
|
32
|
+
}, retry: (next: RecoveryState) => void, onFailure: (error: unknown) => void, onGiveUp: (error: AiError) => void) => void;
|
|
33
|
+
report: (error: AiError) => void;
|
|
34
|
+
setQuota: (next: QuotaSnapshot | undefined) => void;
|
|
35
|
+
}
|
|
36
|
+
/** What is left of the app's allowance. */
|
|
37
|
+
export type QuotaSnapshot = {
|
|
38
|
+
minuteRemaining: number;
|
|
39
|
+
dayRemaining: number;
|
|
40
|
+
dayTokensRemaining: number;
|
|
41
|
+
};
|
|
42
|
+
export declare function createQuotaRequest(deps: QuotaRequestDeps): {
|
|
43
|
+
getQuota: () => Promise<QuotaSnapshot>;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=quotaRequest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quotaRequest.d.ts","sourceRoot":"","sources":["../../../../src/core/quotaRequest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAErE,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,OAAO,KAAK,CAAC;IACtB,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;QAC1D,MAAM,EAAE,iBAAiB,CAAC;QAC1B,KAAK,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;IACxE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,aAAa,GAAG,SAAS,CAAC;IACvD,OAAO,EAAE,CACR,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE;QAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;KAAE,EACxD,KAAK,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,EACpC,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,EACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,KAC9B,IAAI,CAAC;IACV,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;CACpD;AAED,2CAA2C;AAC3C,MAAM,MAAM,aAAa,GAAG;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB;oBAI7B,OAAO,CAAC,aAAa,CAAC;EAuEjD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Typed client errors (contracts/rn-ai-public-api.md). */
|
|
2
|
+
import { SdkError } from '@chipmobilesdk/rn-core';
|
|
3
|
+
export type AiErrorCode = 'auth-invalid'
|
|
4
|
+
/** The session itself ended: the user has to sign in again. */
|
|
5
|
+
| 'session-expired' | 'not-entitled' | 'user-blocked' | 'app-unknown' | 'rate-limited' | 'upstream-busy' | 'payload-too-large' | 'modality-not-allowed' | 'config-unavailable'
|
|
6
|
+
/** The request never reached the gateway: no connection, a timeout, a dropped stream. */
|
|
7
|
+
| 'network' | 'upstream-error' | 'internal';
|
|
8
|
+
export interface AiErrorOptions {
|
|
9
|
+
retryAfterSeconds?: number | undefined;
|
|
10
|
+
/** Whether retrying can succeed. Defaults by code; see `RETRYABLE_BY_DEFAULT`. */
|
|
11
|
+
retryable?: boolean | undefined;
|
|
12
|
+
/** @deprecated Use `retryable`; accepted as its alias. */
|
|
13
|
+
recoverable?: boolean | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* The code the layer underneath reported — an rn-auth `AuthErrorCode`, or the
|
|
16
|
+
* gateway's own code. Kept so a screen can say *why* rather than only *what*.
|
|
17
|
+
*/
|
|
18
|
+
cause?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
/** The package's error; an `SdkError` (`@chipmobilesdk/rn-core`) with `pkg: 'rn-ai'`. */
|
|
21
|
+
export declare class AiError extends SdkError<AiErrorCode> {
|
|
22
|
+
readonly retryAfterSeconds?: number | undefined;
|
|
23
|
+
/** The underlying code, when one layer down had a name for the failure. */
|
|
24
|
+
readonly cause?: string | undefined;
|
|
25
|
+
constructor(code: AiErrorCode, message: string, options?: AiErrorOptions);
|
|
26
|
+
/** @deprecated Use `retryable`, the name every SDK package shares. */
|
|
27
|
+
get recoverable(): boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function isAiError(value: unknown): value is AiError;
|
|
30
|
+
/** `Retry-After` in seconds, from either form the header may take. */
|
|
31
|
+
export declare function parseRetryAfter(value: string | null | undefined): number | undefined;
|
|
32
|
+
export interface HttpErrorContext {
|
|
33
|
+
/** The response headers, when the transport can read them. */
|
|
34
|
+
getHeader?: (name: string) => string | null | undefined;
|
|
35
|
+
}
|
|
36
|
+
/** Map a gateway error response (status + JSON body) to a typed AiError. */
|
|
37
|
+
export declare function errorFromHttp(status: number, bodyText: string, context?: HttpErrorContext): AiError;
|
|
38
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/diagnostics/errors.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,EAAE,QAAQ,EAAkB,MAAM,wBAAwB,CAAC;AAQlE,MAAM,MAAM,WAAW,GACpB,cAAc;AAChB,+DAA+D;GAC7D,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,aAAa,GACb,cAAc,GACd,eAAe,GACf,mBAAmB,GACnB,sBAAsB,GACtB,oBAAoB;AACtB,yFAAyF;GACvF,SAAS,GACT,gBAAgB,GAChB,UAAU,CAAC;AAEd,MAAM,WAAW,cAAc;IAC9B,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,kFAAkF;IAClF,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AASD,yFAAyF;AACzF,qBAAa,OAAQ,SAAQ,QAAQ,CAAC,WAAW,CAAC;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;gBAExB,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;IAU5E,sEAAsE;IACtE,IAAI,WAAW,IAAI,OAAO,CAEzB;CACD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAE1D;AA0BD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAapF;AAED,MAAM,WAAW,gBAAgB;IAChC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACxD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC5B,OAAO,CA4BT"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AiError } from './errors';
|
|
2
|
+
export declare const aiMessageSet: import("@chipmobilesdk/rn-core").MessageSet<{
|
|
3
|
+
'ai.state.loading': string;
|
|
4
|
+
'ai.state.streaming': string;
|
|
5
|
+
'ai.input.placeholder': string;
|
|
6
|
+
'ai.action.send': string;
|
|
7
|
+
'ai.action.cancel': string;
|
|
8
|
+
'ai.action.retry': string;
|
|
9
|
+
'ai.action.retryAt': string;
|
|
10
|
+
'ai.quota.remaining': string;
|
|
11
|
+
'ai.error.rateLimited': string;
|
|
12
|
+
'ai.error.premiumRequired': string;
|
|
13
|
+
'ai.error.blocked': string;
|
|
14
|
+
'ai.error.payloadTooLarge': string;
|
|
15
|
+
'ai.error.modality': string;
|
|
16
|
+
'ai.error.busy': string;
|
|
17
|
+
'ai.error.unavailable': string;
|
|
18
|
+
'ai.error.signIn': string;
|
|
19
|
+
'ai.error.offline': string;
|
|
20
|
+
'ai.error.generic': string;
|
|
21
|
+
}, Record<never, string>>;
|
|
22
|
+
export declare const aiMessages: Readonly<{
|
|
23
|
+
'ai.state.loading': string;
|
|
24
|
+
'ai.state.streaming': string;
|
|
25
|
+
'ai.input.placeholder': string;
|
|
26
|
+
'ai.action.send': string;
|
|
27
|
+
'ai.action.cancel': string;
|
|
28
|
+
'ai.action.retry': string;
|
|
29
|
+
'ai.action.retryAt': string;
|
|
30
|
+
'ai.quota.remaining': string;
|
|
31
|
+
'ai.error.rateLimited': string;
|
|
32
|
+
'ai.error.premiumRequired': string;
|
|
33
|
+
'ai.error.blocked': string;
|
|
34
|
+
'ai.error.payloadTooLarge': string;
|
|
35
|
+
'ai.error.modality': string;
|
|
36
|
+
'ai.error.busy': string;
|
|
37
|
+
'ai.error.unavailable': string;
|
|
38
|
+
'ai.error.signIn': string;
|
|
39
|
+
'ai.error.offline': string;
|
|
40
|
+
'ai.error.generic': string;
|
|
41
|
+
} & Record<never, string>>;
|
|
42
|
+
export type AiMessageKey = keyof typeof aiMessages;
|
|
43
|
+
export declare function aiMessage(key: AiMessageKey): string;
|
|
44
|
+
/** The message key to show a user for an error. */
|
|
45
|
+
export declare function messageKeyForError(error: AiError): AiMessageKey;
|
|
46
|
+
//# sourceMappingURL=messageKeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messageKeys.d.ts","sourceRoot":"","sources":["../../../../src/diagnostics/messageKeys.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;yBAsBvB,CAAC;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;0BAAwB,CAAC;AAEhD,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,UAAU,CAAC;AAEnD,wBAAgB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAEnD;AAsBD,mDAAmD;AACnD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAE/D"}
|