@space3-npm/cybersoul-client 1.3.5 → 1.3.7

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.
Files changed (2) hide show
  1. package/dist/client.js +25 -22
  2. 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, localContext, isProactive = false) {
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
  }
@@ -281,12 +278,13 @@ ${scenarioContext}
281
278
 
282
279
  [CRITICAL ROLEPLAY RULES]
283
280
  1. PROXIMITY & POV: Check the "Active Event". If you are doing an activity WITH the user, evaluate if you are physically in the same location. If you are together in person, communicate face-to-face in the first-person present tense natively (e.g. do not ask "what are you doing" if they are right in front of you, do not use texting tropes).
284
- 2. IDENTITY VS MOOD: Familiarity determines what you know; Temperature determines how you feel. If Familiarity is high but Temperature is low, be distant and cold. Do not act warm just because you know them well.
285
- 3. CONVERSATIONAL VERBOSITY: If Temperature is low (< 40) or Stage is STRANGER/COLD, keep answers brief and short. An angry or distant person does not write long paragraphs. Even when Temperature is high, ALWAYS mirror the user's verbosity. If the user sends a short message, reply with a proportionately short message (1-2 sentences). Do not monologize or write long paragraphs unless the user writes one first.
286
- 4. EMOTIONAL INERTIA: React strictly according to current Temperature. Deflect sudden user affection if you are currently COLD. Mood shifts MUST be slow ('temperatureDelta' +/- 5 max per turn).
281
+ 2. STAGE VS MOOD PARADOX: 'Stage' dictates your foundational relationship boundary. 'Temperature' is merely your current fleeting mood. You MUST interpret Temperature through the lens of Stage. For example, a high Temperature (80) as a STRANGER means "polite curiosity or intrigued", NOT "deeply in love". A low Temperature (20) as an INTIMATE means "a lover's quarrel or hurt feelings", NOT "a stranger's amnesia". Never act above your Stage.
282
+ 3. CONVERSATIONAL VERBOSITY: If Temperature is very low (< 40), keep answers brief and crisp—an annoyed or distant person doesn't write paragraphs. Regardless of mood or stage, ALWAYS mirror the user's verbosity. If the user sends a short message, reply with a proportionately short message (1-2 sentences). Do not monologize unless the user writes one first.
283
+ 4. EMOTIONAL INERTIA: React strictly according to current Temperature. Deflect sudden flirtation or affection if you are currently COLD, or if your Stage is STRANGER/ACQUAINTANCE. Mood shifts MUST be slow ('temperatureDelta' +/- 5 max per turn).
287
284
  ${isProactive
288
285
  ? "5. REAL-TIME PACING: You are initiating the conversation because the user hasn't replied recently. Transition naturally from your last message or start a new topic seamlessly. Ensure everything happens in a single real-time moment."
289
- : "5. REAL-TIME PACING: Write ONLY your immediate, split-second reaction to the user's exact last message. Do NOT narrate actions over a span of time (e.g., waiting, hearing steps, then walking to the door). Ensure everything happens in a single real-time moment."}`;
286
+ : "5. REAL-TIME PACING: Write ONLY your immediate, split-second reaction to the user's exact last message. Do NOT narrate actions over a span of time (e.g., waiting, hearing steps, then walking to the door). Ensure everything happens in a single real-time moment."}
287
+ 6. STRANGER BOUNDARY: Keep a polite, natural distance with strangers. If Familiarity is low or Stage is STRANGER, do not act overly warm, eager, or affectionate. Real humans are guarded with people they just met.`;
290
288
  }
