@ayni.org/ayni-ui-core 0.3.2 → 0.3.4

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/README.md CHANGED
@@ -16,7 +16,7 @@ The browser draws with CSS and the Ayni app with React Native styles. What the t
16
16
 
17
17
  | Surface | Design values and colour roles | What it shows |
18
18
  | --- | --- | --- |
19
- | A conversation | `CONVERSATION_DESIGN`, `CONVERSATION_COLORS` | `replyQuoteOf`, `reactionPillOf`, `plainText` |
19
+ | A conversation | `CONVERSATION_DESIGN`, `CONVERSATION_COLORS` | `replyQuoteOf`, `reactionPillOf`, `plainText`, `progressOf` (the agent is working) |
20
20
  | The home page (rail and column) | `HOME_DESIGN`, `HOME_COLORS` | `TRUST_MARK`, `CONTROLLER_KIND_ICON`, `formatTime` |
21
21
  | The Proof of Trust | `PROOF_OF_TRUST_DESIGN`, `PROOF_OF_TRUST_COLORS` | `verdictOf`, `identityStepOf`, `accreditationLine`, `otherCredentialLine`, `claimRows`, and its English wording (`PROOF_OF_TRUST_COPY`) |
22
22
 
@@ -75,6 +75,33 @@ export declare const CONVERSATION_DESIGN: {
75
75
  readonly bottom: 12;
76
76
  readonly awayBeyond: 320;
77
77
  };
78
+ /**
79
+ * The agent is working (UI-CONV-016): a bubble on the agent's side with three bouncing dots, then the steps of
80
+ * the run in progress or "Thinking…".
81
+ */
82
+ readonly progress: {
83
+ readonly fontSize: 13;
84
+ readonly gap: 10;
85
+ readonly paddingY: 10;
86
+ readonly paddingX: 14;
87
+ readonly radius: 16;
88
+ readonly tailRadius: 4;
89
+ };
90
+ /**
91
+ * The three dots: each rises and brightens, one after the other. Over one period a dot is at rest until it
92
+ * starts, at its peak at `peakAt` of the period and back at rest from `restFrom`; the second and third dots
93
+ * start `delayMs` and twice `delayMs` later.
94
+ */
95
+ readonly dots: {
96
+ readonly size: 7;
97
+ readonly gap: 4;
98
+ readonly periodMs: 1200;
99
+ readonly delayMs: 150;
100
+ readonly lift: 4;
101
+ readonly restOpacity: 0.35;
102
+ readonly peakAt: 0.4;
103
+ readonly restFrom: 0.8;
104
+ };
78
105
  };
79
106
  export type ConversationDesign = typeof CONVERSATION_DESIGN;
80
107
  /** The colour roles both palettes define, in the browser as custom properties and in the app as theme colours. */
@@ -113,6 +140,13 @@ export declare const CONVERSATION_COLORS: {
113
140
  readonly border: "border";
114
141
  readonly icon: "text";
115
142
  };
143
+ readonly progress: {
144
+ readonly background: "surface";
145
+ readonly text: "muted";
146
+ };
147
+ readonly dots: {
148
+ readonly color: "accent";
149
+ };
116
150
  };
117
151
  /** The side a message sits on, and the corner its bubble tightens. */
118
152
  export declare function bubbleSide(role: 'user' | 'assistant' | 'system'): 'mine' | 'theirs' | 'system';
@@ -165,3 +199,26 @@ export declare function reactionPillOf(reactions: readonly {
165
199
  }[];
166
200
  mine?: string;
167
201
  } | null;
202
+ /** The wording of a conversation the two renderers share, in English (the browser's `conversation.*` keys). */
203
+ export declare const CONVERSATION_COPY: {
204
+ readonly thinking: "Thinking…";
205
+ };
206
+ /**
207
+ * What the transcript shows while the agent works (UI-CONV-016): the steps of the run in progress when it reports
208
+ * some; else "thinking", from the start of a run until its reply begins to stream; nothing when no run is in
209
+ * progress or the reply is already arriving. A run started from another device of the person counts the same.
210
+ */
211
+ export declare function progressOf(transcript: {
212
+ run: {
213
+ steps: readonly string[];
214
+ } | null;
215
+ messages: readonly {
216
+ role: string;
217
+ streaming?: boolean;
218
+ }[];
219
+ } | null | undefined): {
220
+ kind: 'steps';
221
+ steps: readonly string[];
222
+ } | {
223
+ kind: 'thinking';
224
+ } | null;
@@ -59,6 +59,17 @@ export const CONVERSATION_DESIGN = {
59
59
  },
60
60
  /** the button that returns to the latest message */
61
61
  latestButton: { size: 36, right: 20, bottom: 12, awayBeyond: 320 },
62
+ /**
63
+ * The agent is working (UI-CONV-016): a bubble on the agent's side with three bouncing dots, then the steps of
64
+ * the run in progress or "Thinking…".
65
+ */
66
+ progress: { fontSize: 13, gap: 10, paddingY: 10, paddingX: 14, radius: 16, tailRadius: 4 },
67
+ /**
68
+ * The three dots: each rises and brightens, one after the other. Over one period a dot is at rest until it
69
+ * starts, at its peak at `peakAt` of the period and back at rest from `restFrom`; the second and third dots
70
+ * start `delayMs` and twice `delayMs` later.
71
+ */
72
+ dots: { size: 7, gap: 4, periodMs: 1200, delayMs: 150, lift: 4, restOpacity: 0.35, peakAt: 0.4, restFrom: 0.8 },
62
73
  };
