@convai/embody 0.4.0 → 0.4.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/CHANGELOG.md +6 -0
- package/dist/react/useWidgetClient.d.ts +26 -0
- package/dist/react/useWidgetClient.js +44 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,31 @@ export type WidgetClient = ConvaiClient & {
|
|
|
6
6
|
isVideoEnabled: boolean;
|
|
7
7
|
isScreenShareActive: boolean;
|
|
8
8
|
};
|
|
9
|
+
type ChatMessage = ConvaiClient['chatMessages'][number];
|
|
10
|
+
/**
|
|
11
|
+
* How long after a typed message its server echo can still arrive. Measured
|
|
12
|
+
* at ~2 s on staging; the window is generous because a slow turn is still an
|
|
13
|
+
* echo, while the same words said aloud half a minute later are a new message.
|
|
14
|
+
*/
|
|
15
|
+
export declare const TYPED_ECHO_WINDOW_MS = 30000;
|
|
16
|
+
/**
|
|
17
|
+
* The transcript without the server's echo of typed messages.
|
|
18
|
+
*
|
|
19
|
+
* `sendUserTextMessage` appends the text locally as `user-llm-text`, and the
|
|
20
|
+
* SDK drops the server's `user-llm-text` echo so the message appears once.
|
|
21
|
+
* But the server ALSO answers typed text with a final `user-transcription`
|
|
22
|
+
* carrying the same words — with no `logicalTurnId` to correlate on — which
|
|
23
|
+
* the SDK stores as a new message and `<ConvaiWidget/>` renders as a second
|
|
24
|
+
* "You" bubble. Every typed message showed twice; every reply once. Verified
|
|
25
|
+
* on web-sdk 1.8.0 and 1.9.0-beta.3, which filter identically.
|
|
26
|
+
*
|
|
27
|
+
* A transcription is an echo when an unmatched typed message with the same
|
|
28
|
+
* trimmed text precedes it within the window; each typed message cancels at
|
|
29
|
+
* most one. Spoken turns never produce a `user-llm-text`, so a real
|
|
30
|
+
* transcription is never dropped. An echo that streams in chunks can show
|
|
31
|
+
* its partial text until the final chunk matches — a flicker, not a duplicate.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withoutTypedEchoes(messages: readonly ChatMessage[]): ChatMessage[];
|
|
9
34
|
/**
|
|
10
35
|
* ```tsx
|
|
11
36
|
* const { client } = useCharacter({ apiKey, characterId })
|
|
@@ -16,3 +41,4 @@ export type WidgetClient = ConvaiClient & {
|
|
|
16
41
|
* Returns `null` until the character's connection exists.
|
|
17
42
|
*/
|
|
18
43
|
export declare function useWidgetClient(client: ConvaiClient | null): WidgetClient | null;
|
|
44
|
+
export {};
|
|
@@ -12,6 +12,47 @@
|
|
|
12
12
|
* for activity, and the three control emitters for the toggles.
|
|
13
13
|
*/
|
|
14
14
|
import { useEffect, useMemo, useState } from 'react';
|
|
15
|
+
/**
|
|
16
|
+
* How long after a typed message its server echo can still arrive. Measured
|
|
17
|
+
* at ~2 s on staging; the window is generous because a slow turn is still an
|
|
18
|
+
* echo, while the same words said aloud half a minute later are a new message.
|
|
19
|
+
*/
|
|
20
|
+
export const TYPED_ECHO_WINDOW_MS = 30_000;
|
|
21
|
+
/**
|
|
22
|
+
* The transcript without the server's echo of typed messages.
|
|
23
|
+
*
|
|
24
|
+
* `sendUserTextMessage` appends the text locally as `user-llm-text`, and the
|
|
25
|
+
* SDK drops the server's `user-llm-text` echo so the message appears once.
|
|
26
|
+
* But the server ALSO answers typed text with a final `user-transcription`
|
|
27
|
+
* carrying the same words — with no `logicalTurnId` to correlate on — which
|
|
28
|
+
* the SDK stores as a new message and `<ConvaiWidget/>` renders as a second
|
|
29
|
+
* "You" bubble. Every typed message showed twice; every reply once. Verified
|
|
30
|
+
* on web-sdk 1.8.0 and 1.9.0-beta.3, which filter identically.
|
|
31
|
+
*
|
|
32
|
+
* A transcription is an echo when an unmatched typed message with the same
|
|
33
|
+
* trimmed text precedes it within the window; each typed message cancels at
|
|
34
|
+
* most one. Spoken turns never produce a `user-llm-text`, so a real
|
|
35
|
+
* transcription is never dropped. An echo that streams in chunks can show
|
|
36
|
+
* its partial text until the final chunk matches — a flicker, not a duplicate.
|
|
37
|
+
*/
|
|
38
|
+
export function withoutTypedEchoes(messages) {
|
|
39
|
+
const pending = [];
|
|
40
|
+
return messages.filter((m) => {
|
|
41
|
+
const content = m.content.trim();
|
|
42
|
+
const at = Date.parse(m.timestamp);
|
|
43
|
+
if (m.type === 'user-llm-text') {
|
|
44
|
+
pending.push({ content, at });
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (m.type !== 'user-transcription')
|
|
48
|
+
return true;
|
|
49
|
+
const i = pending.findIndex((t) => t.content === content && at - t.at >= 0 && at - t.at <= TYPED_ECHO_WINDOW_MS);
|
|
50
|
+
if (i === -1)
|
|
51
|
+
return true;
|
|
52
|
+
pending.splice(i, 1);
|
|
53
|
+
return false;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
15
56
|
/** Priority order matches the SDK's: speaking > listening > thinking > connected. */
|
|
16
57
|
function activityOf(state) {
|
|
17
58
|
if (state.isSpeaking)
|
|
@@ -89,6 +130,9 @@ export function useWidgetClient(client) {
|
|
|
89
130
|
};
|
|
90
131
|
return new Proxy(client, {
|
|
91
132
|
get(target, prop, receiver) {
|
|
133
|
+
// The widget renders straight from this; see withoutTypedEchoes.
|
|
134
|
+
if (prop === 'chatMessages')
|
|
135
|
+
return withoutTypedEchoes(Reflect.get(target, prop, target));
|
|
92
136
|
if (typeof prop === 'string' && prop in overrides)
|
|
93
137
|
return overrides[prop];
|
|
94
138
|
// Receiver is the TARGET, not the proxy, so getters and methods run
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@convai/embody",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Give a Convai character a body: resolve 3D characters by characterId and drive them with lipsync and animation. Layered on @convai/web-sdk.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Convai <support@convai.com>",
|