@space3-npm/cybersoul-client 1.4.15 → 1.4.16
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/client.js +85 -0
- package/dist/types.d.ts +36 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -724,6 +724,34 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
724
724
|
if (parsedIntent && (parsedIntent.stateUpdate || parsedIntent.userAnalysis)) {
|
|
725
725
|
persistedStatePromise = this._updateDynamicContextInternal(parsedIntent.stateUpdate, parsedIntent.userAnalysis);
|
|
726
726
|
}
|
|
727
|
+
// Fire `onStateReady` the moment the dynamic-context PATCH resolves
|
|
728
|
+
// (or immediately, when no state update was emitted). This is
|
|
729
|
+
// independent of media generation, so the UI can stop showing
|
|
730
|
+
// "updating…" on temperature / relationship stage well before the
|
|
731
|
+
// (potentially slow) image task finishes. Errors are swallowed:
|
|
732
|
+
// an authoritative snapshot is best-effort, the optimistic delta
|
|
733
|
+
// already applied client-side is the fallback.
|
|
734
|
+
if (params.onStateReady) {
|
|
735
|
+
const stateReadyCb = params.onStateReady;
|
|
736
|
+
persistedStatePromise
|
|
737
|
+
.then((persisted) => {
|
|
738
|
+
try {
|
|
739
|
+
stateReadyCb(persisted ?? {});
|
|
740
|
+
}
|
|
741
|
+
catch (cbErr) {
|
|
742
|
+
console.warn("[CyberSoulClient] onStateReady callback threw:", cbErr);
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
.catch(() => {
|
|
746
|
+
// PATCH failed; still signal LLM-phase complete with an empty snapshot.
|
|
747
|
+
try {
|
|
748
|
+
stateReadyCb({});
|
|
749
|
+
}
|
|
750
|
+
catch (cbErr) {
|
|
751
|
+
console.warn("[CyberSoulClient] onStateReady callback threw:", cbErr);
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
}
|
|
727
755
|
const resolvedTextResponse = typeof parsedIntent.textResponse === "string" &&
|
|
728
756
|
parsedIntent.textResponse.trim().length > 0
|
|
729
757
|
? parsedIntent.textResponse
|
|
@@ -799,6 +827,18 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
799
827
|
.then((res) => {
|
|
800
828
|
finalImageUrl = res.image_url;
|
|
801
829
|
finalImageMediaId = res.id;
|
|
830
|
+
if (params.onMediaReady && finalImageUrl) {
|
|
831
|
+
try {
|
|
832
|
+
params.onMediaReady({
|
|
833
|
+
modality: "image",
|
|
834
|
+
url: finalImageUrl,
|
|
835
|
+
mediaId: finalImageMediaId,
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
catch (cbErr) {
|
|
839
|
+
console.warn("[CyberSoulClient] onMediaReady(image) threw:", cbErr);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
802
842
|
})
|
|
803
843
|
.catch((e) => {
|
|
804
844
|
if (!(e instanceof CyberSoulInsufficientPointsError) &&
|
|
@@ -826,6 +866,19 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
826
866
|
finalAudioUrl = res.audio_url;
|
|
827
867
|
finalAudioMediaId = res.id;
|
|
828
868
|
finalDurationSec = res.duration_sec;
|
|
869
|
+
if (params.onMediaReady && finalAudioUrl) {
|
|
870
|
+
try {
|
|
871
|
+
params.onMediaReady({
|
|
872
|
+
modality: "voice",
|
|
873
|
+
url: finalAudioUrl,
|
|
874
|
+
mediaId: finalAudioMediaId,
|
|
875
|
+
durationSec: finalDurationSec,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
catch (cbErr) {
|
|
879
|
+
console.warn("[CyberSoulClient] onMediaReady(voice) threw:", cbErr);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
829
882
|
})
|
|
830
883
|
.catch((e) => {
|
|
831
884
|
if (!(e instanceof CyberSoulInsufficientPointsError) &&
|
|
@@ -1095,6 +1148,26 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1095
1148
|
if (parsedIntent.stateUpdate) {
|
|
1096
1149
|
persistedStatePromise = this._updateDynamicContextInternal(parsedIntent.stateUpdate);
|
|
1097
1150
|
}
|
|
1151
|
+
if (params.onStateReady) {
|
|
1152
|
+
const stateReadyCb = params.onStateReady;
|
|
1153
|
+
persistedStatePromise
|
|
1154
|
+
.then((persisted) => {
|
|
1155
|
+
try {
|
|
1156
|
+
stateReadyCb(persisted ?? {});
|
|
1157
|
+
}
|
|
1158
|
+
catch (cbErr) {
|
|
1159
|
+
console.warn("[CyberSoulClient] onStateReady callback threw:", cbErr);
|
|
1160
|
+
}
|
|
1161
|
+
})
|
|
1162
|
+
.catch(() => {
|
|
1163
|
+
try {
|
|
1164
|
+
stateReadyCb({});
|
|
1165
|
+
}
|
|
1166
|
+
catch (cbErr) {
|
|
1167
|
+
console.warn("[CyberSoulClient] onStateReady callback threw:", cbErr);
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1098
1171
|
if (params.onTextReady) {
|
|
1099
1172
|
params.onTextReady(parsedIntent.textResponse, parsedIntent.actionText, {
|
|
1100
1173
|
stateUpdate: parsedIntent.stateUpdate,
|
|
@@ -1109,6 +1182,18 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1109
1182
|
const res = await this.generatePrimitive("image", parsedIntent.imageParams);
|
|
1110
1183
|
finalImageUrl = res.image_url;
|
|
1111
1184
|
finalImageMediaId = res.id;
|
|
1185
|
+
if (params.onMediaReady && finalImageUrl) {
|
|
1186
|
+
try {
|
|
1187
|
+
params.onMediaReady({
|
|
1188
|
+
modality: "image",
|
|
1189
|
+
url: finalImageUrl,
|
|
1190
|
+
mediaId: finalImageMediaId,
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
catch (cbErr) {
|
|
1194
|
+
console.warn("[CyberSoulClient] onMediaReady(image) threw:", cbErr);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1112
1197
|
}
|
|
1113
1198
|
catch (e) {
|
|
1114
1199
|
if (e instanceof CyberSoulInsufficientPointsError ||
|
package/dist/types.d.ts
CHANGED
|
@@ -53,12 +53,37 @@ export interface PersistedDynamicContext {
|
|
|
53
53
|
/** Persisted relationship stage label after re-evaluation. */
|
|
54
54
|
relationshipStage?: string;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Payload delivered by [InteractParams.onMediaReady] when an individual
|
|
58
|
+
* media task (image/voice) finishes. Fires from inside the SDK's
|
|
59
|
+
* per-modality `.then()` so callers can render the bubble the moment
|
|
60
|
+
* that modality is ready, instead of waiting for the slowest one to
|
|
61
|
+
* finish. The aggregated `InteractResponse` is still returned at the
|
|
62
|
+
* end and carries the same URLs (no double-render needed if the caller
|
|
63
|
+
* tracks per-modality state).
|
|
64
|
+
*/
|
|
65
|
+
export interface MediaReadyPayload {
|
|
66
|
+
modality: "image" | "voice";
|
|
67
|
+
url: string;
|
|
68
|
+
mediaId?: string;
|
|
69
|
+
/** Voice only — TTS duration in seconds when known. */
|
|
70
|
+
durationSec?: number;
|
|
71
|
+
}
|
|
56
72
|
export interface ProactiveParams {
|
|
57
73
|
history?: HistoryEntry[];
|
|
58
74
|
maxUnreplied?: number;
|
|
59
75
|
requestTypes?: InteractRequestType[];
|
|
60
76
|
localContext?: string;
|
|
61
77
|
onTextReady?: (textResponse: string, actionText?: string, metadata?: InteractMetadata) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Fires when the server-authoritative PATCH /dynamic-context resolves,
|
|
80
|
+
* before media generation completes. Lets the UI update the live
|
|
81
|
+
* temperature / relationship stage immediately instead of waiting for
|
|
82
|
+
* the (potentially slow) image task.
|
|
83
|
+
*/
|
|
84
|
+
onStateReady?: (persisted: PersistedDynamicContext) => void;
|
|
85
|
+
/** Fires per modality as each media task settles successfully. */
|
|
86
|
+
onMediaReady?: (payload: MediaReadyPayload) => void;
|
|
62
87
|
}
|
|
63
88
|
export interface ProactiveResponse {
|
|
64
89
|
status: "success" | "skipped" | "error";
|
|
@@ -85,6 +110,17 @@ export interface InteractParams {
|
|
|
85
110
|
requestTypes?: InteractRequestType[];
|
|
86
111
|
history?: HistoryEntry[];
|
|
87
112
|
onTextReady?: (textResponse: string, actionText?: string, metadata?: InteractMetadata) => void;
|
|
113
|
+
/**
|
|
114
|
+
* Fires when the server-authoritative PATCH /dynamic-context resolves,
|
|
115
|
+
* before media generation completes. Lets the UI update the live
|
|
116
|
+
* temperature / relationship stage immediately instead of waiting for
|
|
117
|
+
* the (potentially slow) image task. When the turn has no
|
|
118
|
+
* `stateUpdate`, this still fires with an empty object so callers can
|
|
119
|
+
* use it as a generic "LLM phase done" signal.
|
|
120
|
+
*/
|
|
121
|
+
onStateReady?: (persisted: PersistedDynamicContext) => void;
|
|
122
|
+
/** Fires per modality as each media task settles successfully. */
|
|
123
|
+
onMediaReady?: (payload: MediaReadyPayload) => void;
|
|
88
124
|
}
|
|
89
125
|
export interface OndemandEventParams {
|
|
90
126
|
eventDescription: string;
|