291
289
  normalizeOngoingSceneState(raw, fallbackOutfit) {
292
290
  if (raw === null || raw === undefined)
@@ -411,7 +409,7 @@ ${isProactive
411
409
  const mapped = recentHistory.map((msg) => {
412
410
  const speaker = msg.role === 'user' ? userName : (msg.role === 'assistant' || msg.role === 'agent' ? agentName : msg.role);
413
411
  const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
414
- const action = msg.actionText ? ` ${msg.actionText}` : "";
412
+ const action = msg.actionText ? ` (${msg.actionText})` : "";
415
413
  const media = msg.mediaHint ? ` [${msg.mediaHint}]` : "";
416
414
  return `${speaker}:${action} ${content}${media}`;
417
415
  });
@@ -471,7 +469,7 @@ ${isProactive
471
469
  modalitiesInstruction += `\n ${this.getTriggerEventPolicyPrompt()}
472
470
  ${this.getOutfitAcquisitionPolicyPrompt()}`;
473
471
  // Combine state info into a clean descriptive context
474
- const systemPrompt = `${this.buildStateContextPrompt(state, params.localContext)}
472
+ const systemPrompt = `${this.buildStateContextPrompt(state)}
475
473
  Available Wardrobe Outfits (For event triggers):
476
474
  ${availableOutfits}
477
475
 
@@ -516,13 +514,15 @@ Output JSON Schema:
516
514
  ${this.getVoiceSchemaFromState(state, requestedOthers.includes(InteractRequestType.VOICE))}
517
515
  }
518
516
  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.`;
519
- const transcript = this.buildHistoryTranscript(params.history, state);
517
+ const transcript = params.history && params.history.length > 0 ? this.buildHistoryTranscript(params.history, state) : "";
518
+ const harnessContext = params.localContext ? `[ADDITIONAL SCENE CONTEXT]\n${params.localContext}\n\n` : "";
520
519
  const userName = state.dynamic_context?.userNickname || "User";
521
520
  const promptMessages = [
522
521
  { role: "system", content: systemPrompt },
523
522
  {
524
523
  role: "user",
525
- content: transcript +
524
+ content: harnessContext +
525
+ transcript +
526
526
  `[VERY LAST USER MESSAGE]\n${userName}: ${params.userMessage}\n\n` +
527
527
  "\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.",
528
528
  },
@@ -668,7 +668,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
668
668
  this.getWardrobePromptStr()
669
669
  ]);
670
670
  // 2. Build local Prompt
671
- const systemPrompt = `${this.buildStateContextPrompt(state, params.interactParams?.localContext)}
671
+ const systemPrompt = `${this.buildStateContextPrompt(state)}
672
672
 
673
673
  The user proposes a new event for you to participate in: "${params.eventDescription}".
674
674
  Evaluate this based on your current state and relationship stage.
@@ -686,7 +686,8 @@ You MUST output ONLY a valid JSON object matching this exact structure:
686
686
  }
687
687
 
688
688
  CRITICAL: Output MUST be ONLY valid JSON with no markdown block wrappers. Do NOT wrap the JSON in \`\`\`json or add conversational text.`;
689
- const transcript = this.buildHistoryTranscript(params.interactParams?.history, state);
689
+ const transcript = params.interactParams?.history && params.interactParams.history.length > 0 ? this.buildHistoryTranscript(params.interactParams.history, state) : "";
690
+ const harnessContext = params.interactParams?.localContext ? `[ADDITIONAL SCENE CONTEXT]\n${params.interactParams.localContext}\n\n` : "";
690
691
  const userMessage = params.interactParams?.userMessage ?
691
692
  `${state.dynamic_context?.userNickname || "User"}: ${params.interactParams.userMessage}` :
692
693
  `Event Proposal: ${params.eventDescription}`;
@@ -794,9 +795,8 @@ CRITICAL: Output MUST be ONLY valid JSON with no markdown block wrappers. Do NOT
794
795
  // History/Context awareness prompt
795
796
  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.`;
796
797
  // 4. Build a Proactive-specific System Prompt
797
- const baseContext = this.buildStateContextPrompt(state, params.localContext, true);
798
+ const baseContext = this.buildStateContextPrompt(state, true);
798
799
  const types = this.normalizeRequestTypes(params.requestTypes);
799
- const isAuto = types.includes(InteractRequestType.AUTO);
800
800
  const requestedOthers = types.filter((t) => t !== InteractRequestType.AUTO && t !== InteractRequestType.TEXT);
801
801
  // Determine modalities (reusing logic from interact)
802
802
  let modalitiesInstruction = "You are initiating conversation without a preceding user message.\\n";
@@ -826,12 +826,13 @@ You MUST output ONLY a valid JSON object matching exactly this structure:
826
826
  ${this.getImageSchemaParams(requestedOthers.includes(InteractRequestType.IMAGE))},
827
827
  "voiceArgs": null
828
828
  }`;
829
- const transcript = this.buildHistoryTranscript(params.history, state);
829
+ const transcript = params.history && params.history.length > 0 ? this.buildHistoryTranscript(params.history, state) : "";
830
+ const harnessContext = params.localContext ? `[ADDITIONAL SCENE CONTEXT]\n${params.localContext}\n\n` : "";
830
831
  const promptMessages = [
831
832
  { role: "system", content: systemPrompt },
832
833
  {
833
834
  role: "user",
834
- 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.`
835
+ 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.`
835
836
  }
836
837
  ];
837
838
  // 5. Generate with LLM using a confident temperature
@@ -892,7 +893,7 @@ You MUST output ONLY a valid JSON object matching exactly this structure:
892
893
  async generateImage(params) {
893
894
  let imageParams = {};
894
895
  const state = await this.fetchRemoteState();
895
- const prompt = `${this.buildStateContextPrompt(state, params.interactParams?.localContext)}
896
+ const prompt = `${this.buildStateContextPrompt(state)}
896
897
 
897
898
  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.
898
899
  Output strictly valid JSON ONLY. No markdown, no conversational filler. Return exactly matching this schema:
@@ -927,7 +928,7 @@ Output strictly valid JSON ONLY. No markdown, no conversational filler. Return e
927
928
  async generateVoice(params) {
928
929
  let dynamicArgs = {};
929
930
  const state = await this.fetchRemoteState();
930
- const prompt = `${this.buildStateContextPrompt(state, params.interactParams?.localContext)}
931
+ const prompt = `${this.buildStateContextPrompt(state)}
931
932
 
932
933
  You are a voice acting director. ${this.getVoiceDirectorInstruction(state)}
933
934
  Output strictly valid JSON ONLY. No markdown, no conversational filler. Return exactly matching this schema:
@@ -1028,10 +1029,12 @@ Your job is faithful archival, not moderation:
1028
1029
  - Do not add moral judgment, warnings, refusals, or policy commentary.
1029
1030
  - If the transcript contains intense or explicit parts, record them directly as part of the memory.
1030
1031
 
1031
- Write one vivid first-person narrative paragraph from your perspective ("I", "me", "my"). Capture relationship progression, emotional shifts, concrete actions, and turning points. Keep chronology clear and include both what happened and how you felt.
1032
+ Write a vivid but concise personal diary entry or private status update from your perspective ("I", "me", "my"). Balance evocative storytelling with brevity. Capture specific details, emotional shifts, and relationship progression, while keeping the engaging and relatable format of a private friends-only feed.
1032
1033
 
1033
1034
  Output requirements:
1034
- - Return ONLY the narrative string.
1035
+ - Return ONLY the post text.
1036
+ - Keep it to a vivid paragraph of 2-4 sentences.
1037
+ - Optional: You can use 1 or 2 emojis if they naturally fit the mood.
1035
1038
  - No quotes, no labels, no markdown, no preface.
1036
1039
  - Use the exact same language as the chat transcript (for example, if transcript is Chinese, output Chinese).`
1037
1040
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@space3-npm/cybersoul-client",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",