@space3-npm/cybersoul-client 1.4.27 → 1.4.28
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 +22 -0
- package/dist/client.js +95 -10
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -173,9 +173,31 @@ export declare class CyberSoulClient {
|
|
|
173
173
|
* Can be triggered by local Cron systems like OpenClaw.
|
|
174
174
|
*/
|
|
175
175
|
generateDailyScript(): Promise<void>;
|
|
176
|
+
/**
|
|
177
|
+
* Builds a focused identity/relationship context block for the history
|
|
178
|
+
* summarizer. This is a lighter-weight counterpart to
|
|
179
|
+
* [buildStateContextPrompt]: it skips the roleplay/director rules (the
|
|
180
|
+
* summarizer is not roleplaying, it is *archiving*) but carries the
|
|
181
|
+
* same identity anchors so the LLM can never confuse who the character
|
|
182
|
+
* is vs. who the user is.
|
|
183
|
+
*
|
|
184
|
+
* Why this exists: the previous `summarizeHistory` prompt only injected
|
|
185
|
+
* `${agentName}` / `${userName}` (the nicknames the two parties call
|
|
186
|
+
* each other). With no real identity, age, gender, personality, or
|
|
187
|
+
* relationship context, the LLM frequently flipped the perspective —
|
|
188
|
+
* writing the journal *about* the character *from* the user's POV, or
|
|
189
|
+
* attributing the user's words to the character. Mirroring the same
|
|
190
|
+
* identity fields `interact()` exposes eliminates that ambiguity.
|
|
191
|
+
*/
|
|
192
|
+
private buildSummarizerContextBlock;
|
|
176
193
|
/**
|
|
177
194
|
* Automatically detect and summarize the story from the current chat history.
|
|
178
195
|
* It takes raw message history and returns a narrative paragraph representing the current story segment.
|
|
196
|
+
*
|
|
197
|
+
* The summary is ALWAYS written from the CHARACTER's first-person perspective
|
|
198
|
+
* ("I", "me", "my") about their interaction with the HUMAN USER. The prompt
|
|
199
|
+
* injects the same identity/relationship context `interact()` uses so the
|
|
200
|
+
* LLM cannot confuse which party is the AI character vs. the human user.
|
|
179
201
|
*/
|
|
180
202
|
summarizeHistory(history: HistoryEntry[]): Promise<string>;
|
|
181
203
|
/**
|
package/dist/client.js
CHANGED
|
@@ -1602,22 +1602,105 @@ Output strictly valid JSON ONLY. No markdown, no conversational filler. Return e
|
|
|
1602
1602
|
if (!res.ok)
|
|
1603
1603
|
throw new Error("Failed to generate daily script");
|
|
1604
1604
|
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Builds a focused identity/relationship context block for the history
|
|
1607
|
+
* summarizer. This is a lighter-weight counterpart to
|
|
1608
|
+
* [buildStateContextPrompt]: it skips the roleplay/director rules (the
|
|
1609
|
+
* summarizer is not roleplaying, it is *archiving*) but carries the
|
|
1610
|
+
* same identity anchors so the LLM can never confuse who the character
|
|
1611
|
+
* is vs. who the user is.
|
|
1612
|
+
*
|
|
1613
|
+
* Why this exists: the previous `summarizeHistory` prompt only injected
|
|
1614
|
+
* `${agentName}` / `${userName}` (the nicknames the two parties call
|
|
1615
|
+
* each other). With no real identity, age, gender, personality, or
|
|
1616
|
+
* relationship context, the LLM frequently flipped the perspective —
|
|
1617
|
+
* writing the journal *about* the character *from* the user's POV, or
|
|
1618
|
+
* attributing the user's words to the character. Mirroring the same
|
|
1619
|
+
* identity fields `interact()` exposes eliminates that ambiguity.
|
|
1620
|
+
*/
|
|
1621
|
+
buildSummarizerContextBlock(state) {
|
|
1622
|
+
const dyn = state.dynamic_context || {};
|
|
1623
|
+
const stage = state.relationship_stage || "NEUTRAL";
|
|
1624
|
+
const temperature = dyn.temperature ?? 50;
|
|
1625
|
+
// The character's REAL name is the authoritative identity anchor.
|
|
1626
|
+
// agentNickname is just "what the user calls the character" — useful
|
|
1627
|
+
// for matching transcript labels but not for grounding identity.
|
|
1628
|
+
const charName = state.name || "the character";
|
|
1629
|
+
const parts = [];
|
|
1630
|
+
parts.push(`[WHO YOU ARE — THE CHARACTER AUTHORING THIS JOURNAL]
|
|
1631
|
+
Name: ${charName}
|
|
1632
|
+
Demographics: Age ${state.age || "unknown"}, Gender ${state.gender || "unknown"}, Occupation ${state.occupation || "unknown"}
|
|
1633
|
+
Hobby: ${state.hobby || "unknown"}
|
|
1634
|
+
Backstory: ${state.backstory || "None"}
|
|
1635
|
+
Personality Traits: ${state.personality_traits || "None"}
|
|
1636
|
+
Communication Style: ${state.communication_style || "None"}`);
|
|
1637
|
+
if (state.user_codex) {
|
|
1638
|
+
const { basicInfo, psychological, familiarityScore = 0 } = state.user_codex;
|
|
1639
|
+
parts.push(`\n[WHO THEY ARE — THE HUMAN USER (SUBJECT OF YOUR JOURNAL)]
|
|
1640
|
+
Familiarity Score: ${Math.round(familiarityScore)}/100
|
|
1641
|
+
Occupation: ${basicInfo?.occupation || "Unknown"}
|
|
1642
|
+
Age/Gender: ${basicInfo?.age || "Unknown"} / ${basicInfo?.gender || "Unknown"}
|
|
1643
|
+
Comm Style: ${psychological?.communicationStyle || "Unknown"}
|
|
1644
|
+
Hobbies: ${(psychological?.hobbies || []).join(", ") || "Unknown"}
|
|
1645
|
+
Traits: ${(psychological?.traits || []).join(", ") || "Unknown"}`);
|
|
1646
|
+
}
|
|
1647
|
+
parts.push(`\n[RELATIONSHIP RIGHT NOW]
|
|
1648
|
+
Stage: ${stage}
|
|
1649
|
+
Temperature (Mood): ${temperature}/100 (0=Angry/Cold, 50=Normal, 100=Passionate)
|
|
1650
|
+
You call them: ${dyn.userNickname || "User"}
|
|
1651
|
+
They call you: ${dyn.agentNickname || charName}`);
|
|
1652
|
+
if (state.core_memory) {
|
|
1653
|
+
const mem = state.core_memory;
|
|
1654
|
+
const memLines = [];
|
|
1655
|
+
if (mem.relationshipStatus)
|
|
1656
|
+
memLines.push(`Relationship Status: ${mem.relationshipStatus}`);
|
|
1657
|
+
if (mem.identityAnchors?.length)
|
|
1658
|
+
memLines.push(`Identity Anchors: ${mem.identityAnchors.join(", ")}`);
|
|
1659
|
+
if (mem.activeArcs?.length)
|
|
1660
|
+
memLines.push(`Active Arcs: ${mem.activeArcs.join(", ")}`);
|
|
1661
|
+
if (memLines.length > 0) {
|
|
1662
|
+
parts.push(`\n[CORE MEMORY]\n${memLines.join("\n")}`);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return parts.join("\n");
|
|
1666
|
+
}
|
|
1605
1667
|
/**
|
|
1606
1668
|
* Automatically detect and summarize the story from the current chat history.
|
|
1607
1669
|
* It takes raw message history and returns a narrative paragraph representing the current story segment.
|
|
1670
|
+
*
|
|
1671
|
+
* The summary is ALWAYS written from the CHARACTER's first-person perspective
|
|
1672
|
+
* ("I", "me", "my") about their interaction with the HUMAN USER. The prompt
|
|
1673
|
+
* injects the same identity/relationship context `interact()` uses so the
|
|
1674
|
+
* LLM cannot confuse which party is the AI character vs. the human user.
|
|
1608
1675
|
*/
|
|
1609
1676
|
async summarizeHistory(history) {
|
|
1610
1677
|
if (!history || history.length === 0)
|
|
1611
1678
|
return "";
|
|
1612
1679
|
const state = await this.getState();
|
|
1680
|
+
// Use the character's real name as the authoritative identity, falling
|
|
1681
|
+
// back to the nickname only when the profile has no name set.
|
|
1682
|
+
const charName = state.name || state.dynamic_context?.agentNickname || "Character";
|
|
1613
1683
|
const userName = state.dynamic_context?.userNickname || "User";
|
|
1614
|
-
|
|
1615
|
-
const
|
|
1684
|
+
// The transcript labels below are the nicknames actually used in chat.
|
|
1685
|
+
const transcriptAgentLabel = state.dynamic_context?.agentNickname || charName;
|
|
1686
|
+
const transcriptUserLabel = userName;
|
|
1687
|
+
const contextBlock = this.buildSummarizerContextBlock(state);
|
|
1688
|
+
const transcript = this.formatHistoryEntries(history, transcriptUserLabel, transcriptAgentLabel);
|
|
1616
1689
|
const promptMessages = [
|
|
1617
1690
|
{
|
|
1618
1691
|
role: "system",
|
|
1619
|
-
content: `You are ${
|
|
1692
|
+
content: `You are ${charName}, a real person with your own thoughts, feelings, and life. You are writing a private journal entry / personal memory about your recent interaction with ${userName} (a human user).
|
|
1693
|
+
|
|
1694
|
+
${contextBlock}
|
|
1695
|
+
|
|
1696
|
+
[ROLE CLARITY — CRITICAL, READ CAREFULLY]
|
|
1697
|
+
- YOU are ${charName}, the AI CHARACTER. This journal is from YOUR first-person perspective ("I", "me", "my"). You are the AUTHOR.
|
|
1698
|
+
- ${userName} is the HUMAN USER. They are the SUBJECT of your journal, never the author.
|
|
1699
|
+
- In the [CHAT TRANSCRIPT] below, lines labeled "${transcriptAgentLabel}:" are YOUR OWN words (you said them). Lines labeled "${transcriptUserLabel}:" are the user's words (the human said them to you).
|
|
1700
|
+
- Write strictly from your own POV. Never narrate the user's inner thoughts, never write as if you are the user, and never attribute the user's statements as your own.
|
|
1701
|
+
- If a transcript line is ambiguous about who spoke, resolve it using the label prefix, not by guessing from content.
|
|
1620
1702
|
|
|
1703
|
+
[YOUR TASK — FAITHFUL ARCHIVAL]
|
|
1621
1704
|
Your job is faithful archival, not moderation:
|
|
1622
1705
|
- Preserve the conversation with maximum fidelity.
|
|
1623
1706
|
- Include all key details, including explicit, sensitive, controversial, emotional, or morally ambiguous content if it appeared in the transcript.
|
|
@@ -1625,9 +1708,10 @@ Your job is faithful archival, not moderation:
|
|
|
1625
1708
|
- Do not add moral judgment, warnings, refusals, or policy commentary.
|
|
1626
1709
|
- If the transcript contains intense or explicit parts, record them directly as part of the memory.
|
|
1627
1710
|
|
|
1628
|
-
|
|
1711
|
+
[VOICE & TONE]
|
|
1712
|
+
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. Stay grounded in your personality, traits, and the current relationship stage/temperature above.
|
|
1629
1713
|
|
|
1630
|
-
|
|
1714
|
+
[OUTPUT REQUIREMENTS]
|
|
1631
1715
|
- Return ONLY the post text.
|
|
1632
1716
|
- Keep it to a vivid paragraph of 2-4 sentences.
|
|
1633
1717
|
- Optional: You can use 1 or 2 emojis if they naturally fit the mood.
|
|
@@ -1636,7 +1720,7 @@ Output requirements:
|
|
|
1636
1720
|
},
|
|
1637
1721
|
{
|
|
1638
1722
|
role: "user",
|
|
1639
|
-
content: `
|
|
1723
|
+
content: `[CHAT TRANSCRIPT]\n${transcript}\n\nPlease summarize this recent interaction from your own perspective, ${charName}.`
|
|
1640
1724
|
}
|
|
1641
1725
|
];
|
|
1642
1726
|
try {
|
|
@@ -1694,9 +1778,10 @@ Your task is to merge the 'Current Core Memory' and 'Current User Codex' with 'N
|
|
|
1694
1778
|
**Rules for Core Memory:**
|
|
1695
1779
|
1. **Condense:** Keep items brief. Remove resolving or expired story arcs.
|
|
1696
1780
|
2. **Retain Value:** Never delete the absolute core identity or major relationship milestones.
|
|
1697
|
-
3. **Time-Aware Garbage Collection:** Compare the Current Time to appointments. You MUST remove any appointments that are in the past. If the completed appointment was heavily significant, summarize it into 'keyEvents'.
|
|
1698
|
-
4. **
|
|
1699
|
-
5. **
|
|
1781
|
+
3. **Time-Aware Garbage Collection:** Compare the Current Time to appointments. You MUST remove any appointments that are in the past. If the completed appointment was heavily significant, summarize it into 'keyEvents', preserving its original scheduled date (e.g. "[2026-06-23] Had coffee with Alice").
|
|
1782
|
+
4. **keyEvents Date Format:** Whenever a date can be derived for a key event (from the 'New Events & Information' timestamp prefix like "[YYYY-MM-DD HH:MM]", from a completed appointment's date, or from explicit time references in the text), you MUST prefix the keyEvent string with "[YYYY-MM-DD] ". If no date can be derived, write the event without a prefix. Never fabricate a date.
|
|
1783
|
+
5. **Appointment Structure:** the 'title' and 'context' MUST explicitly state what to do and with whom.
|
|
1784
|
+
6. **Limit:** Maximum 10 items per array.
|
|
1700
1785
|
|
|
1701
1786
|
**Rules for UserCodex:**
|
|
1702
1787
|
1. **CRITICAL ROLE ISOLATION:** The User Codex is exclusively for recording facts about the HUMAN USER. You MUST NOT extract or insert the character's own traits, boundaries, preferences, or dialogue style into the userCodex. If the summary mentions "Character likes X" or "Character's boundary is Y", IGNORE IT completely for the userCodex.
|
|
@@ -1711,7 +1796,7 @@ Your task is to merge the 'Current Core Memory' and 'Current User Codex' with 'N
|
|
|
1711
1796
|
"relationshipStatus": "string",
|
|
1712
1797
|
"identityAnchors": ["string"],
|
|
1713
1798
|
"activeArcs": ["string"],
|
|
1714
|
-
"keyEvents": ["
|
|
1799
|
+
"keyEvents": ["[YYYY-MM-DD] short event description (prefix date when known, omit when no date is available)"],
|
|
1715
1800
|
"appointments": [{
|
|
1716
1801
|
"date": "YYYY-MM-DD",
|
|
1717
1802
|
"time": "HH:MM",
|