@space3-npm/cybersoul-client 1.3.4 → 1.3.6
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 +22 -21
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -154,7 +154,7 @@ export class CyberSoulClient {
|
|
|
154
154
|
}
|
|
155
155
|
return normalized;
|
|
156
156
|
}
|
|
157
|
-
buildStateContextPrompt(state,
|
|
157
|
+
buildStateContextPrompt(state, isProactive = false) {
|
|
158
158
|
const dyn = state.dynamic_context || {};
|
|
159
159
|
const stage = state.relationship_stage || "NEUTRAL";
|
|
160
160
|
const temperature = dyn.temperature ?? 50;
|
|
@@ -210,9 +210,6 @@ Current time: ${new Date(currentTimeMs).toLocaleString("zh-CN", { timeZone: "Asi
|
|
|
210
210
|
if (state.active_event) {
|
|
211
211
|
contextParts.push(`Active Event: ${state.active_event.title} (${state.active_event.narrative_context})`);
|
|
212
212
|
}
|
|
213
|
-
if (localContext) {
|
|
214
|
-
contextParts.push(`Additional Context: ${localContext}`);
|
|
215
|
-
}
|
|
216
213
|
if (state.next_event) {
|
|
217
214
|
contextParts.push(`Next Event: ${state.next_event.title} at ${state.next_event.start_time} (in ${state.next_event.time_until_mins} mins)`);
|
|
218
215
|
}
|
|
@@ -411,7 +408,7 @@ ${isProactive
|
|
|
411
408
|
const mapped = recentHistory.map((msg) => {
|
|
412
409
|
const speaker = msg.role === 'user' ? userName : (msg.role === 'assistant' || msg.role === 'agent' ? agentName : msg.role);
|
|
413
410
|
const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
414
|
-
const action = msg.actionText ? ` ${msg.actionText}` : "";
|
|
411
|
+
const action = msg.actionText ? ` (${msg.actionText})` : "";
|
|
415
412
|
const media = msg.mediaHint ? ` [${msg.mediaHint}]` : "";
|
|
416
413
|
return `${speaker}:${action} ${content}${media}`;
|
|
417
414
|
});
|
|
@@ -471,7 +468,7 @@ ${isProactive
|
|
|
471
468
|
modalitiesInstruction += `\n ${this.getTriggerEventPolicyPrompt()}
|
|
472
469
|
${this.getOutfitAcquisitionPolicyPrompt()}`;
|
|
473
470
|
// Combine state info into a clean descriptive context
|
|
474
|
-
const systemPrompt = `${this.buildStateContextPrompt(state
|
|
471
|
+
const systemPrompt = `${this.buildStateContextPrompt(state)}
|
|
475
472
|
Available Wardrobe Outfits (For event triggers):
|
|
476
473
|
${availableOutfits}
|
|
477
474
|
|
|
@@ -484,14 +481,15 @@ Always return 'stateUpdate.ongoingScene' as an object with both keys: { "scene":
|
|
|
484
481
|
For 'ongoingScene.outfit': decide based on the current active wardrobe by default; switch to a new explicit outfit description only if the scene implies changing clothes; if no clothing is worn, explicitly output "naked".
|
|
485
482
|
|
|
486
483
|
USER ANALYSIS WORKFLOW:
|
|
487
|
-
- Extract from VERY LAST
|
|
484
|
+
- Extract facts ONLY about the HUMAN USER from their VERY LAST MESSAGE.
|
|
485
|
+
- DO NOT extract facts about yourself (the AI character), your own boundaries, or your own preferences.
|
|
488
486
|
- Add only explicit new user facts from this turn (no inference).
|
|
489
487
|
- Exclude transient, temporary, or time-sensitive activities (e.g., "I am working on a release today", "I'm eating dinner"). Do not map short-term actions into permanent categories like 'occupation' or 'hobby'.
|
|
490
|
-
- For 'preference', only capture explicit statements (e.g., "I like/love/dislike/hate...").
|
|
491
|
-
- For 'boundary', only capture explicit rejections or limitations (e.g., "Don't talk about X", "I won't do Y").
|
|
488
|
+
- For 'preference', only capture explicit statements the user makes about what THEY like (e.g., "I like/love/dislike/hate...").
|
|
489
|
+
- For 'boundary', only capture explicit rejections or limitations from the user (e.g., "Don't talk about X to me", "I won't do Y"). DO NOT record your own character boundaries here.
|
|
492
490
|
- Categories: 'realName', 'occupation', 'age', 'gender', 'hobby', 'trait', 'communicationStyle', 'boundary', 'preference'.
|
|
493
491
|
- Keep nicknames in stateUpdate; do not place them in newFactsLearned.
|
|
494
|
-
- If no new fact is
|
|
492
|
+
- If no new explicit fact about the human user is learned, set userAnalysis to null.
|
|
495
493
|
|
|
496
494
|
For 'isEndTurn', use true only when the interaction naturally concludes (confirmation/bye, event ending, or clear hard scene shift); otherwise false.
|
|
497
495
|
|
|
@@ -506,7 +504,7 @@ Output JSON Schema:
|
|
|
506
504
|
"likePreviousPicture": false,
|
|
507
505
|
"stateUpdate": { "temperatureDelta": 1, "userNickname": "How character addresses user", "agentNickname": "How user addresses character", "talkingStyle": "Current speaking style", "ongoingScene": { "scene": "Current physical scene/activity", "outfit": "Current outfit wording; use 'naked' when applicable" } },
|
|
508
506
|
"giftOutfit": { "descriptionText": "Concise description of the newly acquired outfit to add into wardrobe." },
|
|
509
|
-
"userAnalysis": { "newFactsLearned": [{ "category": "realName|occupation|age|gender|hobby|trait|communicationStyle|boundary|preference", "value": "explicit new user fact from VERY LAST
|
|
507
|
+
"userAnalysis": { "newFactsLearned": [{ "category": "realName|occupation|age|gender|hobby|trait|communicationStyle|boundary|preference", "value": "explicit new user fact about the human from THEIR VERY LAST MESSAGE" }] },
|
|
510
508
|
"isEndTurn": false,
|
|
511
509
|
"triggerEvent": {
|
|
512
510
|
${this.getEventSchemaParams(state.dynamic_context?.userNickname)}
|
|
@@ -515,13 +513,15 @@ Output JSON Schema:
|
|
|
515
513
|
${this.getVoiceSchemaFromState(state, requestedOthers.includes(InteractRequestType.VOICE))}
|
|
516
514
|
}
|
|
517
515
|
Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent", "giftOutfit", or "userAnalysis" are not needed, set them to null. "stateUpdate" cannot be null. Return valid raw JSON only.`;
|
|
518
|
-
const transcript = this.buildHistoryTranscript(params.history, state);
|
|
516
|
+
const transcript = params.history && params.history.length > 0 ? this.buildHistoryTranscript(params.history, state) : "";
|
|
517
|
+
const harnessContext = params.localContext ? `[ADDITIONAL SCENE CONTEXT]\n${params.localContext}\n\n` : "";
|
|
519
518
|
const userName = state.dynamic_context?.userNickname || "User";
|
|
520
519
|
const promptMessages = [
|
|
521
520
|
{ role: "system", content: systemPrompt },
|
|
522
521
|
{
|
|
523
522
|
role: "user",
|
|
524
|
-
content:
|
|
523
|
+
content: harnessContext +
|
|
524
|
+
transcript +
|
|
525
525
|
`[VERY LAST USER MESSAGE]\n${userName}: ${params.userMessage}\n\n` +
|
|
526
526
|
"\n\nReturn only valid JSON matching the schema. Escape newlines inside JSON strings with \\n. Keep imageParams values in ENGLISH and use the provided enums.",
|
|
527
527
|
},
|
|
@@ -667,7 +667,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
667
667
|
this.getWardrobePromptStr()
|
|
668
668
|
]);
|
|
669
669
|
// 2. Build local Prompt
|
|
670
|
-
const systemPrompt = `${this.buildStateContextPrompt(state
|
|
670
|
+
const systemPrompt = `${this.buildStateContextPrompt(state)}
|
|
671
671
|
|
|
672
672
|
The user proposes a new event for you to participate in: "${params.eventDescription}".
|
|
673
673
|
Evaluate this based on your current state and relationship stage.
|
|
@@ -685,7 +685,8 @@ You MUST output ONLY a valid JSON object matching this exact structure:
|
|
|
685
685
|
}
|
|
686
686
|
|
|
687
687
|
CRITICAL: Output MUST be ONLY valid JSON with no markdown block wrappers. Do NOT wrap the JSON in \`\`\`json or add conversational text.`;
|
|
688
|
-
const transcript = this.buildHistoryTranscript(params.interactParams
|
|
688
|
+
const transcript = params.interactParams?.history && params.interactParams.history.length > 0 ? this.buildHistoryTranscript(params.interactParams.history, state) : "";
|
|
689
|
+
const harnessContext = params.interactParams?.localContext ? `[ADDITIONAL SCENE CONTEXT]\n${params.interactParams.localContext}\n\n` : "";
|
|
689
690
|
const userMessage = params.interactParams?.userMessage ?
|
|
690
691
|
`${state.dynamic_context?.userNickname || "User"}: ${params.interactParams.userMessage}` :
|
|
691
692
|
`Event Proposal: ${params.eventDescription}`;
|
|
@@ -793,9 +794,8 @@ CRITICAL: Output MUST be ONLY valid JSON with no markdown block wrappers. Do NOT
|
|
|
793
794
|
// History/Context awareness prompt
|
|
794
795
|
const historyAwarenessPrompt = `CRITICAL CONTEXT AWARENESS: Read the CHAT HISTORY above carefully. Remember that YOU sent the last message. Your new message MUST feel organically connected to the flow of what you two were previously talking about, or naturally bring up a known event/topic from your [CORE MEMORY]. Do not sound like a robot reading a log.`;
|
|
795
796
|
// 4. Build a Proactive-specific System Prompt
|
|
796
|
-
const baseContext = this.buildStateContextPrompt(state,
|
|
797
|
+
const baseContext = this.buildStateContextPrompt(state, true);
|
|
797
798
|
const types = this.normalizeRequestTypes(params.requestTypes);
|
|
798
|
-
const isAuto = types.includes(InteractRequestType.AUTO);
|
|
799
799
|
const requestedOthers = types.filter((t) => t !== InteractRequestType.AUTO && t !== InteractRequestType.TEXT);
|
|
800
800
|
// Determine modalities (reusing logic from interact)
|
|
801
801
|
let modalitiesInstruction = "You are initiating conversation without a preceding user message.\\n";
|
|
@@ -825,12 +825,13 @@ You MUST output ONLY a valid JSON object matching exactly this structure:
|
|
|
825
825
|
${this.getImageSchemaParams(requestedOthers.includes(InteractRequestType.IMAGE))},
|
|
826
826
|
"voiceArgs": null
|
|
827
827
|
}`;
|
|
828
|
-
const transcript = this.buildHistoryTranscript(params.history, state);
|
|
828
|
+
const transcript = params.history && params.history.length > 0 ? this.buildHistoryTranscript(params.history, state) : "";
|
|
829
|
+
const harnessContext = params.localContext ? `[ADDITIONAL SCENE CONTEXT]\n${params.localContext}\n\n` : "";
|
|
829
830
|
const promptMessages = [
|
|
830
831
|
{ role: "system", content: systemPrompt },
|
|
831
832
|
{
|
|
832
833
|
role: "user",
|
|
833
|
-
content: `${transcript}\n[TRIGGER PROACTIVE MESSAGE]\nBased on your active event and environment, send a new message to the user.\n\nCRITICAL: Output ONLY valid JSON matching the schema. DO NOT wrap the JSON in \`\`\`json.`
|
|
834
|
+
content: `${harnessContext}${transcript}\n[TRIGGER PROACTIVE MESSAGE]\nBased on your active event and environment, send a new message to the user.\n\nCRITICAL: Output ONLY valid JSON matching the schema. DO NOT wrap the JSON in \`\`\`json.`
|
|
834
835
|
}
|
|
835
836
|
];
|
|
836
837
|
// 5. Generate with LLM using a confident temperature
|
|
@@ -891,7 +892,7 @@ You MUST output ONLY a valid JSON object matching exactly this structure:
|
|
|
891
892
|
async generateImage(params) {
|
|
892
893
|
let imageParams = {};
|
|
893
894
|
const state = await this.fetchRemoteState();
|
|
894
|
-
const prompt = `${this.buildStateContextPrompt(state
|
|
895
|
+
const prompt = `${this.buildStateContextPrompt(state)}
|
|
895
896
|
|
|
896
897
|
You are an AI image prompt director. Analyze the scene description according to the character's relationship stage and emotional inertia to determine the best image generation parameters.
|
|
897
898
|
Output strictly valid JSON ONLY. No markdown, no conversational filler. Return exactly matching this schema:
|
|
@@ -926,7 +927,7 @@ Output strictly valid JSON ONLY. No markdown, no conversational filler. Return e
|
|
|
926
927
|
async generateVoice(params) {
|
|
927
928
|
let dynamicArgs = {};
|
|
928
929
|
const state = await this.fetchRemoteState();
|
|
929
|
-
const prompt = `${this.buildStateContextPrompt(state
|
|
930
|
+
const prompt = `${this.buildStateContextPrompt(state)}
|
|
930
931
|
|
|
931
932
|
You are a voice acting director. ${this.getVoiceDirectorInstruction(state)}
|
|
932
933
|
Output strictly valid JSON ONLY. No markdown, no conversational filler. Return exactly matching this schema:
|