@ayni.org/ayni-ui-core 0.3.6 → 0.3.8
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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mediaMessages.d.ts +28 -0
- package/dist/mediaMessages.js +71 -0
- package/dist/profileClient.d.ts +5 -0
- package/dist/profileClient.js +6 -0
- package/dist/reducer.js +4 -1
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './conversationDesign.js';
|
|
|
4
4
|
export * from './directory.js';
|
|
5
5
|
export * from './flag.js';
|
|
6
6
|
export * from './homeDesign.js';
|
|
7
|
+
export * from './mediaMessages.js';
|
|
7
8
|
export * from './profileClient.js';
|
|
8
9
|
export * from './proofOfTrustDesign.js';
|
|
9
10
|
export * from './readState.js';
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './conversationDesign.js';
|
|
|
4
4
|
export * from './directory.js';
|
|
5
5
|
export * from './flag.js';
|
|
6
6
|
export * from './homeDesign.js';
|
|
7
|
+
export * from './mediaMessages.js';
|
|
7
8
|
export * from './profileClient.js';
|
|
8
9
|
export * from './proofOfTrustDesign.js';
|
|
9
10
|
export * from './readState.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReplyQuote, TranscriptMessage } from './types.js';
|
|
2
|
+
type Attachment = Extract<TranscriptMessage, {
|
|
3
|
+
role: 'activity';
|
|
4
|
+
}>;
|
|
5
|
+
/** Whether a transcript message is an attachment of a media message. */
|
|
6
|
+
export declare function isAttachment(message: TranscriptMessage): message is Attachment;
|
|
7
|
+
/** The id the agent knows a message under: a text by its own, a media message by its entry's. */
|
|
8
|
+
export declare function targetIdOf(message: TranscriptMessage): string;
|
|
9
|
+
/** What a media message is, for the quote of a reply and for its menu. */
|
|
10
|
+
export type MediaKind = 'image' | 'voice' | 'video' | 'file';
|
|
11
|
+
export declare function mediaKindOf(message: Attachment): MediaKind;
|
|
12
|
+
/** The quote a reply to any message carries (PROF-RUN-009): a text by its words, a media message by what it is. */
|
|
13
|
+
export declare function quoteOf(message: Exclude<TranscriptMessage, {
|
|
14
|
+
role: 'system';
|
|
15
|
+
}>): ReplyQuote;
|
|
16
|
+
/** The English names of a media message; a UI with its own languages translates the kind. */
|
|
17
|
+
export declare const MEDIA_COPY: Record<MediaKind, string>;
|
|
18
|
+
/**
|
|
19
|
+
* What a quote shows: the words of the quoted message, else what it is. A file is named by its file name; `name`
|
|
20
|
+
* gives the word for a kind in the UI's language.
|
|
21
|
+
*/
|
|
22
|
+
export declare function quoteLabel(quote: ReplyQuote, name?: (kind: MediaKind) => string): string;
|
|
23
|
+
/**
|
|
24
|
+
* The last attachment of each media message: the one that shows the message's reactions when the message carries
|
|
25
|
+
* several (UI-CONV-024). Keyed by the message's entry.
|
|
26
|
+
*/
|
|
27
|
+
export declare function lastAttachments(messages: readonly TranscriptMessage[]): Map<string, string>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reactions and replies on a media message (UI-CONV-024, APP-MSG-005, PROF-RUN-009/010): a picture, a video, a
|
|
3
|
+
* file or a voice note is a message like a text. The agent knows it by the id of its entry, which each of its
|
|
4
|
+
* attachments carries, never by the id of an attachment: a reaction or a reply names that entry, and the
|
|
5
|
+
* reactions of the message are read under it. A reply quotes a media message by what it is.
|
|
6
|
+
*/
|
|
7
|
+
import { ACTIVITY } from '@ayni.org/ayni-agui-profile';
|
|
8
|
+
import { plainText, REPLY_QUOTE_LENGTH } from './conversationDesign.js';
|
|
9
|
+
/** Whether a transcript message is an attachment of a media message. */
|
|
10
|
+
export function isAttachment(message) {
|
|
11
|
+
return message.role === 'activity' && message.activityType === ACTIVITY.attachment;
|
|
12
|
+
}
|
|
13
|
+
/** The id the agent knows a message under: a text by its own, a media message by its entry's. */
|
|
14
|
+
export function targetIdOf(message) {
|
|
15
|
+
return isAttachment(message) ? (message.entryId ?? message.id) : message.id;
|
|
16
|
+
}
|
|
17
|
+
export function mediaKindOf(message) {
|
|
18
|
+
const type = message.content.type;
|
|
19
|
+
return type === 'image' || type === 'voice' || type === 'video' ? type : 'file';
|
|
20
|
+
}
|
|
21
|
+
/** The words a media message has of its own: a caption, a transcription; not the agent's placeholder for it. */
|
|
22
|
+
function ownWords(textRepr) {
|
|
23
|
+
const text = typeof textRepr === 'string' ? textRepr.trim() : '';
|
|
24
|
+
return /^\[[^\]]*\]$/.test(text) ? '' : text;
|
|
25
|
+
}
|
|
26
|
+
/** The quote a reply to any message carries (PROF-RUN-009): a text by its words, a media message by what it is. */
|
|
27
|
+
export function quoteOf(message) {
|
|
28
|
+
if (message.role !== 'activity')
|
|
29
|
+
return {
|
|
30
|
+
id: message.id,
|
|
31
|
+
text: plainText(message.content).slice(0, REPLY_QUOTE_LENGTH),
|
|
32
|
+
role: message.role === 'user' ? 'user' : 'assistant',
|
|
33
|
+
};
|
|
34
|
+
const content = message.content;
|
|
35
|
+
return {
|
|
36
|
+
id: targetIdOf(message),
|
|
37
|
+
text: ownWords(content.textRepr).slice(0, REPLY_QUOTE_LENGTH),
|
|
38
|
+
role: content.role === 'user' ? 'user' : 'assistant',
|
|
39
|
+
media: mediaKindOf(message),
|
|
40
|
+
...(content.filename ? { filename: content.filename } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** The English names of a media message; a UI with its own languages translates the kind. */
|
|
44
|
+
export const MEDIA_COPY = {
|
|
45
|
+
image: 'Photo',
|
|
46
|
+
voice: 'Voice note',
|
|
47
|
+
video: 'Video',
|
|
48
|
+
file: 'File',
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* What a quote shows: the words of the quoted message, else what it is. A file is named by its file name; `name`
|
|
52
|
+
* gives the word for a kind in the UI's language.
|
|
53
|
+
*/
|
|
54
|
+
export function quoteLabel(quote, name = (kind) => MEDIA_COPY[kind]) {
|
|
55
|
+
if (quote.text)
|
|
56
|
+
return quote.text;
|
|
57
|
+
if (!quote.media)
|
|
58
|
+
return '';
|
|
59
|
+
return quote.media === 'file' && quote.filename ? quote.filename : name(quote.media);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The last attachment of each media message: the one that shows the message's reactions when the message carries
|
|
63
|
+
* several (UI-CONV-024). Keyed by the message's entry.
|
|
64
|
+
*/
|
|
65
|
+
export function lastAttachments(messages) {
|
|
66
|
+
const last = new Map();
|
|
67
|
+
for (const m of messages)
|
|
68
|
+
if (isAttachment(m))
|
|
69
|
+
last.set(targetIdOf(m), m.id);
|
|
70
|
+
return last;
|
|
71
|
+
}
|
package/dist/profileClient.d.ts
CHANGED
|
@@ -52,6 +52,11 @@ export declare class ProfileClient {
|
|
|
52
52
|
run(sessionId: string, token: string, input: RunInput, onEvent: (event: AgUiEvent) => void, signal: AbortSignal): Promise<void>;
|
|
53
53
|
cancel(sessionId: string, token: string, runId: string): Promise<boolean>;
|
|
54
54
|
history(sessionId: string, token: string, before?: string, limit?: number): Promise<HistoryPage>;
|
|
55
|
+
/**
|
|
56
|
+
* Uploads a file before the turn that references it (UI-MEDIA-003). Its name goes in a field of its own, before
|
|
57
|
+
* the file (PROF-HIST-008): platforms do not write the name of a multipart file alike, and the agent takes the
|
|
58
|
+
* field as the name when it is there.
|
|
59
|
+
*/
|
|
55
60
|
upload(sessionId: string, token: string, file: Blob, filename: string): Promise<UploadResponse>;
|
|
56
61
|
/** Attachments are fetched with the token and shown as revocable object URLs (UI-MEDIA-001). */
|
|
57
62
|
attachment(sessionId: string, token: string, attachmentId: string): Promise<Blob>;
|
package/dist/profileClient.js
CHANGED
|
@@ -178,8 +178,14 @@ export class ProfileClient {
|
|
|
178
178
|
throw await parseError(response);
|
|
179
179
|
return response.json();
|
|
180
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Uploads a file before the turn that references it (UI-MEDIA-003). Its name goes in a field of its own, before
|
|
183
|
+
* the file (PROF-HIST-008): platforms do not write the name of a multipart file alike, and the agent takes the
|
|
184
|
+
* field as the name when it is there.
|
|
185
|
+
*/
|
|
181
186
|
async upload(sessionId, token, file, filename) {
|
|
182
187
|
const form = new FormData();
|
|
188
|
+
form.append('filename', filename);
|
|
183
189
|
form.append('file', file, filename);
|
|
184
190
|
const response = await this.fetchFn(this.url(`/${sessionId}/attachments`), {
|
|
185
191
|
method: 'POST',
|
package/dist/reducer.js
CHANGED
|
@@ -287,8 +287,11 @@ export function reactionsOf(page) {
|
|
|
287
287
|
const out = {};
|
|
288
288
|
for (const m of page) {
|
|
289
289
|
const meta = (m.metadata ?? {});
|
|
290
|
+
// the reactions of a media message are those of its entry, which each of its attachments carries: they are
|
|
291
|
+
// kept under the entry, where a live `ayni.reaction` names it too (UI-CONV-024)
|
|
292
|
+
const key = m.role === 'activity' && meta.entryId ? meta.entryId : String(m.id);
|
|
290
293
|
if (meta.reactions?.length)
|
|
291
|
-
out[
|
|
294
|
+
out[key] = meta.reactions.map((r) => ({ emoji: r.emoji, by: r.by }));
|
|
292
295
|
}
|
|
293
296
|
return out;
|
|
294
297
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -106,8 +106,12 @@ export interface SessionRecord {
|
|
|
106
106
|
}
|
|
107
107
|
export interface ReplyQuote {
|
|
108
108
|
id: string;
|
|
109
|
+
/** the words of the quoted message; empty for a media message that has none of its own */
|
|
109
110
|
text: string;
|
|
110
111
|
role: 'user' | 'assistant';
|
|
112
|
+
/** what the quoted message is, when it is a media message (PROF-RUN-009) */
|
|
113
|
+
media?: 'image' | 'voice' | 'video' | 'file';
|
|
114
|
+
filename?: string;
|
|
111
115
|
}
|
|
112
116
|
export type TranscriptMessage = {
|
|
113
117
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ayni.org/ayni-ui-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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",
|