@space3-npm/cybersoul-client 1.4.12 → 1.4.13
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.d.ts +8 -0
- package/dist/client.js +67 -4
- package/dist/types.d.ts +27 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -70,6 +70,14 @@ export declare class CyberSoulClient {
|
|
|
70
70
|
* neutral placeholder (e.g. "...") so the TTS call still has valid input.
|
|
71
71
|
*/
|
|
72
72
|
private sanitizeTextForVoice;
|
|
73
|
+
/**
|
|
74
|
+
* Build the in-band `mediaError` envelope from the first typed media
|
|
75
|
+
* failure captured during `interact()` / `proactiveInteract()`. Keeps
|
|
76
|
+
* the conversion in one place so both call sites stay consistent and
|
|
77
|
+
* the SDK never re-throws on a partial media failure once the text
|
|
78
|
+
* reply is already in flight.
|
|
79
|
+
*/
|
|
80
|
+
private buildMediaError;
|
|
73
81
|
private formatHistoryEntries;
|
|
74
82
|
private buildHistoryTranscript;
|
|
75
83
|
interact(params: InteractParams): Promise<InteractResponse>;
|
package/dist/client.js
CHANGED
|
@@ -515,6 +515,35 @@ ${isProactive
|
|
|
515
515
|
.replace(/\s+/g, " ")
|
|
516
516
|
.trim();
|
|
517
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* Build the in-band `mediaError` envelope from the first typed media
|
|
520
|
+
* failure captured during `interact()` / `proactiveInteract()`. Keeps
|
|
521
|
+
* the conversion in one place so both call sites stay consistent and
|
|
522
|
+
* the SDK never re-throws on a partial media failure once the text
|
|
523
|
+
* reply is already in flight.
|
|
524
|
+
*/
|
|
525
|
+
buildMediaError(err, affected) {
|
|
526
|
+
if (err instanceof CyberSoulInsufficientPointsError) {
|
|
527
|
+
return {
|
|
528
|
+
kind: "insufficient-points",
|
|
529
|
+
code: err.code,
|
|
530
|
+
message: err.message,
|
|
531
|
+
affected,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
if (err instanceof CyberSoulWalletError) {
|
|
535
|
+
return {
|
|
536
|
+
kind: "wallet",
|
|
537
|
+
message: err.message,
|
|
538
|
+
affected,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
kind: "unknown",
|
|
543
|
+
message: err.message,
|
|
544
|
+
affected,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
518
547
|
formatHistoryEntries(history, userName, agentName, promptDirective = "") {
|
|
519
548
|
const contextLines = [];
|
|
520
549
|
for (let i = 0; i < history.length; i++) {
|
|
@@ -712,6 +741,27 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
712
741
|
let finalAudioUrl = undefined;
|
|
713
742
|
let finalAudioMediaId = undefined;
|
|
714
743
|
let finalDurationSec = undefined;
|
|
744
|
+
// Partial-failure capture: text was already produced and emitted
|
|
745
|
+
// via [onTextReady], so a wallet / insufficient-points failure on
|
|
746
|
+
// image or voice MUST NOT abort the whole turn. We collect the
|
|
747
|
+
// affected modalities + first typed error and surface them in-band
|
|
748
|
+
// through `InteractResponse.mediaError`. The caller (MessageBus /
|
|
749
|
+
// UI) decides how to message the user without losing the reply.
|
|
750
|
+
const mediaErrorAffected = [];
|
|
751
|
+
let firstMediaError = null;
|
|
752
|
+
const captureMediaError = (modality, e) => {
|
|
753
|
+
if (!(e instanceof CyberSoulError))
|
|
754
|
+
return;
|
|
755
|
+
if (!(e instanceof CyberSoulInsufficientPointsError) &&
|
|
756
|
+
!(e instanceof CyberSoulWalletError)) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (!mediaErrorAffected.includes(modality)) {
|
|
760
|
+
mediaErrorAffected.push(modality);
|
|
761
|
+
}
|
|
762
|
+
if (!firstMediaError)
|
|
763
|
+
firstMediaError = e;
|
|
764
|
+
};
|
|
715
765
|
// Output Event Trigger
|
|
716
766
|
if (parsedIntent.triggerEvent) {
|
|
717
767
|
mediaTasks.push(this.apiFetch("/api/v1/cyber-soul/characters/ondemand-event", {
|
|
@@ -748,8 +798,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
748
798
|
})
|
|
749
799
|
.catch((e) => {
|
|
750
800
|
console.error("[CyberSoulClient] Image generation failed:", e);
|
|
751
|
-
|
|
752
|
-
throw e;
|
|
801
|
+
captureMediaError("image", e);
|
|
753
802
|
}));
|
|
754
803
|
}
|
|
755
804
|
const shouldGenerateVoice = types.includes(InteractRequestType.VOICE) &&
|
|
@@ -773,8 +822,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
773
822
|
})
|
|
774
823
|
.catch((e) => {
|
|
775
824
|
console.error("[CyberSoulClient] Voice generation failed:", e);
|
|
776
|
-
|
|
777
|
-
throw e;
|
|
825
|
+
captureMediaError("voice", e);
|
|
778
826
|
}));
|
|
779
827
|
}
|
|
780
828
|
// Wait for image/voice gens to return successfully
|
|
@@ -784,6 +832,9 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
784
832
|
// This adds at most ~1 small request to the critical path; in
|
|
785
833
|
// practice the PATCH usually resolves before media generation.
|
|
786
834
|
const persistedDynamicContext = (await persistedStatePromise) ?? undefined;
|
|
835
|
+
const mediaError = firstMediaError
|
|
836
|
+
? this.buildMediaError(firstMediaError, mediaErrorAffected)
|
|
837
|
+
: undefined;
|
|
787
838
|
return {
|
|
788
839
|
status: "success",
|
|
789
840
|
textResponse: resolvedTextResponse || "...",
|
|
@@ -799,6 +850,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
799
850
|
userAnalysis: parsedIntent.userAnalysis,
|
|
800
851
|
isEndTurn: parsedIntent.isEndTurn,
|
|
801
852
|
persistedDynamicContext,
|
|
853
|
+
mediaError,
|
|
802
854
|
};
|
|
803
855
|
}
|
|
804
856
|
catch (error) {
|
|
@@ -1040,6 +1092,8 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1040
1092
|
}
|
|
1041
1093
|
let finalImageUrl;
|
|
1042
1094
|
let finalImageMediaId;
|
|
1095
|
+
let proactiveMediaError = null;
|
|
1096
|
+
const proactiveAffected = [];
|
|
1043
1097
|
if (parsedIntent.imageParams) {
|
|
1044
1098
|
try {
|
|
1045
1099
|
const res = await this.generatePrimitive("image", parsedIntent.imageParams);
|
|
@@ -1048,9 +1102,17 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1048
1102
|
}
|
|
1049
1103
|
catch (e) {
|
|
1050
1104
|
console.error("[CyberSoulClient] Proactive Image generation failed:", e);
|
|
1105
|
+
if (e instanceof CyberSoulInsufficientPointsError ||
|
|
1106
|
+
e instanceof CyberSoulWalletError) {
|
|
1107
|
+
proactiveMediaError = e;
|
|
1108
|
+
proactiveAffected.push("image");
|
|
1109
|
+
}
|
|
1051
1110
|
}
|
|
1052
1111
|
}
|
|
1053
1112
|
const persistedDynamicContext = (await persistedStatePromise) ?? undefined;
|
|
1113
|
+
const proactiveMediaErrorEnv = proactiveMediaError
|
|
1114
|
+
? this.buildMediaError(proactiveMediaError, proactiveAffected)
|
|
1115
|
+
: undefined;
|
|
1054
1116
|
return {
|
|
1055
1117
|
status: "success",
|
|
1056
1118
|
textResponse: parsedIntent.textResponse,
|
|
@@ -1059,6 +1121,7 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1059
1121
|
imageMediaId: finalImageMediaId,
|
|
1060
1122
|
stateUpdate: parsedIntent.stateUpdate,
|
|
1061
1123
|
persistedDynamicContext,
|
|
1124
|
+
mediaError: proactiveMediaErrorEnv,
|
|
1062
1125
|
};
|
|
1063
1126
|
}
|
|
1064
1127
|
catch (error) {
|
package/dist/types.d.ts
CHANGED
|
@@ -72,6 +72,11 @@ export interface ProactiveResponse {
|
|
|
72
72
|
stateUpdate?: DispatcherIntent["stateUpdate"];
|
|
73
73
|
/** Server-authoritative post-write snapshot (see PersistedDynamicContext). */
|
|
74
74
|
persistedDynamicContext?: PersistedDynamicContext;
|
|
75
|
+
/** Partial-failure descriptor: text was generated successfully but one or
|
|
76
|
+
* more media calls (image/voice) failed. Surfaced in-band so the caller
|
|
77
|
+
* can still render the text reply and explain the missing media
|
|
78
|
+
* without losing the conversation. See [InteractMediaError]. */
|
|
79
|
+
mediaError?: InteractMediaError;
|
|
75
80
|
error?: string;
|
|
76
81
|
}
|
|
77
82
|
export interface InteractParams {
|
|
@@ -134,8 +139,30 @@ export interface InteractResponse {
|
|
|
134
139
|
isEndTurn?: boolean;
|
|
135
140
|
/** Server-authoritative post-write snapshot (see PersistedDynamicContext). */
|
|
136
141
|
persistedDynamicContext?: PersistedDynamicContext;
|
|
142
|
+
/** Partial-failure descriptor: text was generated successfully but one or
|
|
143
|
+
* more media calls (image/voice) failed. Surfaced in-band so the caller
|
|
144
|
+
* can still render the text reply and explain the missing media
|
|
145
|
+
* without losing the conversation. See [InteractMediaError]. */
|
|
146
|
+
mediaError?: InteractMediaError;
|
|
137
147
|
error?: string;
|
|
138
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Describes a partial-failure during an [interact] / [proactiveInteract]
|
|
151
|
+
* call: the text reply was generated and returned, but image and/or
|
|
152
|
+
* voice generation failed (usually because the user ran out of points
|
|
153
|
+
* mid-turn). Surfaced in-band on the success envelope so callers can
|
|
154
|
+
* render the text response without losing it to an exception.
|
|
155
|
+
*/
|
|
156
|
+
export interface InteractMediaError {
|
|
157
|
+
/** Coarse kind so UIs can map to a single user-facing message. */
|
|
158
|
+
kind: "insufficient-points" | "wallet" | "unknown";
|
|
159
|
+
/** Backend machine code when available (e.g. "INSUFFICIENT_POINTS"). */
|
|
160
|
+
code?: string;
|
|
161
|
+
/** Raw error message, for logs / diagnostics. */
|
|
162
|
+
message?: string;
|
|
163
|
+
/** Which media generation calls were affected. */
|
|
164
|
+
affected: Array<"image" | "voice">;
|
|
165
|
+
}
|
|
139
166
|
export interface OngoingSceneState {
|
|
140
167
|
scene: string;
|
|
141
168
|
outfit: string;
|