@alia.onl/sdk 7.1.1 → 7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alia.onl/sdk",
3
- "version": "7.1.1",
3
+ "version": "7.2.1",
4
4
  "description": "Alia AI chat SDK — reusable chat UI, voice, and streaming components for Oxy apps",
5
5
  "main": "src/index.ts",
6
6
  "react-native": "src/index.ts",
@@ -8,6 +8,7 @@
8
8
  "types": "src/index.ts",
9
9
  "exports": {
10
10
  ".": "./src/index.ts",
11
+ "./content": "./src/lib/content-utils.ts",
11
12
  "./voice": "./src/voice.ts",
12
13
  "./package.json": "./package.json"
13
14
  },
@@ -44,8 +45,8 @@
44
45
  "peerDependencies": {
45
46
  "react": "^19.2.3",
46
47
  "react-native": "^0.86.0",
47
- "@oxyhq/core": "^23.2.1",
48
- "@oxyhq/services": "^30.2.5",
48
+ "@oxyhq/core": "23.3.1",
49
+ "@oxyhq/services": "31.0.1",
49
50
  "@react-native-async-storage/async-storage": "^2.2.0",
50
51
  "socket.io-client": "^4.8.3",
51
52
  "expo-font": "^57.0.0",
@@ -28,7 +28,7 @@ import type { VoiceSessionComponent } from '../types';
28
28
  export interface AliaChatScreenProps {
29
29
  /** App context injected into system prompt */
30
30
  clientContext?: string;
31
- /** Alia model. Checked against `GET /catalogue`; omitted, the build's preference is used. */
31
+ /** Kaana routing profile. Checked against `GET /catalogue`; omitted, the build's preference is used. */
32
32
  model?: string;
33
33
  /** API URL override */
34
34
  apiUrl?: string;
@@ -45,7 +45,7 @@ const SPRING_CONFIG = {
45
45
  export interface AliaChatSheetProps {
46
46
  /** App context injected into system prompt */
47
47
  clientContext?: string;
48
- /** Alia model. Checked against `GET /catalogue`; omitted, the build's preference is used. */
48
+ /** Kaana routing profile. Checked against `GET /catalogue`; omitted, the build's preference is used. */
49
49
  model?: string;
50
50
  /** API URL override */
51
51
  apiUrl?: string;
@@ -12,7 +12,14 @@ const API_URL = process.env.EXPO_PUBLIC_ALIA_API_URL ?? 'https://api.alia.onl';
12
12
  export interface UseAliaChatOptions {
13
13
  /** Alia API base URL (default: EXPO_PUBLIC_ALIA_API_URL or https://api.alia.onl) */
14
14
  apiUrl?: string;
15
- /** Alia model or routing profile to use. */
15
+ /**
16
+ * Kaana routing profile to use.
17
+ *
18
+ * Optional, and checked against `GET /catalogue` before a request carries it:
19
+ * an identifier the server no longer offers is replaced rather than sent, so a
20
+ * retirement does not turn into a 400 inside a consumer's app. Omitted, the
21
+ * build's `PREFERRED_CHAT_MODEL_ID` is what gets checked.
22
+ */
16
23
  model?: string;
17
24
  /** App context injected as system message so Alia knows which app the user is in. */
18
25
  clientContext?: string;
@@ -3,7 +3,7 @@
3
3
  * workstream 5).
4
4
  *
5
5
  * Every surface used to hardcode an `alia-*` identifier as its default —
6
- * `useAliaChat` sent `alia-v1`, `useTTS` and `useVoiceRoom` sent `alia-v1-voice`
6
+ * `useAliaChat` sent `route:auto`, `useTTS` and `useVoiceRoom` sent `route:voice`
7
7
  * — which meant a retired identifier became a 400 in a consumer's app with
8
8
  * nothing the consumer could do about it, since the string was baked into the
9
9
  * package they installed. This module is how the SDK asks the server what it
@@ -200,6 +200,7 @@ export async function resolveModelId(
200
200
  accessToken?: string,
201
201
  preferredId?: string,
202
202
  ): Promise<string> {
203
+ if (requestedId.startsWith('mode:')) return requestedId;
203
204
  try {
204
205
  const entries = await fetchCatalogue(apiUrl, accessToken);
205
206
  return resolveSelection(requestedId, entries, preferredId).effectiveId;
package/src/lib/config.ts CHANGED
@@ -11,12 +11,11 @@
11
11
  *
12
12
  * Overridable per build so a consumer is not stranded on a retired identifier
13
13
  * until the SDK ships a new version, which is the failure the hardcoded
14
- * `'alia-v1'` inside `useAliaChat` used to guarantee.
14
+ * `'route:auto'` inside `useAliaChat` used to guarantee.
15
15
  */
16
16
 
17
17
  /** What a chat request asks for when the caller names no model. Checked against the catalogue. */
18
- export const PREFERRED_CHAT_MODEL_ID =
19
- process.env.EXPO_PUBLIC_ALIA_DEFAULT_MODEL ?? 'profile:v1';
18
+ export const PREFERRED_CHAT_MODEL_ID = 'mode:auto';
20
19
 
21
20
  /**
22
21
  * What speech synthesis and the voice session ask for.
@@ -34,5 +33,4 @@ export const PREFERRED_CHAT_MODEL_ID =
34
33
  * Resolving it properly needs a catalogue that describes voice capability as a
35
34
  * first-class filter; that is workstream 5's business, not a thing to fake here.
36
35
  */
37
- export const PREFERRED_VOICE_MODEL_ID =
38
- process.env.EXPO_PUBLIC_ALIA_VOICE_MODEL ?? 'profile:v1-voice';
36
+ export const PREFERRED_VOICE_MODEL_ID = 'route:voice';
@@ -28,12 +28,28 @@ const TOOL_REGISTRY: Record<string, ToolDefinition> = {
28
28
  updateUserContext: { label: 'Updating context', category: 'memory' },
29
29
  };
30
30
 
31
+ /**
32
+ * `Object.hasOwn`, not a bare index, in all three lookups below.
33
+ *
34
+ * Every key here comes off the wire — a tool name the server chose, a research
35
+ * phase the server chose — and these are plain object literals, so
36
+ * `REGISTRY['constructor']` is `Object.prototype`'s and not a miss.
37
+ * `getResearchActiveLabel('constructor')` returned that FUNCTION, which reaches
38
+ * a caption as `[object Function]`; the two tool lookups happened to survive
39
+ * only because `?.label` on a function is `undefined`, which is luck rather
40
+ * than a guard. The API states the same rule for its own lookups
41
+ * (`prototype-keyed-lookups.test.ts`).
42
+ */
43
+ function lookup<T>(table: Record<string, T>, key: string): T | undefined {
44
+ return Object.hasOwn(table, key) ? table[key] : undefined;
45
+ }
46
+
31
47
  export function getToolLabel(toolName: string): string {
32
- return TOOL_REGISTRY[toolName]?.label || toolName;
48
+ return lookup(TOOL_REGISTRY, toolName)?.label || toolName;
33
49
  }
34
50
 
35
51
  export function getToolActiveLabel(toolName: string): string | undefined {
36
- const label = TOOL_REGISTRY[toolName]?.label;
52
+ const label = lookup(TOOL_REGISTRY, toolName)?.label;
37
53
  if (!label) return undefined;
38
54
  return label + '...';
39
55
  }
@@ -49,7 +65,7 @@ const RESEARCH_ACTIVE_LABELS: Record<string, string> = {
49
65
  };
50
66
 
51
67
  export function getResearchActiveLabel(phase: string): string | undefined {
52
- return RESEARCH_ACTIVE_LABELS[phase];
68
+ return lookup(RESEARCH_ACTIVE_LABELS, phase);
53
69
  }
54
70
 
55
71
  export { TOOL_REGISTRY };
package/src/lib/utils.ts CHANGED
@@ -17,9 +17,19 @@ export function errorMessage(err: unknown, fallback = 'Something went wrong'): s
17
17
  }
18
18
 
19
19
  export function formatFileSize(bytes: number): string {
20
- if (bytes === 0) return '0 B';
20
+ if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';
21
21
  const k = 1024;
22
- const sizes = ['B', 'KB', 'MB', 'GB'];
23
- const i = Math.floor(Math.log(bytes) / Math.log(k));
24
- return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
22
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
23
+ /**
24
+ * Clamped to the unit table.
25
+ *
26
+ * `Math.floor(Math.log(bytes) / Math.log(k))` is unbounded at both ends, and
27
+ * `sizes[i]` is `undefined` outside it — so a file of a terabyte or more read
28
+ * "1 undefined", and any size below one byte (a fractional value, which
29
+ * `attachment.size` can be) took `log` of a number below 1, giving `i = -1`
30
+ * and the same undefined unit. Negative and non-finite inputs went further:
31
+ * `Math.log` of them is `NaN`, and `sizes[NaN]` is undefined too.
32
+ */
33
+ const i = Math.min(sizes.length - 1, Math.max(0, Math.floor(Math.log(bytes) / Math.log(k))));
34
+ return `${String(Math.round((bytes / Math.pow(k, i)) * 100) / 100)} ${sizes[i]}`;
25
35
  }