@alia.onl/sdk 22.1.1 → 22.1.2

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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # @alia.onl/sdk
2
2
 
3
+ ## 22.1.2
4
+
5
+ - **Every entry type-checks under `noUncheckedIndexedAccess`.** The SDK ships source, so a
6
+ consumer compiling with `"noUncheckedIndexedAccess": true` (Astro) type-checked the SDK under
7
+ it too and got errors from indexed reads in the runtime, thread, citation and catalogue-tool
8
+ modules (27 from `@alia.onl/sdk/runtime` alone). Each read is now narrowed where the index is
9
+ known to be in range, with a loop over the values where that is simpler. Behaviour is unchanged.
10
+ - `check:entry-types` compiles every entry with `noUncheckedIndexedAccess` on, so CI keeps it so.
11
+
3
12
  ## 22.1.1
4
13
 
5
14
  - A delayed Stop acknowledgement cannot idle a newer turn, replace its sidebar
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alia.onl/sdk",
3
- "version": "22.1.1",
3
+ "version": "22.1.2",
4
4
  "description": "Alia AI chat SDK — the conversation runtime, chat UI, voice calls and dictation for Oxy apps",
5
5
  "main": "src/index.ts",
6
6
  "react-native": "src/index.ts",
@@ -554,7 +554,7 @@ export const AmbientField = memo(function AmbientField({
554
554
  key={config.w}
555
555
  config={config}
556
556
  index={index}
557
- color={palette[index]}
557
+ color={palette[index] as string}
558
558
  vw={vw}
559
559
  vh={vh}
560
560
  vmax={vmax}
@@ -121,7 +121,7 @@ function parseBlockData(type: string, match: RegExpExecArray): any {
121
121
  switch (type) {
122
122
  case 'COMPACTLIST': {
123
123
  const title = match[1];
124
- const itemsText = match[2];
124
+ const itemsText = match[2] ?? '';
125
125
  const items = itemsText
126
126
  .split('\n')
127
127
  .filter((line) => line.trim().startsWith('-'))
@@ -140,26 +140,26 @@ function parseBlockData(type: string, match: RegExpExecArray): any {
140
140
  return {
141
141
  type: match[1],
142
142
  title: match[2],
143
- content: match[3].trim(),
143
+ content: (match[3] ?? '').trim(),
144
144
  };
145
145
  }
146
146
  case 'COMPARISON': {
147
147
  const title = match[1];
148
- const content = match[2];
148
+ const content = match[2] ?? '';
149
149
  const leftMatch = content.match(/LEFT:\s*({.*?})/s);
150
150
  const rightMatch = content.match(/RIGHT:\s*({.*?})/s);
151
151
  const conclusionMatch = content.match(/CONCLUSION:\s*(.*?)$/s);
152
152
 
153
153
  return {
154
154
  title,
155
- left: leftMatch ? JSON.parse(leftMatch[1]) : {},
156
- right: rightMatch ? JSON.parse(rightMatch[1]) : {},
157
- conclusion: conclusionMatch ? conclusionMatch[1].trim() : undefined,
155
+ left: leftMatch ? JSON.parse(leftMatch[1] ?? '') : {},
156
+ right: rightMatch ? JSON.parse(rightMatch[1] ?? '') : {},
157
+ conclusion: conclusionMatch ? (conclusionMatch[1] ?? '').trim() : undefined,
158
158
  };
159
159
  }
160
160
  case 'TIMELINE': {
161
161
  const title = match[1];
162
- const itemsText = match[2];
162
+ const itemsText = match[2] ?? '';
163
163
  const items = itemsText
164
164
  .split('\n')
165
165
  .filter((line) => line.trim().startsWith('-'))
@@ -183,7 +183,7 @@ function parseBlockData(type: string, match: RegExpExecArray): any {
183
183
  }
184
184
  case 'CREDIBILITY': {
185
185
  return {
186
- level: parseInt(match[1], 10),
186
+ level: parseInt(match[1] ?? '', 10),
187
187
  source: match[2],
188
188
  };
189
189
  }
@@ -30,7 +30,7 @@ export function ChartRenderer({ data, title }: ChartRendererProps) {
30
30
  labels.map((label, i) => ({ label, value: values[i] || 0 }));
31
31
 
32
32
  if (chartType === 'line' && datasets.length === 1) {
33
- const series = datasets[0];
33
+ const series = datasets[0] as (typeof datasets)[number];
34
34
  return (
35
35
  <LineChartCard
36
36
  title={series.label || title}
@@ -129,7 +129,7 @@ function StepsTab({ steps, lifecycle }: { steps: ThoughtStep[]; lifecycle: TurnL
129
129
  return <EmptyState variant="compact" description={t('thought.noSteps')} />;
130
130
  }
131
131
 
132
- const last = steps[steps.length - 1];
132
+ const last = steps[steps.length - 1] as (typeof steps)[number];
133
133
  const tail = live && (last.type === 'thinking' || last.type === 'writing') ? last : null;
134
134
  const rows = tail === null ? steps : steps.slice(0, -1);
135
135
 
@@ -213,7 +213,7 @@ export const AliaThread = memo(function AliaThread({
213
213
  if (index !== lastReplyIndex || index !== rows.length - 1) return false;
214
214
  if (index < history.length || failedTurn?.anchorMessageId === message.id) return false;
215
215
  for (let i = index - 1; i >= history.length; i--) {
216
- if (rows[i].role === 'user') return true;
216
+ if (rows[i]?.role === 'user') return true;
217
217
  }
218
218
  return false;
219
219
  };
@@ -223,7 +223,7 @@ export const AliaThread = memo(function AliaThread({
223
223
  * an old message belongs to the stretch that ended, not to the one on screen.
224
224
  */
225
225
  const conversationOf = (index: number): string | undefined =>
226
- index < history.length ? history[index].conversationId : conversationId;
226
+ index < history.length ? history[index]?.conversationId : conversationId;
227
227
 
228
228
  // ── Which rows are mounted, and the scroll that goes with them ──
229
229
  /** The row a cursor jump was aimed at, as an index into what is shown, or -1. */
@@ -169,7 +169,7 @@ export function useTimelineWindow({
169
169
  anchor: kept,
170
170
  offset: lastOffset.current ?? 0,
171
171
  atBottom: atBottom.current,
172
- probeId: rows[first],
172
+ probeId: rows[first] as string,
173
173
  });
174
174
  };
175
175
  }, [scrollKey]);
@@ -71,8 +71,8 @@ export function levelFromFrames(frames: readonly number[]): number {
71
71
  if (frames.length === 0) return 0;
72
72
 
73
73
  let sumSquares = 0;
74
- for (let index = 0; index < frames.length; index += 1) {
75
- sumSquares += frames[index] * frames[index];
74
+ for (const frame of frames) {
75
+ sumSquares += frame * frame;
76
76
  }
77
77
  const rms = Math.sqrt(sumSquares / frames.length);
78
78
 
@@ -12,7 +12,7 @@ const CANONICAL_TOOL = /^(?:oxy|self)_([a-z][a-z0-9-]{0,63})__([A-Za-z0-9_-]+)$/
12
12
  /** The app and tool of a canonical catalogue tool name, or `null` for any other name. */
13
13
  export function parseCatalogueTool(toolName: string): { app: string; tool: string } | null {
14
14
  const match = CANONICAL_TOOL.exec(toolName);
15
- return match ? { app: match[1], tool: match[2] } : null;
15
+ return match ? { app: match[1] ?? '', tool: match[2] ?? '' } : null;
16
16
  }
17
17
 
18
18
  /** The renderer key of a tool name (`<app>:<tool>`), or `null` when it is not a catalogue tool. */
@@ -180,7 +180,7 @@ export function splitReferences(
180
180
  const m = REFERENCE_LINE_RE.exec(line);
181
181
  if (m) {
182
182
  flush();
183
- current = { id: Number(m[1]), rest: m[2] };
183
+ current = { id: Number(m[1]), rest: m[2] ?? '' };
184
184
  } else if (current && line.trim().length > 0) {
185
185
  // A legacy entry's URL sits on the indented line after the title.
186
186
  current.rest += ` ${line.trim()}`;
@@ -275,13 +275,14 @@ function upsertOnTop(
275
275
  if (moveExisting) {
276
276
  // Remove the conversation from its current position (if it is in any page)
277
277
  for (let i = 0; i < pages.length; i++) {
278
- const existingIndex = pages[i].conversations.findIndex((c) => c.id === row.id);
278
+ const page = pages[i] as ConversationsPage;
279
+ const existingIndex = page.conversations.findIndex((c) => c.id === row.id);
279
280
  if (existingIndex >= 0) {
280
281
  pages[i] = {
281
- ...pages[i],
282
+ ...page,
282
283
  conversations: [
283
- ...pages[i].conversations.slice(0, existingIndex),
284
- ...pages[i].conversations.slice(existingIndex + 1),
284
+ ...page.conversations.slice(0, existingIndex),
285
+ ...page.conversations.slice(existingIndex + 1),
285
286
  ],
286
287
  };
287
288
  break;
@@ -347,7 +348,10 @@ export function useSaveConversation() {
347
348
  id,
348
349
  title: offlineTitle,
349
350
  lastMessage,
350
- createdAt: existingIndex >= 0 ? conversations[existingIndex].createdAt : new Date(),
351
+ createdAt:
352
+ existingIndex >= 0
353
+ ? (conversations[existingIndex] as Conversation).createdAt
354
+ : new Date(),
351
355
  updatedAt: new Date(),
352
356
  messages,
353
357
  };
@@ -102,7 +102,7 @@ export function normalizeConversationMessages(messages: readonly Message[]): Mes
102
102
  messages = messages.filter((message) => message.role !== 'system');
103
103
 
104
104
  for (let index = 0; index < messages.length; index += 1) {
105
- const current = messages[index];
105
+ const current = messages[index] as Message;
106
106
  const placeholder = messages[index + 1];
107
107
  const duplicate = messages[index + 2];
108
108
 
@@ -718,8 +718,9 @@ export function turnTiming(
718
718
  const index = messages.findIndex((m) => m.id === message.id);
719
719
  let sendStamp: number | null = null;
720
720
  for (let i = index - 1; i >= 0; i -= 1) {
721
- if (messages[i].role === 'user') {
722
- sendStamp = stampToMs(messages[i].createdAt);
721
+ const earlier = messages[i];
722
+ if (earlier?.role === 'user') {
723
+ sendStamp = stampToMs(earlier.createdAt);
723
724
  break;
724
725
  }
725
726
  }
@@ -95,7 +95,7 @@ export function threadHistory(
95
95
  ): ThreadMessage[] {
96
96
  const history: ThreadMessage[] = [];
97
97
  for (let page = pages.length - 1; page >= 0; page -= 1) {
98
- for (const message of pages[page].messages) {
98
+ for (const message of pages[page]?.messages ?? []) {
99
99
  if (message.conversationId === activeConversationId) continue;
100
100
  history.push({ ...message, id: message.id ?? message.cursor });
101
101
  }
@@ -76,7 +76,7 @@ function tailStart(count: number): number {
76
76
  /** The anchor that keeps exactly the rows mounted now, from the row at `start`. */
77
77
  export function pinAnchor(ids: readonly string[], start: number): TimelineAnchor {
78
78
  if (start <= 0 || ids.length === 0) return TOP;
79
- return { kind: 'row', id: ids[start] };
79
+ return { kind: 'row', id: ids[start] as string };
80
80
  }
81
81
 
82
82
  /**
@@ -124,7 +124,7 @@ export function sameTimelineShape(previous: readonly Shape[], next: readonly Sha
124
124
  if (previous === next) return true;
125
125
  if (previous.length !== next.length) return false;
126
126
  for (let i = 0; i < next.length; i += 1) {
127
- if (!sameShape(previous[i], next[i])) return false;
127
+ if (!sameShape(previous[i] as Shape, next[i] as Shape)) return false;
128
128
  }
129
129
  return true;
130
130
  }
@@ -125,8 +125,8 @@ function toPoints(series: readonly PricePoint[], intraday: boolean, locale: stri
125
125
 
126
126
  /** First-to-last change as a ratio, or none for a run that started at nothing. */
127
127
  function runDelta(series: readonly PricePoint[]): number | undefined {
128
- const first = series[0][1];
129
- const last = series[series.length - 1][1];
128
+ const first = (series[0] as PricePoint)[1];
129
+ const last = (series[series.length - 1] as PricePoint)[1];
130
130
  return first === 0 ? undefined : (last - first) / first;
131
131
  }
132
132
 
@@ -189,7 +189,7 @@ export function marketChart(data: MarketCardData, t: Translate, locale: string):
189
189
  id,
190
190
  label: t(`market.range.${id}`),
191
191
  data: toPoints(run, id === '1D', locale),
192
- headline: quoted(data.price) ? data.price : run[run.length - 1][1],
192
+ headline: quoted(data.price) ? data.price : (run[run.length - 1] as PricePoint)[1],
193
193
  delta: id === '1D' && quoted(data.changePct) ? data.changePct / 100 : runDelta(run),
194
194
  });
195
195
  }
@@ -205,7 +205,7 @@ export function marketChart(data: MarketCardData, t: Translate, locale: string):
205
205
  if (intraday.length >= 2) {
206
206
  notes.push(
207
207
  [
208
- `${t('market.open')} ${format(intraday[0])}`,
208
+ `${t('market.open')} ${format(intraday[0] as number)}`,
209
209
  `${t('market.dayHigh')} ${format(Math.max(...intraday))}`,
210
210
  `${t('market.dayLow')} ${format(Math.min(...intraday))}`,
211
211
  ].join(' · '),
@@ -220,7 +220,9 @@ export function marketChart(data: MarketCardData, t: Translate, locale: string):
220
220
  return {
221
221
  title: `${data.name} · ${data.symbol}`,
222
222
  ranges,
223
- defaultRange: ranges.some((r) => r.id === '1D') ? '1D' : ranges[0].id,
223
+ defaultRange: ranges.some((r) => r.id === '1D')
224
+ ? '1D'
225
+ : (ranges[0] as (typeof ranges)[number]).id,
224
226
  format,
225
227
  formatAxisValue: (value) => formatAxis(value, locale),
226
228
  notes,
@@ -275,7 +277,7 @@ export function faircoinChart(
275
277
  id,
276
278
  label: t(`faircoin.range.${id}`),
277
279
  data: toPoints(run, id === '24h', locale),
278
- headline: quoted(data.price) ? data.price : run[run.length - 1][1],
280
+ headline: quoted(data.price) ? data.price : (run[run.length - 1] as PricePoint)[1],
279
281
  delta: id === '24h' && quoted(data.changePct) ? data.changePct / 100 : runDelta(run),
280
282
  });
281
283
  }
@@ -331,7 +333,9 @@ export function faircoinChart(
331
333
  chart: {
332
334
  title: `${t('faircoin.name')} · ${t('faircoin.symbol')}`,
333
335
  ranges,
334
- defaultRange: ranges.some((r) => r.id === '24h') ? '24h' : ranges[0].id,
336
+ defaultRange: ranges.some((r) => r.id === '24h')
337
+ ? '24h'
338
+ : (ranges[0] as (typeof ranges)[number]).id,
335
339
  format,
336
340
  formatAxisValue: (value) => formatAxis(value, locale),
337
341
  notes: [],
@@ -897,7 +897,7 @@ export function useConversationStream({
897
897
  const idx = invocations.findIndex((t) => t.toolCallId === tool_call_id);
898
898
  if (idx >= 0) {
899
899
  invocations[idx] = {
900
- ...invocations[idx],
900
+ ...(invocations[idx] as ToolInvocation),
901
901
  state: 'result',
902
902
  result: output,
903
903
  };
@@ -1254,7 +1254,11 @@ export function useConversationStream({
1254
1254
  const idx = invocations.findIndex((t) => t.toolCallId === tool_call_id);
1255
1255
 
1256
1256
  if (idx >= 0) {
1257
- invocations[idx] = { ...invocations[idx], state: 'result', result: output };
1257
+ invocations[idx] = {
1258
+ ...(invocations[idx] as ToolInvocation),
1259
+ state: 'result',
1260
+ result: output,
1261
+ };
1258
1262
  } else {
1259
1263
  invocations.push({
1260
1264
  toolCallId: tool_call_id,
@@ -435,7 +435,8 @@ export function useConversationThread({
435
435
  (assistantMessageId: string): Message | undefined => {
436
436
  const idx = messages.findIndex((msg) => msg.id === assistantMessageId);
437
437
  for (let i = idx - 1; i >= 0; i--) {
438
- if (messages[i].role === 'user') return messages[i];
438
+ const earlier = messages[i];
439
+ if (earlier?.role === 'user') return earlier;
439
440
  }
440
441
  return undefined;
441
442
  },