@space3-npm/cybersoul-client 1.4.23 → 1.4.24
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 +13 -1
- package/dist/client.js +73 -2
- package/dist/types.d.ts +42 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -83,6 +83,15 @@ export declare class CyberSoulClient {
|
|
|
83
83
|
* reply is already in flight.
|
|
84
84
|
*/
|
|
85
85
|
private buildMediaError;
|
|
86
|
+
/**
|
|
87
|
+
* Shared giftOutfit handler for `interact()` / `proactiveInteract()`.
|
|
88
|
+
* Validates the LLM's `giftOutfit` intent, performs the wardrobe write,
|
|
89
|
+
* fires the `onOutfitGifted` callback, and resolves to the
|
|
90
|
+
* [OutfitGiftedPayload] (or `undefined` when there was nothing to gift
|
|
91
|
+
* or the write failed). Failures are swallowed (logged) so a wardrobe
|
|
92
|
+
* hiccup never aborts the chat turn.
|
|
93
|
+
*/
|
|
94
|
+
private processGiftOutfit;
|
|
86
95
|
private formatHistoryEntries;
|
|
87
96
|
private buildHistoryTranscript;
|
|
88
97
|
interact(params: InteractParams): Promise<InteractResponse>;
|
|
@@ -144,8 +153,11 @@ export declare class CyberSoulClient {
|
|
|
144
153
|
updateDynamicContext(stateUpdate: DispatcherIntent["stateUpdate"], userAnalysis?: DispatcherIntent["userAnalysis"]): Promise<PersistedDynamicContext | null>;
|
|
145
154
|
/**
|
|
146
155
|
* Gift a new outfit to the character's wardrobe inventory.
|
|
156
|
+
* Returns the number of wardrobe items the backend created (the
|
|
157
|
+
* backend may expand a single description into multiple items), or
|
|
158
|
+
* `undefined` when the server did not report a count.
|
|
147
159
|
*/
|
|
148
|
-
giftOutfit(descriptionText: string): Promise<
|
|
160
|
+
giftOutfit(descriptionText: string): Promise<number | undefined>;
|
|
149
161
|
/**
|
|
150
162
|
* Bootstrap character profile from OpenClaw workspace files.
|
|
151
163
|
*/
|
package/dist/client.js
CHANGED
|
@@ -482,7 +482,10 @@ ${isProactive
|
|
|
482
482
|
return `- Include 'triggerEvent' only if the VERY LAST USER MESSAGE proposes a new activity/hangout AND you accept the invitation, explicitly requests an outfit change AND you agree, or proposes intimate/romantic actions AND you agree; ignore older history. DO NOT include it if you decline or reject the proposal. ${this.getOutfitSelectionPrompt()}`;
|
|
483
483
|
}
|
|
484
484
|
getOutfitAcquisitionPolicyPrompt() {
|
|
485
|
-
return `- Outfit acquisition (
|
|
485
|
+
return `- Outfit acquisition (giftOutfit): set 'giftOutfit' to { "descriptionText": "short outfit description" } when a genuinely NEW outfit (one that is NOT already in the Available Wardrobe) is obtained THIS turn, triggered by EITHER:
|
|
486
|
+
(a) USER-GIFTED: the VERY LAST USER MESSAGE expresses gift/buy/add-clothes intent for you (e.g. "I bought you a dress", "here, wear this new outfit", "adding some lingerie to your closet").
|
|
487
|
+
(b) CHARACTER-ACQUIRED: the conversation or active event naturally leads YOU to acquire a new outfit you don't already own (e.g. you went shopping, received/made clothes, or the scene requires changing into a brand-new outfit that is absent from your Available Wardrobe).
|
|
488
|
+
Keep 'descriptionText' to a concise English-or-matching-language description of the single new outfit. Otherwise set 'giftOutfit' to null. Do NOT fire it for outfits already present in the Available Wardrobe, and do NOT fire it just because you changed into an existing outfit.`;
|
|
486
489
|
}
|
|
487
490
|
getEventSchemaParams(userName) {
|
|
488
491
|
const name = userName || "the user";
|
|
@@ -607,6 +610,45 @@ ${isProactive
|
|
|
607
610
|
affected,
|
|
608
611
|
};
|
|
609
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* Shared giftOutfit handler for `interact()` / `proactiveInteract()`.
|
|
615
|
+
* Validates the LLM's `giftOutfit` intent, performs the wardrobe write,
|
|
616
|
+
* fires the `onOutfitGifted` callback, and resolves to the
|
|
617
|
+
* [OutfitGiftedPayload] (or `undefined` when there was nothing to gift
|
|
618
|
+
* or the write failed). Failures are swallowed (logged) so a wardrobe
|
|
619
|
+
* hiccup never aborts the chat turn.
|
|
620
|
+
*/
|
|
621
|
+
async processGiftOutfit(giftOutfitIntent, onOutfitGifted) {
|
|
622
|
+
if (!giftOutfitIntent ||
|
|
623
|
+
typeof giftOutfitIntent !== "object" ||
|
|
624
|
+
typeof giftOutfitIntent.descriptionText !== "string" ||
|
|
625
|
+
giftOutfitIntent.descriptionText.trim().length === 0) {
|
|
626
|
+
return undefined;
|
|
627
|
+
}
|
|
628
|
+
const outfitDescription = giftOutfitIntent.descriptionText.trim();
|
|
629
|
+
try {
|
|
630
|
+
const count = await this.giftOutfit(outfitDescription);
|
|
631
|
+
const giftedOutfit = {
|
|
632
|
+
descriptionText: outfitDescription,
|
|
633
|
+
};
|
|
634
|
+
if (typeof count === "number") {
|
|
635
|
+
giftedOutfit.count = count;
|
|
636
|
+
}
|
|
637
|
+
if (onOutfitGifted) {
|
|
638
|
+
try {
|
|
639
|
+
onOutfitGifted(giftedOutfit);
|
|
640
|
+
}
|
|
641
|
+
catch (cbErr) {
|
|
642
|
+
console.warn("[CyberSoulClient] onOutfitGifted callback threw:", cbErr);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return giftedOutfit;
|
|
646
|
+
}
|
|
647
|
+
catch (e) {
|
|
648
|
+
console.error("[CyberSoulClient] giftOutfit failed:", e);
|
|
649
|
+
return undefined;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
610
652
|
formatHistoryEntries(history, userName, agentName, promptDirective = "") {
|
|
611
653
|
const contextLines = [];
|
|
612
654
|
for (let i = 0; i < history.length; i++) {
|
|
@@ -846,6 +888,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
846
888
|
let finalAudioUrl = undefined;
|
|
847
889
|
let finalAudioMediaId = undefined;
|
|
848
890
|
let finalDurationSec = undefined;
|
|
891
|
+
let giftedOutfit = undefined;
|
|
849
892
|
// Partial-failure capture: text was already produced and emitted
|
|
850
893
|
// via [onTextReady], so a wallet / insufficient-points failure on
|
|
851
894
|
// image or voice MUST NOT abort the whole turn. We collect the
|
|
@@ -886,7 +929,10 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
886
929
|
typeof parsedIntent.giftOutfit === "object" &&
|
|
887
930
|
typeof parsedIntent.giftOutfit.descriptionText === "string" &&
|
|
888
931
|
parsedIntent.giftOutfit.descriptionText.trim().length > 0) {
|
|
889
|
-
mediaTasks.push(this.
|
|
932
|
+
mediaTasks.push(this.processGiftOutfit(parsedIntent.giftOutfit, params.onOutfitGifted).then((result) => {
|
|
933
|
+
if (result)
|
|
934
|
+
giftedOutfit = result;
|
|
935
|
+
}));
|
|
890
936
|
}
|
|
891
937
|
const shouldGenerateImage = types.includes(InteractRequestType.IMAGE) &&
|
|
892
938
|
(!isAuto || !!parsedIntent.imageParams);
|
|
@@ -989,6 +1035,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
989
1035
|
isEndTurn: parsedIntent.isEndTurn,
|
|
990
1036
|
persistedDynamicContext,
|
|
991
1037
|
mediaError,
|
|
1038
|
+
giftedOutfit,
|
|
992
1039
|
};
|
|
993
1040
|
}
|
|
994
1041
|
catch (error) {
|
|
@@ -1190,6 +1237,7 @@ Modalities:
|
|
|
1190
1237
|
? "'imageParams' may be included only if sending a photo right now would feel natural for this character in this relationship — otherwise set null. Do not attach a photo just because you can."
|
|
1191
1238
|
: "ALWAYS set 'imageParams' to null."}
|
|
1192
1239
|
- ALWAYS set 'voiceArgs' to null.
|
|
1240
|
+
${this.getOutfitAcquisitionPolicyPrompt()}
|
|
1193
1241
|
|
|
1194
1242
|
Output ONLY a valid JSON object matching exactly this structure (no markdown wrappers).
|
|
1195
1243
|
If "shouldSkipProactive" is true, set "skipReason" to one short sentence and set every other field to null.
|
|
@@ -1200,6 +1248,7 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1200
1248
|
"actionText": "(Scene descriptions, physical actions, expressions, inner feelings) ONLY.",
|
|
1201
1249
|
"textResponse": "Spoken dialogue ONLY.",
|
|
1202
1250
|
"stateUpdate": { "temperatureDelta": 0, "ongoingScene": { "scene": "...", "outfit": "..." } },
|
|
1251
|
+
"giftOutfit": { "descriptionText": "Concise description of the newly acquired outfit to add into wardrobe." },
|
|
1203
1252
|
${this.getImageSchemaParams(imageAllowed)},
|
|
1204
1253
|
"voiceArgs": null
|
|
1205
1254
|
}`;
|
|
@@ -1265,6 +1314,11 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1265
1314
|
stateUpdate: parsedIntent.stateUpdate,
|
|
1266
1315
|
});
|
|
1267
1316
|
}
|
|
1317
|
+
// Outfit acquisition: the character may decide, on its own, to pick
|
|
1318
|
+
// up a brand-new outfit while reaching out. Fire-and-capture in
|
|
1319
|
+
// parallel with image generation; surface it via callback + the
|
|
1320
|
+
// final response so upstream can show "New outfit added".
|
|
1321
|
+
const giftOutfitPromise = this.processGiftOutfit(parsedIntent.giftOutfit, params.onOutfitGifted);
|
|
1268
1322
|
let finalImageUrl;
|
|
1269
1323
|
let finalImageMediaId;
|
|
1270
1324
|
let proactiveMediaError = null;
|
|
@@ -1300,6 +1354,7 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1300
1354
|
}
|
|
1301
1355
|
}
|
|
1302
1356
|
const persistedDynamicContext = (await persistedStatePromise) ?? undefined;
|
|
1357
|
+
const giftedOutfit = (await giftOutfitPromise) ?? undefined;
|
|
1303
1358
|
const proactiveMediaErrorEnv = proactiveMediaError
|
|
1304
1359
|
? this.buildMediaError(proactiveMediaError, proactiveAffected)
|
|
1305
1360
|
: undefined;
|
|
@@ -1312,6 +1367,7 @@ If "shouldSkipProactive" is false, "textResponse" is required and "stateUpdate"
|
|
|
1312
1367
|
stateUpdate: parsedIntent.stateUpdate,
|
|
1313
1368
|
persistedDynamicContext,
|
|
1314
1369
|
mediaError: proactiveMediaErrorEnv,
|
|
1370
|
+
giftedOutfit,
|
|
1315
1371
|
};
|
|
1316
1372
|
}
|
|
1317
1373
|
catch (error) {
|
|
@@ -1435,6 +1491,9 @@ Output strictly valid JSON ONLY. No markdown, no conversational filler. Return e
|
|
|
1435
1491
|
}
|
|
1436
1492
|
/**
|
|
1437
1493
|
* Gift a new outfit to the character's wardrobe inventory.
|
|
1494
|
+
* Returns the number of wardrobe items the backend created (the
|
|
1495
|
+
* backend may expand a single description into multiple items), or
|
|
1496
|
+
* `undefined` when the server did not report a count.
|
|
1438
1497
|
*/
|
|
1439
1498
|
async giftOutfit(descriptionText) {
|
|
1440
1499
|
const res = await this.apiFetch("/api/v1/cyber-soul/characters/gift-outfit", {
|
|
@@ -1443,6 +1502,18 @@ Output strictly valid JSON ONLY. No markdown, no conversational filler. Return e
|
|
|
1443
1502
|
});
|
|
1444
1503
|
if (!res.ok)
|
|
1445
1504
|
throw new Error("Failed to gift outfit");
|
|
1505
|
+
try {
|
|
1506
|
+
const body = (await res.json());
|
|
1507
|
+
return typeof body.count === "number" && Number.isFinite(body.count)
|
|
1508
|
+
? body.count
|
|
1509
|
+
: undefined;
|
|
1510
|
+
}
|
|
1511
|
+
catch {
|
|
1512
|
+
// The gift already succeeded server-side (res.ok); a missing/
|
|
1513
|
+
// unparseable count is non-fatal — report "unknown" rather than
|
|
1514
|
+
// fabricating a number.
|
|
1515
|
+
return undefined;
|
|
1516
|
+
}
|
|
1446
1517
|
}
|
|
1447
1518
|
/**
|
|
1448
1519
|
* Bootstrap character profile from OpenClaw workspace files.
|
package/dist/types.d.ts
CHANGED
|
@@ -80,6 +80,26 @@ export interface MediaReadyPayload {
|
|
|
80
80
|
/** Voice only — TTS duration in seconds when known. */
|
|
81
81
|
durationSec?: number;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Payload delivered by [InteractParams.onOutfitGifted] /
|
|
85
|
+
* [ProactiveParams.onOutfitGifted] when a new outfit is successfully
|
|
86
|
+
* added to the character's wardrobe during a turn. Fires for BOTH
|
|
87
|
+
* trigger paths: (a) the user explicitly gifts/buys an outfit, and
|
|
88
|
+
* (b) the conversation or an active event leads the character to
|
|
89
|
+
* acquire a brand-new outfit. Lets upstream consumers (e.g.
|
|
90
|
+
* cybersoul-chat) render a system message like
|
|
91
|
+
* "New outfit added to wardrobe".
|
|
92
|
+
*/
|
|
93
|
+
export interface OutfitGiftedPayload {
|
|
94
|
+
/** Human-readable description of the newly acquired outfit. */
|
|
95
|
+
descriptionText: string;
|
|
96
|
+
/**
|
|
97
|
+
* Number of wardrobe items the backend created for this gift, when
|
|
98
|
+
* the server reported it. Omitted when the count is unknown — never
|
|
99
|
+
* fabricated.
|
|
100
|
+
*/
|
|
101
|
+
count?: number;
|
|
102
|
+
}
|
|
83
103
|
export interface ProactiveParams {
|
|
84
104
|
history?: HistoryEntry[];
|
|
85
105
|
maxUnreplied?: number;
|
|
@@ -95,6 +115,13 @@ export interface ProactiveParams {
|
|
|
95
115
|
onStateReady?: (persisted: PersistedDynamicContext) => void;
|
|
96
116
|
/** Fires per modality as each media task settles successfully. */
|
|
97
117
|
onMediaReady?: (payload: MediaReadyPayload) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Fires when an outfit has been successfully added to the wardrobe
|
|
120
|
+
* during this turn (user-initiated gift OR character-initiated
|
|
121
|
+
* acquisition). Lets the UI render a system message like
|
|
122
|
+
* "New outfit added to wardrobe" in real time.
|
|
123
|
+
*/
|
|
124
|
+
onOutfitGifted?: (payload: OutfitGiftedPayload) => void;
|
|
98
125
|
}
|
|
99
126
|
export interface ProactiveResponse {
|
|
100
127
|
status: "success" | "skipped" | "error";
|
|
@@ -113,6 +140,10 @@ export interface ProactiveResponse {
|
|
|
113
140
|
* can still render the text reply and explain the missing media
|
|
114
141
|
* without losing the conversation. See [InteractMediaError]. */
|
|
115
142
|
mediaError?: InteractMediaError;
|
|
143
|
+
/** Set when an outfit was successfully added to the wardrobe this turn.
|
|
144
|
+
* Mirrors the [ProactiveParams.onOutfitGifted] callback for consumers
|
|
145
|
+
* that only read the final response. See [OutfitGiftedPayload]. */
|
|
146
|
+
giftedOutfit?: OutfitGiftedPayload;
|
|
116
147
|
error?: string;
|
|
117
148
|
}
|
|
118
149
|
export interface InteractParams {
|
|
@@ -132,6 +163,13 @@ export interface InteractParams {
|
|
|
132
163
|
onStateReady?: (persisted: PersistedDynamicContext) => void;
|
|
133
164
|
/** Fires per modality as each media task settles successfully. */
|
|
134
165
|
onMediaReady?: (payload: MediaReadyPayload) => void;
|
|
166
|
+
/**
|
|
167
|
+
* Fires when an outfit has been successfully added to the wardrobe
|
|
168
|
+
* during this turn (user-initiated gift OR character-initiated
|
|
169
|
+
* acquisition). Lets the UI render a system message like
|
|
170
|
+
* "New outfit added to wardrobe" in real time.
|
|
171
|
+
*/
|
|
172
|
+
onOutfitGifted?: (payload: OutfitGiftedPayload) => void;
|
|
135
173
|
}
|
|
136
174
|
export interface OndemandEventParams {
|
|
137
175
|
eventDescription: string;
|
|
@@ -173,6 +211,10 @@ export interface InteractResponse {
|
|
|
173
211
|
imageMediaId?: string;
|
|
174
212
|
audioUrl?: string;
|
|
175
213
|
audioMediaId?: string;
|
|
214
|
+
/** Set when an outfit was successfully added to the wardrobe this turn.
|
|
215
|
+
* Mirrors the [InteractParams.onOutfitGifted] callback for consumers
|
|
216
|
+
* that only read the final response. See [OutfitGiftedPayload]. */
|
|
217
|
+
giftedOutfit?: OutfitGiftedPayload;
|
|
176
218
|
likePreviousPicture?: boolean;
|
|
177
219
|
durationSec?: number;
|
|
178
220
|
triggeredEvent?: {
|