@alia.onl/sdk 11.1.0 → 13.0.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/package.json +5 -4
  3. package/src/components/AliaAvatar.tsx +16 -20
  4. package/src/components/AliaChatContent.tsx +234 -96
  5. package/src/components/AliaChatHeader.tsx +102 -76
  6. package/src/components/AliaChatMessageList.tsx +174 -134
  7. package/src/components/AliaChatScreen.tsx +45 -23
  8. package/src/components/AliaChatSheet.tsx +151 -50
  9. package/src/components/AliaWelcomeMessage.tsx +26 -53
  10. package/src/components/AmbientField.tsx +19 -16
  11. package/src/components/ComposerSuggestions.tsx +45 -0
  12. package/src/components/IdentityMark.tsx +3 -1
  13. package/src/components/Markdown.tsx +18 -24
  14. package/src/components/QuestionCard.tsx +35 -33
  15. package/src/components/ThinkingBlock.tsx +9 -13
  16. package/src/components/VoiceModeIcon.tsx +15 -7
  17. package/src/components/voice/VoiceControls.tsx +17 -9
  18. package/src/hooks/useAliaChat.ts +124 -5
  19. package/src/hooks/useComposerSuggestions.ts +84 -0
  20. package/src/index.ts +10 -10
  21. package/src/lib/agent-character.ts +28 -0
  22. package/src/lib/chat-stream.ts +25 -3
  23. package/src/lib/citations.ts +62 -10
  24. package/src/lib/delegation.ts +34 -0
  25. package/src/lib/domain.ts +12 -0
  26. package/src/lib/flights.ts +24 -0
  27. package/src/lib/greeting.ts +15 -0
  28. package/src/lib/image-data-url.ts +26 -5
  29. package/src/lib/labels.tsx +10 -2
  30. package/src/lib/questions.ts +15 -1
  31. package/src/lib/suggestions.ts +53 -0
  32. package/src/lib/task-labels.ts +7 -39
  33. package/src/lib/use-after-delay.ts +19 -0
  34. package/src/lib/work-log.ts +3 -9
  35. package/src/tools.ts +8 -1
  36. package/src/types.ts +6 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,139 @@
1
1
  # @alia.onl/sdk
2
2
 