63
74
  /** Which colour role paints what in a conversation. */
64
75
  export const CONVERSATION_COLORS = {
@@ -70,6 +81,8 @@ export const CONVERSATION_COLORS = {
70
81
  quote: { border: 'accent', who: 'accent' },
71
82
  reactionPill: { background: 'bg', border: 'border', text: 'text', mineBorder: 'accent' },
72
83
  latestButton: { background: 'bg', border: 'border', icon: 'text' },
84
+ progress: { background: 'surface', text: 'muted' },
85
+ dots: { color: 'accent' },
73
86
  };
74
87
  /** The side a message sits on, and the corner its bubble tightens. */
75
88
  export function bubbleSide(role) {
@@ -123,3 +136,21 @@ export function reactionPillOf(reactions, me) {
123
136
  mine: own?.emoji,
124
137
  };
125
138
  }
139
+ /** The wording of a conversation the two renderers share, in English (the browser's `conversation.*` keys). */
140
+ export const CONVERSATION_COPY = {
141
+ thinking: 'Thinking…',
142
+ };
143
+ /**
144
+ * What the transcript shows while the agent works (UI-CONV-016): the steps of the run in progress when it reports
145
+ * some; else "thinking", from the start of a run until its reply begins to stream; nothing when no run is in
146
+ * progress or the reply is already arriving. A run started from another device of the person counts the same.
147
+ */
148
+ export function progressOf(transcript) {
149
+ const run = transcript?.run;
150
+ if (!run)
151
+ return null;
152
+ if (run.steps.length)
153
+ return { kind: 'steps', steps: run.steps };
154
+ const replying = transcript.messages.some((m) => m.role !== 'activity' && m.streaming);
155
+ return replying ? null : { kind: 'thinking' };
156
+ }
package/dist/reducer.d.ts CHANGED
@@ -4,9 +4,14 @@ export interface Reduction {
4
4
  transcript: Transcript;
5
5
  session: SessionRecord;
6
6
  /** signals the shell reacts to (title, badge, sound) */
7
- signals: ('message' | 'bound' | 'closed' | 'token' | 'approval' | 'identified')[];
7
+ signals: ('message' | 'bound' | 'closed' | 'token' | 'approval' | 'identified' | 'conversations')[];
8
8
  }
9
9
  export declare function emptyTranscript(sessionId: string): Transcript;
10
+ /**
11
+ * The agent's signal that the person's list of conversations changed (PROF-CONV-007): a title, an archive, a
12
+ * closure, made from any device. Named here until the profile package that lists it is the one every client has.
13
+ */
14
+ export declare const CONVERSATION_CHANGED = "ayni.conversation.changed";
10
15
  /** The five closed states of a flow (flow profile §5.2). */
11
16
  export declare function isClosedFlow(state: unknown): boolean;
12
17
  export declare function reduce(transcript: Transcript, session: SessionRecord, event: AgUiEvent, fromRun: boolean, isOnScreen: boolean): Reduction;
package/dist/reducer.js CHANGED
@@ -7,6 +7,11 @@ export function emptyTranscript(sessionId) {
7
7
  return { sessionId, messages: [], oldestLoadedId: null, complete: false, run: null, routed: {}, reactions: {} };
8
8
  }
9
9
  const now = () => new Date().toISOString();
10
+ /**
11
+ * The agent's signal that the person's list of conversations changed (PROF-CONV-007): a title, an archive, a
12
+ * closure, made from any device. Named here until the profile package that lists it is the one every client has.
13
+ */
14
+ export const CONVERSATION_CHANGED = 'ayni.conversation.changed';
10
15
  /** The five closed states of a flow (flow profile §5.2). */
11
16
  export function isClosedFlow(state) {
12
17
  return (state === 'completed' || state === 'declined' || state === 'cancelled' || state === 'failed' || state === 'expired');
@@ -191,6 +196,11 @@ export function reduce(transcript, session, event, fromRun, isOnScreen) {
191
196
  }
192
197
  break;
193
198
  }
199
+ case CONVERSATION_CHANGED:
200
+ // a conversation of the person was renamed, archived or closed, here or on another device: the client
201
+ // reads the agent's list again (PROF-CONV-007)
202
+ signals.push('conversations');
203
+ break;
194
204
  case CUSTOM_EVENT.sessionBound:
195
205
  s = {
196
206
  ...s,
package/dist/types.d.ts CHANGED
@@ -64,6 +64,8 @@ export interface AgentRecord {
64
64
  deviceHandle?: string;
65
65
  /** pairing secret from the agent (D30): sent as deviceProof, replaced by every rotation, never leaves the device store */
66
66
  deviceSecret?: string;
67
+ /** when this device was paired with the agent through the phone; kept across the rotations of the secret */
68
+ linkedAt?: string;
67
69
  }
68
70
  export interface SessionRecord {
69
71
  sessionId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ayni.org/ayni-ui-core",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Framework-independent core of the Ayni UI (UI-SHELL-004): agents and controllers, trust resolution, sessions and binding, the conversation reducer, the local store and sync; shared by the browser UI and the Ayni app",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",