@space3-npm/cybersoul-client 1.2.3 → 1.2.4
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.js +9 -6
- package/dist/types.d.ts +2 -1
- package/dist/utils/json.utils.d.ts +1 -1
- package/dist/utils/json.utils.js +45 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -226,7 +226,8 @@ Occupation: ${basicInfo?.occupation || "Unknown"}
|
|
|
226
226
|
Age/Gender: ${basicInfo?.age || "Unknown"} / ${basicInfo?.gender || "Unknown"}
|
|
227
227
|
Comm Style: ${psychological?.communicationStyle || "Unknown"}
|
|
228
228
|
Hobbies: ${(psychological?.hobbies || []).join(", ") || "Unknown"}
|
|
229
|
-
Traits/Boundaries: ${(psychological?.traits || []).join(", ") || "Unknown"} / ${(psychological?.boundaries || []).join(", ") || "Unknown"}
|
|
229
|
+
Traits/Boundaries: ${(psychological?.traits || []).join(", ") || "Unknown"} / ${(psychological?.boundaries || []).join(", ") || "Unknown"}
|
|
230
|
+
Preferences/Habits: ${(psychological?.preferences || []).join(", ") || "Unknown"}`);
|
|
230
231
|
// CURIOSITY DRIVE: Find what's missing, but ONLY IF we are on generally warm speaking terms
|
|
231
232
|
// Paradox avoidance: A cold/angry character shouldn't enthusiastically fish for hobbies.
|
|
232
233
|
if (temperature >= 40 && stage !== "COLD" && stage !== "STRANGER") {
|
|
@@ -413,7 +414,7 @@ For 'ongoingScene.outfit': decide based on the current active wardrobe by defaul
|
|
|
413
414
|
USER ANALYSIS WORKFLOW:
|
|
414
415
|
- Extract from VERY LAST USER MESSAGE only.
|
|
415
416
|
- Add only explicit new user facts from this turn (no inference).
|
|
416
|
-
- Categories: 'realName', 'occupation', 'age', 'gender', 'hobby', 'trait', 'communicationStyle', 'boundary'.
|
|
417
|
+
- Categories: 'realName', 'occupation', 'age', 'gender', 'hobby', 'trait', 'communicationStyle', 'boundary', 'preference'.
|
|
417
418
|
- Keep nicknames in stateUpdate; do not place them in newFactsLearned.
|
|
418
419
|
- If no new fact is explicit, set userAnalysis to null.
|
|
419
420
|
|
|
@@ -427,7 +428,7 @@ Output JSON Schema:
|
|
|
427
428
|
"textResponse": "Spoken dialogue ONLY. Never include actions or parentheses.",
|
|
428
429
|
"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" } },
|
|
429
430
|
"giftOutfit": { "descriptionText": "Concise description of the newly acquired outfit to add into wardrobe." },
|
|
430
|
-
"userAnalysis": { "newFactsLearned": [{ "category": "realName|occupation|age|gender|hobby|trait|communicationStyle|boundary", "value": "explicit new user fact from VERY LAST USER MESSAGE" }] },
|
|
431
|
+
"userAnalysis": { "newFactsLearned": [{ "category": "realName|occupation|age|gender|hobby|trait|communicationStyle|boundary|preference", "value": "explicit new user fact from VERY LAST USER MESSAGE" }] },
|
|
431
432
|
"isEndTurn": false,
|
|
432
433
|
"triggerEvent": {
|
|
433
434
|
${this.getEventSchemaParams(state.dynamic_context?.userNickname)}
|
|
@@ -452,7 +453,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
|
|
|
452
453
|
// console.debug("[CyberSoulClient] Raw LLM Response:", rawLlmResponse);
|
|
453
454
|
let parsedIntent;
|
|
454
455
|
try {
|
|
455
|
-
parsedIntent = robustJsonParse(rawLlmResponse, "Dispatcher fallback");
|
|
456
|
+
parsedIntent = robustJsonParse(rawLlmResponse, "Dispatcher fallback", { textResponse: "", actionText: "", isEndTurn: false });
|
|
456
457
|
}
|
|
457
458
|
catch (e) {
|
|
458
459
|
console.warn("[CyberSoulClient] JSON parse failed, falling back to raw text:", e);
|
|
@@ -842,6 +843,7 @@ Output requirements:
|
|
|
842
843
|
traits: [],
|
|
843
844
|
communicationStyle: "",
|
|
844
845
|
boundaries: [],
|
|
846
|
+
preferences: [],
|
|
845
847
|
}
|
|
846
848
|
};
|
|
847
849
|
const systemPrompt = `You are an AI Memory Consolidation Engine for a virtual companion.
|
|
@@ -855,7 +857,7 @@ Your task is to merge the 'Current Core Memory' and 'Current User Codex' with 'N
|
|
|
855
857
|
5. **Limit:** Maximum 10 items per array.
|
|
856
858
|
|
|
857
859
|
**Rules for UserCodex:**
|
|
858
|
-
1. **Deduplicate & Consolidate:** Remove duplicate hobbies, traits, and
|
|
860
|
+
1. **Deduplicate & Consolidate:** Remove duplicate hobbies, traits, boundaries, and preferences. Combine related points into concise descriptors.
|
|
859
861
|
2. **Update Facts:** If the new events contain updated basic info (like new realName, different occupation), update it. Otherwise keep the existing info.
|
|
860
862
|
3. **Keep it Clean:** Maximum 15 items per array.
|
|
861
863
|
|
|
@@ -885,7 +887,8 @@ Your task is to merge the 'Current Core Memory' and 'Current User Codex' with 'N
|
|
|
885
887
|
"hobbies": ["string"],
|
|
886
888
|
"traits": ["string"],
|
|
887
889
|
"communicationStyle": "string",
|
|
888
|
-
"boundaries": ["string"]
|
|
890
|
+
"boundaries": ["string"],
|
|
891
|
+
"preferences": ["string"]
|
|
889
892
|
}
|
|
890
893
|
}
|
|
891
894
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export interface DispatcherIntent {
|
|
|
82
82
|
} | null;
|
|
83
83
|
userAnalysis?: {
|
|
84
84
|
newFactsLearned: {
|
|
85
|
-
category: "realName" | "occupation" | "age" | "gender" | "hobby" | "trait" | "communicationStyle" | "boundary";
|
|
85
|
+
category: "realName" | "occupation" | "age" | "gender" | "hobby" | "trait" | "communicationStyle" | "boundary" | "preference";
|
|
86
86
|
value: string;
|
|
87
87
|
}[];
|
|
88
88
|
};
|
|
@@ -129,6 +129,7 @@ export interface UserCodex {
|
|
|
129
129
|
traits: string[];
|
|
130
130
|
communicationStyle: string;
|
|
131
131
|
boundaries: string[];
|
|
132
|
+
preferences?: string[];
|
|
132
133
|
};
|
|
133
134
|
familiarityScore?: number;
|
|
134
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function robustJsonParse<T>(jsonString: string, contextMessage?: string): T;
|
|
1
|
+
export declare function robustJsonParse<T>(jsonString: string, contextMessage?: string, fallbackTemplate?: Record<string, any>): T;
|
package/dist/utils/json.utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function robustJsonParse(jsonString, contextMessage = 'throwing original error') {
|
|
1
|
+
export function robustJsonParse(jsonString, contextMessage = 'throwing original error', fallbackTemplate) {
|
|
2
2
|
let cleanJson = jsonString.trim();
|
|
3
3
|
// 0. Inject missing colons between string keys and string values (e.g. "key""value" -> "key":"value")
|
|
4
4
|
// Only insert the colon if we match a likely key (alphanumeric/hyphen) followed by quotes, handling smart quotes.
|
|
@@ -119,6 +119,50 @@ export function robustJsonParse(jsonString, contextMessage = 'throwing original
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
// FINAL FALLBACK: Regex extraction of requested fields if fallbackTemplate is provided
|
|
123
|
+
if (fallbackTemplate) {
|
|
124
|
+
console.warn(`[robustJsonParse] Regex fallback using template for: ${contextMessage}`);
|
|
125
|
+
const extractedObj = { ...fallbackTemplate };
|
|
126
|
+
let extractedAny = false;
|
|
127
|
+
for (const key of Object.keys(fallbackTemplate)) {
|
|
128
|
+
// 1. Try to extract string values handling escaped characters like \" and \n
|
|
129
|
+
const stringMatch = cleanJson.match(new RegExp(`"${key}"\\s*:\\s*"((?:[^"\\\\]|\\\\.)*)"`));
|
|
130
|
+
if (stringMatch) {
|
|
131
|
+
try {
|
|
132
|
+
extractedObj[key] = JSON.parse(`"${stringMatch[1]}"`);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
extractedObj[key] = stringMatch[1];
|
|
136
|
+
}
|
|
137
|
+
extractedAny = true;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// 2. Try to extract booleans, numbers, or null
|
|
141
|
+
const primitiveMatch = cleanJson.match(new RegExp(`"${key}"\\s*:\\s*([a-zA-Z0-9_.-]+)`));
|
|
142
|
+
if (primitiveMatch) {
|
|
143
|
+
const val = primitiveMatch[1];
|
|
144
|
+
if (val === 'true') {
|
|
145
|
+
extractedObj[key] = true;
|
|
146
|
+
extractedAny = true;
|
|
147
|
+
}
|
|
148
|
+
else if (val === 'false') {
|
|
149
|
+
extractedObj[key] = false;
|
|
150
|
+
extractedAny = true;
|
|
151
|
+
}
|
|
152
|
+
else if (val === 'null') {
|
|
153
|
+
extractedObj[key] = null;
|
|
154
|
+
extractedAny = true;
|
|
155
|
+
}
|
|
156
|
+
else if (!isNaN(Number(val))) {
|
|
157
|
+
extractedObj[key] = Number(val);
|
|
158
|
+
extractedAny = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (extractedAny) {
|
|
163
|
+
return extractedObj;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
122
166
|
console.warn(`Failed to parse Dispatcher Intent: ${contextMessage}. Falling back to plain text.`);
|
|
123
167
|
throw e;
|
|
124
168
|
}
|