@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.
Files changed (2) hide show
  1. package/dist/client.js +22 -21
  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
  }
@@ -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, params.localContext)}
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 USER MESSAGE only.
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 explicit, set userAnalysis to null.
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 USER MESSAGE" }] },
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: transcript +
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, params.interactParams?.localContext)}
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?.history, state);
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, params.localContext, true);
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, params.interactParams?.localContext)}
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, params.interactParams?.localContext)}
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:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@space3-npm/cybersoul-client",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",