3
+ ## 13.0.0
4
+
5
+ Fixes found by driving the sheet end to end (the sheet shows plans, links citations, nests lists):
6
+
7
+ - **A plan is drawn.** `plan_preview` was parsed but the sheet passed no handlers, so the card
8
+ never showed. `useAliaChat` now returns `approvePlan` / `rejectPlan` (approve collapses the
9
+ card to "approved"; reject collapses it and stops the turn) and `AliaChatContent` uses them
10
+ unless the host passes its own.
11
+ - **Citations link.** `[n]` markers in a reply link to their sources (`linkifyCitations`,
12
+ `normalizeCitationMarkers`, `citationLabel` are exported from `@alia.onl/sdk/tools`; the app
13
+ re-exports them instead of keeping a copy).
14
+ - **Nested lists** draw under their parent instead of inline beside it.
15
+ - A finished research step reads "Researched", not "Researching".
16
+ - A turn that ends at a question card with no sentence before it counts as answered.
17
+
18
+ - **BREAKING: an agent is drawn with the look the server stores for it.** `agentCharacter(id)` (a
19
+ look hashed from the id) is removed; `readAgentCharacter(value)` parses a stored character
20
+ (Bloom's `parseAvatarCharacter`) and falls back on `DEFAULT_AGENT_CHARACTER`. The `alia.agent`
21
+ event carries `agentCharacter`, and `agentInfo` has `character`. `AliaChatAgent` has `character`;
22
+ `AliaChatSheet` / `AliaChatScreen` take `agents` (the host's directory) so a delegation's
23
+ thinking avatar is the agent's own before its answer arrives. Needs a server that sends
24
+ `agentCharacter`; release this SDK first, since the stream parser rejects unknown keys.
25
+ - **The one who answers thinks with its own avatar, and it is the same avatar that settles under
26
+ the reply** (Bloom's `AgentReplyIdentity`, as in the multi-agent chat). While Alia works, her
27
+ avatar is the indicator, large with "Thinking…", where the `AgentThinking` line was; when her
28
+ text starts it shrinks under it with her name. A call to an agent (`delegateToAgent` /
29
+ `askAgent`, its `agentId` and `agentName` or `agent` arguments) opens the agent's message at
30
+ once, empty and thinking, and its answer fills that same message, so the avatar never remounts;
31
+ an agent that never answers leaves no message. Alia's reply now carries her identity row, as the
32
+ agents' do.
33
+ The reasoning is part of that same component (`AgentReplyIdentity`'s `reasoning`): while the
34
+ turn thinks, "Thinking… ⌃" folds it under the avatar's row, and once the reply starts it is the
35
+ closed "Thought for N seconds" block above it (`ThinkingBlock` draws nothing while it streams, so
36
+ there is one thinking indicator, not two).
37
+ - **No jumps of height, and no flash of the wrong thinker.** A reply, a new row, the reasoning and
38
+ a thinking agent's avatar open and close with their height eased (Bloom's `Collapsible`, now
39
+ with `appear`) instead of popping. Alia is shown thinking only once she has for a moment, so a
40
+ turn she hands to an agent at once shows the agent thinking, not Alia for an instant first.
41
+ - **Bubbles are equal on every side as the eye reads them.** An agent's bubble sets its top and
42
+ bottom padding from the reply's text metrics (`AgentReplyBubble`'s `text`, 16 on 28 here), so
43
+ the gap from the edge to the text is the same above, below and at the sides. Nothing is cut:
44
+ an open `Collapsible` no longer clips.
45
+ - **The greeting's avatar flies up into the header's profile** as the conversation begins
46
+ (Bloom's `avatar-flight`: `useAvatarFlights`, `AvatarAnchor`, `AvatarFlightLayer`), across the
47
+ main and conversation sheets. `AgentProfile`'s new `avatarHidden` keeps the header's avatar
48
+ waiting for it. Needs a Bloom with `avatar-flight` (after 10.3).
49
+ - **`AliaChatSheet` opens the conversation in a second sheet stacked over the main one.** The
50
+ main sheet stays on the greeting, the suggestions and the composer; the first turn (typed or a
51
+ suggestion) opens a fresh conversation sheet on top, whose back button (and the menu's Clear)
52
+ closes just that sheet, back to the main screen. A phone gets sheets flush with the screen
53
+ edges, with the composer clearing the home indicator; from tablet width (768 px) they float.
54
+ `AliaChatContent` gains `onStart` (hand an empty chat's first turn to the host) and
55
+ `initialTurn` (a turn sent once on mount).
56
+ - **The empty chat looks and behaves like the Alia app's, from the same code.** The avatar sits
57
+ beside the greeting (`AliaWelcomeMessage`, now just the greeting: always side by side, no
58
+ `hideMark`, no suggestions) and the header shows Alia's profile only once there is a
59
+ conversation. The suggestions are one-line rows **over the composer** (`ComposerSuggestions`),
60
+ and from two typed characters they become matches with the typed part highlighted, arrows /
61
+ Enter / Escape through the composer's `onKeyPress`. The app now draws its greeting and its
62
+ suggestions with these same components and only supplies its API's data.
63
+ - **Several agents in one turn.** A delegated agent's answer (`alia.agent`) is now its own
64
+ message with its name and avatar, placed before Alia's reply as the app places it, so a turn
65
+ with Lumi, Atlas and Sol shows three speakers. Before, every answer was merged into one message
66
+ under the last agent's name. Alia's reply is dropped when she said nothing after handing over.
67
+ - **A delegated agent shows its 3D avatar.** The speaker line of an agent's message is Bloom's
68
+ `AgentAvatar`, not an image (an agent's account has none): the character comes from the agent's
69
+ id (`agentCharacter(id)`, exported), so the same agent looks the same everywhere and two agents
70
+ in a turn are told apart. The app draws its agents' messages with the same avatar.
71
+ - **Agents are bubbles, and the header holds the team.** As in Bloom's multi-agent chat, a
72
+ delegated agent's reply is a tinted bubble with its avatar and name beneath it. Once agents have
73
+ answered, the header profile stacks Alia with up to two of them and names them together
74
+ ("Alia + Lumi + Atlas"). `headerLeading` / `actions` receive `agents` in their state
75
+ (`AliaChatState`, `AliaChatAgent`), and `AliaChatHeader` takes `agents`.
76
+ - **The row under every reply is Bloom's multi-agent one**: helpful, unhelpful and copy as 22px
77
+ tiles with 12px icons (read aloud is a fourth tile where the host reads), replacing the
78
+ `AiChatFeedbackRow`. New label keys `helpful` and `unhelpful`.
79
+ - **Built on Bloom's `agent-reply`** (peer `@oxy.so/bloom ^10.1.1`): replies, their identity line and
80
+ action tiles, and the header profile are Bloom's `AgentReply`, `AgentReplyBubble`,
81
+ `AgentReplyIdentity`, `AgentReplyActions` and `AgentProfile`, the pieces `MultiAgentChat` is made
82
+ of, not copies. Pressing the profile makes every avatar in it wave.
83
+ - **Questions are asked above the composer, not in the thread.** What Alia asks in her last turn
84
+ (`askUserQuestion`) docks above the composer as Bloom's `Questionnaire`, with a dismiss; typing a
85
+ reply answers just as well. The thread keeps the questions as plain lines (`AskedQuestions`).
86
+ **Breaking:** `QuestionCard` is now the docked questionnaire (`onSubmit` required, new
87
+ `onDismiss`) and no longer draws a read-only variant; the `onAnswerQuestions` prop of the message
88
+ list is gone. `pendingQuestions` joins `@alia.onl/sdk/tools`.
89
+ - **The voice bar is Bloom's voice controls.** `VoiceControls` draws Bloom's `@oxy.so/bloom/voice`
90
+ `VoiceControls` (microphone and end) under the status text, instead of `CallControls`, which is
91
+ made for a dark call stage and lost its captions on the chat's light surface.
92
+ - **The header is back, the profile, share and a menu.** Bloom's `PageHeader` with a back button at
93
+ its start, and at its end share and a three-dots menu (Bloom's `DropdownMenu`, aligned to its
94
+ button) holding Clear and the host's rows. Over the empty chat there is no bar: nothing to do
95
+ there. In the sheet, back returns to the main screen (a fresh chat) and the sheet stays open.
96
+ **Breaking:** `AliaChatHeader` / `AliaChatSheet` / `AliaChatScreen` lose `onClose`; they take
97
+ `onBack` (screen), `onShare` and `headerMenu`; the labels `close` becomes `back`, `share`,
98
+ `more`.
99
+ - **The chat follows Bloom's theme, not the system's scheme.** `AliaMarkdown` and the sheet read
100
+ the app's resolved mode: a person who chose light on a dark OS got white text on a light surface.
101
+ - **Every icon is Bloom's.** The voice button is `RiVolumeUpLine` (it was Entypo); the app's clock,
102
+ robot and connector glyphs are `RiTimeLine`, `RiRobot2Line`, `RiPlugLine` and the SVG generator
103
+ is gone; `@expo/vector-icons` is no longer a peer of the SDK.
104
+ - **Greeting.** The avatar (88px) above the text, both centred; `max-w-xs`, so it always sets in two lines; more room above than below. The Alia app draws the same.
105
+ - Peer `@oxy.so/bloom ^10.2.1` (scrollbar, pill groups, header scrim, voice controls).
106
+ - **Breaking:** `WelcomeSuggestion { id, title, description }` becomes `AliaSuggestion { id, text }`
107
+ (`text` is what is shown and what is sent). New optional props on the sheet, screen and content:
108
+ `suggestionMatches` and `onSuggestionQuery(query)`, so a host can search as the person types.
109
+ New exports: `ComposerSuggestions`, `useComposerSuggestions`, `useSuggestionQuery`,
110
+ `composerCompletions`, `Completion`, `AliaSuggestion`.
111
+
112
+ ## 12.0.0
113
+
114
+ Breaking: Bloom 10 peer; the `header` render prop replaces the breadcrumb path (`title`, `actions`)
115
+ and the mark-state context. Hosts on Bloom 9 stay on 11.1.0.
116
+
117
+ - **The `@oxy.so` peers are open-ended** above their floors (`bloom >=10.0.0`, `core >=3.0.0`,
118
+ `services >=8.0.0`). The `^10.0.0`, `^4.0.0` and `^11.0.0` caps made each new Oxy major a peer
119
+ conflict in every app until this package republished; apps always run the latest Oxy SDK.
120
+
121
+ - **`AmbientField` takes `layout="sheet"`** for a short card (the chat's sheet): the blobs are
122
+ drawn at the size of a phone screen, spread wider and shifted back to the right, cropped by the
123
+ card's edges. It is asked for, not inferred from the field's height, so a short app screen is
124
+ never reinterpreted. `AmbientField`, `AliaAvatar` and `AliaChatHeader` are memoised and the
125
+ chat body no longer repaints them on every streamed token; read-aloud and starting a call no
126
+ longer change identity per flush. `AliaAvatar` takes `portrait` (a still thumbnail, used for
127
+ the sidebar's permanent mark).
128
+ - **One `header` render prop** on `AliaChatContent`, handed `hasMessages`, `clear` and the live
129
+ avatar `markState`; the breadcrumb path (`title`, `actions`) and the mark-state context are gone.
130
+ - The profile and the screen's background are NativeWind classes with Bloom tokens
131
+ (`bg-background-full`, `group-hover/profile:…`), not JS-computed colours.
132
+ - **Bloom is a peer at `^10.0.0`** (was `^9.0.0`). Bloom 10 makes an avatar one flat
133
+ `AvatarCharacter`; `AliaAvatar` is `{ preset: 'blue_beret', accessory: 'none', color: 'orchid' }`
134
+ and no longer builds a `config`. Hosts mount `AgentAvatarProvider` as before. Hosts on Bloom 9
135
+ stay on the previous release.
136
+
3
137
  ## 11.1.0
4
138
 
5
139
  Alia can ask clarifying questions, as ChatGPT and Claude do.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alia.onl/sdk",
3
- "version": "11.1.0",
3
+ "version": "13.0.0",
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",
@@ -39,9 +39,9 @@
39
39
  "react": "^19.2.3",
40
40
  "react-native": "^0.86.0",
41
41
  "@expo/vector-icons": "^15.1.1",
42
- "@oxy.so/bloom": "^9.0.0",
43
- "@oxy.so/core": "^3.0.0 || ^4.0.0",
44
- "@oxy.so/services": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0",
42
+ "@oxy.so/bloom": ">=10.4.0",
43
+ "@oxy.so/core": ">=3.0.0",
44
+ "@oxy.so/services": ">=8.0.0",
45
45
  "@react-native-async-storage/async-storage": "^2.2.0",
46
46
  "expo-blur": "^57.0.0",
47
47
  "react-native-reanimated": "^4.5.0",
@@ -56,6 +56,7 @@
56
56
  "expo-haptics": "^57.0.0",
57
57
  "nativewind": "^5.0.0-preview.3",
58
58
  "expo-clipboard": "^57.0.0",
59
+ "expo-file-system": "^57.0.0",
59
60
  "expo-speech-recognition": "^57.1.0"
60
61
  },
61
62
  "peerDependenciesMeta": {
@@ -1,26 +1,18 @@
1
- import { AgentAvatar, type AvatarConfig, DEFAULT_CONFIG } from '@oxy.so/bloom/agent-avatar';
2
- import { useEffect, useState } from 'react';
1
+ import { AgentAvatar, type AvatarCharacter } from '@oxy.so/bloom/agent-avatar';
2
+ import { memo, useEffect, useState } from 'react';
3
3
 
4
4
  /** What Alia is doing; the avatar plays a working turn each time it starts to think or work. */
5
5
  export type AliaAvatarState = 'idle' | 'thinking' | 'working' | 'writing';
6
6
 
7
7
  /**
8
- * Alia's likeness in Bloom's 3D character engine: the six-lobed flower in orchid,
9
- * plain oval eyes, nothing on its head. The engine ids come from Bloom's catalog
10
- * (`character-shapes.ts`, `character-colors.ts`); change them here and nowhere else.
8
+ * Alia's likeness in Bloom's 3D character engine: the six-lobed flower in orchid, plain oval
9
+ * eyes, nothing on its head. It is `blue_beret` with the hat taken off and the paint changed,
10
+ * so Bloom retargets that preset's animation onto it; change it here and nowhere else.
11
11
  */
12
- const ALIA_AVATAR: AvatarConfig = {
13
- ...DEFAULT_CONFIG,
14
- character: {
15
- preset: 'blue_beret',
16
- selections: {
17
- shape: 'six_lobed_flower',
18
- color: 'orchid',
19
- eyes: 'oval',
20
- eyewear: 'none',
21
- accessory: 'none',
22
- },
23
- },
12
+ export const ALIA_AVATAR: AvatarCharacter = {
13
+ preset: 'blue_beret',
14
+ accessory: 'none',
15
+ color: 'orchid',
24
16
  };
25
17
 
26
18
  const BUSY: ReadonlySet<AliaAvatarState> = new Set(['thinking', 'working']);
@@ -34,6 +26,8 @@ export interface AliaAvatarProps {
34
26
  interactive?: boolean;
35
27
  /** Change it to replay the avatar's reaction (a wave) — for a button that wraps it. */
36
28
  reactionKey?: number;
29
+ /** A still thumbnail instead of a live 3D avatar: for small, permanent spots like a sidebar. */
30
+ portrait?: boolean;
37
31
  }
38
32
 
39
33
  /**
@@ -41,11 +35,12 @@ export interface AliaAvatarProps {
41
35
  * app must mount `AgentAvatarProvider` with the URL of the hosted `character-runtime`;
42
36
  * without it Bloom shows its own "unavailable" state.
43
37
  */
44
- export function AliaAvatar({
38
+ export const AliaAvatar = memo(function AliaAvatar({
45
39
  size,
46
40
  state = 'idle',
47
41
  interactive = false,
48
42
  reactionKey,
43
+ portrait = false,
49
44
  }: AliaAvatarProps) {
50
45
  const [workingKey, setWorkingKey] = useState(0);
51
46
  const busy = BUSY.has(state);
@@ -55,12 +50,13 @@ export function AliaAvatar({
55
50
 
56
51
  return (
57
52
  <AgentAvatar
58
- config={ALIA_AVATAR}
53
+ character={ALIA_AVATAR}
59
54
  size={size}
60
55
  label="Alia"
61
56
  workingKey={workingKey}
62
57
  interactive={interactive}
63
58
  reactionKey={reactionKey}
59
+ portrait={portrait}
64
60
  />
65
61
  );
66
- }
62
+ });