@space3-npm/cybersoul-client 1.3.7 → 1.3.8

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 CHANGED
@@ -1,4 +1,4 @@
1
- import { CyberSoulClientConfig, InteractParams, ProactiveParams, ProactiveResponse, OndemandEventParams, OndemandEventResponse, DispatcherIntent, InteractResponse, CharacterState, CoreMemory, UserCodex, LikedPicture } from "./types.js";
1
+ import { CyberSoulClientConfig, InteractParams, ProactiveParams, ProactiveResponse, OndemandEventParams, OndemandEventResponse, DispatcherIntent, InteractResponse, CharacterState, CoreMemory, UserCodex, HistoryEntry, LikedPicture } from "./types.js";
2
2
  export declare class CyberSoulClient {
3
3
  private config;
4
4
  private llm;
@@ -16,6 +16,7 @@ export declare class CyberSoulClient {
16
16
  private generatePrimitive;
17
17
  private _updateDynamicContextInternal;
18
18
  private normalizeRequestTypes;
19
+ private getElapsedTimeInfo;
19
20
  private buildStateContextPrompt;
20
21
  private normalizeOngoingSceneState;
21
22
  private getImageSchemaParams;
@@ -41,6 +42,7 @@ export declare class CyberSoulClient {
41
42
  * If the payload is already the inner args object (no voiceArgs wrapper), uses it as-is.
42
43
  */
43
44
  private extractVoiceArgsFromLlmResponse;
45
+ private formatHistoryEntries;
44
46
  private buildHistoryTranscript;
45
47
  interact(params: InteractParams): Promise<InteractResponse>;
46
48
  /**
@@ -96,10 +98,7 @@ export declare class CyberSoulClient {
96
98
  * Automatically detect and summarize the story from the current chat history.
97
99
  * It takes raw message history and returns a narrative paragraph representing the current story segment.
98
100
  */
99
- summarizeHistory(history: {
100
- role: string;
101
- content: string;
102
- }[]): Promise<string>;
101
+ summarizeHistory(history: HistoryEntry[]): Promise<string>;
103
102
  /**
104
103
  * Save the recent story moment to the character's backend database to be picked up by the core memory consolidation.
105
104
  */
package/dist/client.js CHANGED
@@ -154,6 +154,23 @@ export class CyberSoulClient {
154
154
  }
155
155
  return normalized;
156
156
  }
157
+ getElapsedTimeInfo(currentTimeMs, lastInteractionAt) {
158
+ const elapsedMs = Math.max(0, currentTimeMs - new Date(lastInteractionAt).getTime());
159
+ const elapsedMins = elapsedMs / (1000 * 60);
160
+ const elapsedHours = elapsedMins / 60;
161
+ const elapsedDays = elapsedHours / 24;
162
+ const elapsedYears = elapsedDays / 365;
163
+ let displayStr = "";
164
+ if (elapsedYears >= 1)
165
+ displayStr = `${elapsedYears.toFixed(1)} years`;
166
+ else if (elapsedDays >= 1)
167
+ displayStr = `${elapsedDays.toFixed(1)} days`;
168
+ else if (elapsedHours >= 1)
169
+ displayStr = `${elapsedHours.toFixed(1)} hours`;
170
+ else
171
+ displayStr = `${Math.floor(elapsedMins)} mins`;
172
+ return { elapsedMs, elapsedMins, elapsedHours, elapsedDays, elapsedYears, displayStr };
173
+ }
157
174
  buildStateContextPrompt(state, isProactive = false) {
158
175
  const dyn = state.dynamic_context || {};
159
176
  const stage = state.relationship_stage || "NEUTRAL";
@@ -180,28 +197,18 @@ Current time: ${new Date(currentTimeMs).toLocaleString("zh-CN", { timeZone: "Asi
180
197
  const scenePrefix = "Last Known Scene";
181
198
  let timeAgoStr = scenePrefix;
182
199
  let isOutdated = false;
183
- let elapsedHours = 0;
200
+ let timeDisplayStr = "";
184
201
  if (dyn.lastInteractionAt) {
185
- const elapsedMs = currentTimeMs - new Date(dyn.lastInteractionAt).getTime();
186
- const elapsedMins = Math.max(0, elapsedMs / (1000 * 60));
187
- elapsedHours = elapsedMins / 60;
188
- const elapsedDays = elapsedHours / 24;
189
- const elapsedYears = elapsedDays / 365;
190
- if (elapsedYears >= 1)
191
- timeAgoStr = `${scenePrefix} ${elapsedYears.toFixed(1)} years ago`;
192
- else if (elapsedDays >= 1)
193
- timeAgoStr = `${scenePrefix} ${elapsedDays.toFixed(1)} days ago`;
194
- else if (elapsedHours >= 1)
195
- timeAgoStr = `${scenePrefix} ${elapsedHours.toFixed(1)} hours ago`;
196
- else
197
- timeAgoStr = `${scenePrefix} ${Math.floor(elapsedMins)} mins ago`;
198
- if (elapsedHours > 1) {
202
+ const timeInfo = this.getElapsedTimeInfo(currentTimeMs, dyn.lastInteractionAt);
203
+ timeDisplayStr = timeInfo.displayStr;
204
+ timeAgoStr = `${scenePrefix} ${timeDisplayStr} ago`;
205
+ if (timeInfo.elapsedHours > 1) {
199
206
  isOutdated = true;
200
207
  }
201
208
  }
202
209
  const lastKnownSceneLine = `${timeAgoStr}: ${ongoingScene.scene} | Outfit: ${ongoingScene.outfit}`;
203
210
  if (isOutdated) {
204
- contextParts.push(`${lastKnownSceneLine}\n[CRITICAL SCENE SHIFT]: It has been ${elapsedHours.toFixed(1)} hours since the last discussion. The 'Last Known Scene' is now strictly OUTDATED. You MUST abandon the previous scene context entirely and transition to a new scene appropriate for the 'Current time' and 'Active Event'. DO NOT continue the old actions or environment!`);
211
+ contextParts.push(`Previous Activity (Ended ${timeDisplayStr} ago): ${ongoingScene.scene}\n[SCENE RESET]: A significant amount of time has passed. The previous activity is completely over. You are now in a fresh, natural state based on your current Wardrobe and Time. Do NOT continue the previous actions.`);
205
212
  }
206
213
  else {
207
214
  contextParts.push(`${lastKnownSceneLine} (Evaluate whether this scene is still valid based on how much time has passed since it was last updated.)`);
@@ -400,20 +407,44 @@ ${isProactive
400
407
  }
401
408
  return payload;
402
409
  }
410
+ formatHistoryEntries(history, userName, agentName, promptDirective = "") {
411
+ const contextLines = [];
412
+ for (let i = 0; i < history.length; i++) {
413
+ const msg = history[i];
414
+ if (i > 0 && history[i - 1].timestamp && msg.timestamp) {
415
+ const prevTime = new Date(history[i - 1].timestamp).getTime();
416
+ const currTime = new Date(msg.timestamp).getTime();
417
+ const timeInfo = this.getElapsedTimeInfo(currTime, prevTime);
418
+ if (timeInfo.elapsedHours > 1) {
419
+ contextLines.push(`\n[--- ${timeInfo.displayStr} later ---${promptDirective ? " " + promptDirective : ""} ---]\n`);
420
+ }
421
+ }
422
+ const speaker = msg.role === 'user' ? userName : (msg.role === 'assistant' || msg.role === 'agent' ? agentName : msg.role);
423
+ const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
424
+ const action = msg.actionText ? ` (${msg.actionText})` : "";
425
+ const media = msg.mediaHint ? ` [${msg.mediaHint}]` : "";
426
+ contextLines.push(`${speaker}:${action} ${content}${media}`);
427
+ }
428
+ return contextLines.join('\n');
429
+ }
403
430
  buildHistoryTranscript(history, state) {
404
431
  if (!history || history.length === 0)
405
432
  return "";
406
433
  const recentHistory = history.slice(-20);
407
434
  const agentName = state.dynamic_context?.agentNickname || state.name || "Agent";
408
435
  const userName = state.dynamic_context?.userNickname || "User";
409
- const mapped = recentHistory.map((msg) => {
410
- const speaker = msg.role === 'user' ? userName : (msg.role === 'assistant' || msg.role === 'agent' ? agentName : msg.role);
411
- const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
412
- const action = msg.actionText ? ` (${msg.actionText})` : "";
413
- const media = msg.mediaHint ? ` [${msg.mediaHint}]` : "";
414
- return `${speaker}:${action} ${content}${media}`;
415
- });
416
- return `[CHAT HISTORY]\n${mapped.join('\n')}\n\n`;
436
+ const directive = "The previous chat history is completely outdated by the time passage. Do not continue its immediate action flow.";
437
+ const transcript = this.formatHistoryEntries(recentHistory, userName, agentName, directive);
438
+ let historyContent = `[CHAT HISTORY]\n${transcript}\n`;
439
+ // If there is a massive time gap between the chat history and the VERY LAST USER MESSAGE
440
+ if (state.dynamic_context?.lastInteractionAt) {
441
+ const currentTimeMs = state.current_time ? new Date(state.current_time).getTime() : Date.now();
442
+ const timeInfo = this.getElapsedTimeInfo(currentTimeMs, state.dynamic_context.lastInteractionAt);
443
+ if (timeInfo.elapsedHours > 1) {
444
+ historyContent += `\n[--- ${timeInfo.displayStr} later --- The previous chat history is completely outdated by the time passage. Do not continue its immediate action flow. ---]\n`;
445
+ }
446
+ }
447
+ return historyContent + "\n";
417
448
  }
418
449
  async interact(params) {
419
450
  try {
@@ -1016,7 +1047,7 @@ Output strictly valid JSON ONLY. No markdown, no conversational filler. Return e
1016
1047
  const state = await this.getState();
1017
1048
  const userName = state.dynamic_context?.userNickname || "User";
1018
1049
  const agentName = state.dynamic_context?.agentNickname || "Character";
1019
- const transcript = history.map(h => `${h.role === 'user' ? userName : agentName}: ${h.content}`).join('\n');
1050
+ const transcript = this.formatHistoryEntries(history, userName, agentName);
1020
1051
  const promptMessages = [
1021
1052
  {
1022
1053
  role: "system",
package/dist/types.d.ts CHANGED
@@ -23,6 +23,7 @@ export interface HistoryEntry {
23
23
  actionText?: string;
24
24
  mediaHint?: string;
25
25
  isProactive?: boolean;
26
+ timestamp?: string | number | Date;
26
27
  }
27
28
  export interface InteractMetadata {
28
29
  stateUpdate?: DispatcherIntent["stateUpdate"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@space3-npm/cybersoul-client",
3
- "version": "1.3.7",
3
+ "version": "1.3.8",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",