@space3-npm/cybersoul-client 1.4.19 → 1.4.21

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 +23 -6
  2. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -622,7 +622,7 @@ ${isProactive
622
622
  (b) A genuine NEW visual moment just happened this turn — i.e. a clearly new scene, new location, new outfit, or a distinctly new physical pose/expression that was NOT already shown in any previous turn's image.
623
623
  (c) An active event JUST started or just hit a visually distinct new beat.
624
624
  REPETITION GATE (hard): Prior assistant turns that already carried a picture are tagged with a [Sent Image] marker in '[CHAT HISTORY]'. If at least one prior assistant turn has a [Sent Image] marker AND the current scene/outfit/pose matches the 'Last Known Scene' line (i.e. nothing visually new has happened since), set 'imageParams' to null. Do NOT send near-duplicate pictures just because mood is high — high Temperature is NOT a trigger by itself.
625
- PRIVACY GATE: Even when a trigger fires, if the user feels like a stranger (low Familiarity) AND your Mood/Temperature is cool/distant (< 50), set 'imageParams' to null and naturally decline. Temperature and Familiarity only GATE permission when a trigger has already fired; they never justify an image on their own.
625
+ PRIVACY GATE: Even when a trigger fires, if the user feels like a stranger (low Familiarity) OR your Mood/Temperature is cool/distant (< 50), set 'imageParams' to null and naturally decline. Temperature and Familiarity only GATE permission when a trigger has already fired; they never justify an image on their own.
626
626
  When you do include 'imageParams', explicitly describe current clothing/exposure in the image fields.`;
627
627
  }
628
628
  else {
@@ -1061,23 +1061,40 @@ CRITICAL: Output MUST be ONLY valid JSON with no markdown block wrappers. Do NOT
1061
1061
  */
1062
1062
  async proactiveInteract(params) {
1063
1063
  try {
1064
- // 1. Spam guard (the only hard-coded gate). Counts assistant messages
1065
- // since the last user reply; bails out if the user has clearly
1066
- // stopped responding.
1064
+ // 1. Spam guard (the only hard-coded gate). Counts assistant
1065
+ // *turns* since the last user reply; bails out if the user has
1066
+ // clearly stopped responding.
1067
+ //
1068
+ // A single character response can be emitted as multiple
1069
+ // HistoryEntry rows (one per modality: text + image + voice).
1070
+ // The host typically writes them within seconds of each other.
1071
+ // Counting entries directly would treat one multimodal reply
1072
+ // as 2-3 "unreplied messages" and trip `maxUnreplied = 2` on
1073
+ // the very first proactive attempt. Collapse consecutive
1074
+ // assistant entries whose timestamps are within
1075
+ // SAME_TURN_WINDOW_MS into a single turn before counting.
1067
1076
  const history = params.history || [];
1068
1077
  const maxUnreplied = params.maxUnreplied ?? 2;
1078
+ const SAME_TURN_WINDOW_MS = 60_000;
1069
1079
  let consecutiveProactive = 0;
1080
+ let lastAssistantTs = null;
1070
1081
  for (let i = history.length - 1; i >= 0; i--) {
1071
1082
  const msg = history[i];
1072
1083
  if (msg.role === "user")
1073
1084
  break;
1074
- if (msg.role === "assistant")
1085
+ if (msg.role !== "assistant")
1086
+ continue;
1087
+ const ts = typeof msg.timestamp === "number" ? msg.timestamp : 0;
1088
+ if (lastAssistantTs === null ||
1089
+ Math.abs(lastAssistantTs - ts) > SAME_TURN_WINDOW_MS) {
1075
1090
  consecutiveProactive++;
1091
+ }
1092
+ lastAssistantTs = ts;
1076
1093
  }
1077
1094
  if (consecutiveProactive >= maxUnreplied) {
1078
1095
  return {
1079
1096
  status: "skipped",
1080
- reason: `Spam guard: ${consecutiveProactive} consecutive un-replied messages already sent.`,
1097
+ reason: `Spam guard: ${consecutiveProactive} consecutive un-replied turns already sent.`,
1081
1098
  };
1082
1099
  }
1083
1100
  // 2. Fetch state. baseContext below already includes stage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@space3-npm/cybersoul-client",
3
- "version": "1.4.19",
3
+ "version": "1.4.21",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",