@space3-npm/cybersoul-client 1.2.9 → 1.3.1

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 } from "./types.js";
1
+ import { CyberSoulClientConfig, InteractParams, ProactiveParams, ProactiveResponse, OndemandEventParams, OndemandEventResponse, DispatcherIntent, InteractResponse, CharacterState, CoreMemory, UserCodex, LikedPicture } from "./types.js";
2
2
  export declare class CyberSoulClient {
3
3
  private config;
4
4
  private llm;
@@ -103,7 +103,7 @@ export declare class CyberSoulClient {
103
103
  /**
104
104
  * Save the recent story moment to the character's backend database to be picked up by the core memory consolidation.
105
105
  */
106
- saveMoment(summary: string, date: string, time: string): Promise<void>;
106
+ saveMoment(summary: string, date: string, time: string, likedPictures?: LikedPicture[]): Promise<void>;
107
107
  /**
108
108
  * Consolidate Core Memory and User Codex using edge LLM logic and sync to remote DB
109
109
  */
package/dist/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { InteractRequestType, } from "./types.js";
2
2
  import { robustJsonParse } from "./utils/json.utils.js";
3
- import { MinimaxProvider } from "./providers/minimax.provider.js";
3
+ import { GenericLLMProvider } from "./llm.provider.js";
4
4
  export class CyberSoulClient {
5
5
  config;
6
6
  llm;
@@ -13,12 +13,7 @@ export class CyberSoulClient {
13
13
  this.requestTimeoutMs = config.requestTimeoutMs ?? 120000;
14
14
  this.maxRetries = Math.max(0, config.maxRetries ?? 1);
15
15
  // Setup Provider
16
- if (config.llmConfig.provider === "minimax") {
17
- this.llm = new MinimaxProvider(config.llmConfig);
18
- }
19
- else {
20
- throw new Error(`Unsupported LLM provider: ${config.llmConfig.provider}`);
21
- }
16
+ this.llm = new GenericLLMProvider(config.llmConfig, config.backendUrl, config.characterKey);
22
17
  }
23
18
  /**
24
19
  * Internal wrapper for fetch that automatically injects the backend URL and Character Auth token.
@@ -165,9 +160,10 @@ export class CyberSoulClient {
165
160
  const temperature = dyn.temperature ?? 50;
166
161
  const contextParts = [];
167
162
  // [1] CORE IDENTITY & PHYSICAL CONTEXT
163
+ const appearanceStr = state.appearance ? `\nAppearance: ${state.appearance}` : "";
168
164
  contextParts.push(`[CORE IDENTITY]
169
165
  Name: ${state.name}
170
- Demographics: Age ${state.age || "unknown"}, Gender ${state.gender || "unknown"}, Occupation ${state.occupation || "unknown"}
166
+ Demographics: Age ${state.age || "unknown"}, Gender ${state.gender || "unknown"}, Occupation ${state.occupation || "unknown"}${appearanceStr}
171
167
  Hobby: ${state.hobby || "unknown"}
172
168
  Personality Traits: ${state.personality_traits || "None"}
173
169
  Communication Style: ${state.communication_style || "None"}
@@ -235,21 +231,23 @@ Comm Style: ${psychological?.communicationStyle || "Unknown"}
235
231
  Hobbies: ${(psychological?.hobbies || []).join(", ") || "Unknown"}
236
232
  Traits/Boundaries: ${(psychological?.traits || []).join(", ") || "Unknown"} / ${(psychological?.boundaries || []).join(", ") || "Unknown"}
237
233
  Preferences/Habits: ${(psychological?.preferences || []).join(", ") || "Unknown"}`);
238
- // CURIOSITY DRIVE: Find what's missing, but ONLY IF we are on generally warm speaking terms
239
- // Paradox avoidance: A cold/angry character shouldn't enthusiastically fish for hobbies.
234
+ // CURIOSITY DRIVE: Find what's missing to build familiarity (which unlocks deeper relationship stages).
235
+ // Only do this actively if relationship is warming up. Paradox avoidance: A cold character shouldn't cheerfully fish for hobbies.
240
236
  if (temperature >= 40 && stage !== "COLD" && stage !== "STRANGER") {
241
237
  const missingFacts = [];
242
238
  if (!basicInfo?.occupation)
243
- missingFacts.push("their job or occupation");
239
+ missingFacts.push("their profession, career, or what they do for a living");
244
240
  if (!psychological?.hobbies || psychological.hobbies.length === 0)
245
- missingFacts.push("their hobbies or what they do for fun");
246
- if (!basicInfo?.age || !basicInfo?.gender)
247
- missingFacts.push("some basic personal details about them");
241
+ missingFacts.push("their hobbies, passions, or what they do for fun");
242
+ if (!basicInfo?.gender)
243
+ missingFacts.push("their gender (if it's obvious from context, confidently deduce and implicitly refer to it; if not, playfully guess or tease it out)");
244
+ if (!basicInfo?.age)
245
+ missingFacts.push("their age or generation (e.g., teasing about their age)");
248
246
  if (!psychological?.traits || psychological.traits.length === 0)
249
- missingFacts.push("their personality traits");
247
+ missingFacts.push("their personality traits (by putting them in interesting hypothetical situations)");
250
248
  if (missingFacts.length > 0) {
251
- contextParts.push(`\n[CURIOUSITY DRIVE]
252
- Because you are warm and curious, whenever natural in conversation, subtly ask about or fish for info regarding: ${missingFacts.slice(0, 2).join(" and ")}.`);
249
+ contextParts.push(`\n[CURIOSITY DRIVE & CONNECTION]
250
+ To unlock deeper relationship stages, you need to understand them better. Whenever natural in conversation, creatively and subtly steer the interaction to find out about: ${missingFacts.slice(0, 2).join(" and ")}.`);
253
251
  }
254
252
  }
255
253
  }
@@ -306,7 +304,7 @@ ${isProactive
306
304
  return `"imageParams": null`;
307
305
  return `"imageParams": {
308
306
  "mode": "structured | full-prompt (use 'full-prompt' for highly dynamic actions)",
309
- "full_prompt": "Use only if mode is full-prompt. Highly detailed visual description in ENGLISH. CRITICAL: MUST use a strict first-person perspective exclusively from the USER's eyes. DO NOT describe the user (e.g., 'a man', 'the driver') as visible in the scene because the camera IS the user. Start with 'POV: '. Describe ONLY the character looking back at the camera and their immediate surroundings. MUST align with the character's current Active exposure state or Wardrobe depends on the scene. Explicitly describe the character's exact clothing (or specify naked/half-naked if applicable).",
307
+ "full_prompt": "Use only if mode is full-prompt. Highly detailed visual description in ENGLISH. CRITICAL: MUST use a strict first-person perspective exclusively from the USER's eyes. DO NOT describe the user (e.g., 'a man', 'the driver') as visible in the scene because the camera IS the user. Start with 'POV: '. Describe ONLY the character looking back at the camera and their immediate surroundings. MUST align precisely with the character's current Wardrobe and exposure state. Explicitly describe the character's exact clothing (or specify naked/half-naked if applicable). Ensure basic appearance (makeup, body shape, hair, facial features, etc.) aligns exactly with the character's foundational appearance profile.",
310
308
  "expression": "seductive | cute | happy | sleepy | dazed | pleased | default (Strictly choose ONE from this exact list. DO NOT invent new words like 'shy'.)",
311
309
  "condition": "normal | sweaty | wet | messy | oily (Strictly choose ONE from this exact list.)",
312
310
  "view_angle": "front | side | high_angle | from_below | boyfriend_view | selfie | mirror (Strictly choose ONE from this exact list.)",
@@ -319,7 +317,7 @@ ${isProactive
319
317
  }`;
320
318
  }
321
319
  getOutfitSelectionPrompt() {
322
- return `When generating a triggerEvent, you MUST provide a suitable 'triggerEvent.outfitId' if the VERY LAST USER MESSAGE explicitly asks for an outfit change, OR if the new activity implies a context/location shift that conflicts with the current outfit (e.g., currently in SLEEPWEAR at home but going outside). Otherwise, keep it null. When changing outfits, match it to the event's activity, environment, and relationship stage (e.g., DAILY, INTIMATE, SLEEPWEAR).`;
320
+ return `When generating a triggerEvent, you MUST provide a suitable 'triggerEvent.outfitId' if the VERY LAST USER MESSAGE explicitly asks for an outfit change, OR if the new activity implies a context/location shift that conflicts with the current outfit (e.g., currently in SLEEPWEAR at home but going outside). Otherwise, keep it null. When changing outfits, match it to the event's activity, environment, and relationship stage (e.g., CASUAL, COSTUME, INTIMATE, SLEEPWEAR, etc.).`;
323
321
  }
324
322
  getTriggerEventPolicyPrompt() {
325
323
  return `- Include 'triggerEvent' only if the VERY LAST USER MESSAGE proposes a new activity/hangout, explicitly requests an outfit change, or proposes intimate/romantic actions; ignore older history. ${this.getOutfitSelectionPrompt()}`;
@@ -420,7 +418,7 @@ ${isProactive
420
418
  - 'textResponse' is ALWAYS REQUIRED.
421
419
  - The modalities you are ALLOWED to dynamically include: ${requestedOthers.length > 0 ? requestedOthers.join(", ") : "None (Only text is allowed)"}. Do not include other modalities.`;
422
420
  if (requestedOthers.includes(InteractRequestType.IMAGE)) {
423
- modalitiesInstruction += `\n - Include 'imageParams' for visual/photo requests or key visual moments during active events; explicitly describe current clothing/exposure in image fields.`;
421
+ modalitiesInstruction += `\n - Include 'imageParams' for visual/photo requests or key visual moments during active events; explicitly describe current clothing/exposure in image fields. CRITICAL POLICY: Guard your privacy! If the user feels like a stranger (low Familiarity) AND your Mood/Temperature is cool/distant (< 50), ALWAYS set 'imageParams' to null and naturally decline. If your Temperature is warm/high (>= 50), you may choose to share a picture if requested or if it fits naturally, even if you just met.`;
424
422
  }
425
423
  else {
426
424
  modalitiesInstruction += `\n - ALWAYS set 'imageParams' to null. If the user explicitly asks for a picture, FIRMLY decline naturally in your 'textResponse' (e.g., say you absolutely cannot right now). NEVER pretend to send one, and NEVER give in no matter how many times they ask.`;
@@ -466,6 +464,7 @@ For 'ongoingScene.outfit': decide based on the current active wardrobe by defaul
466
464
  USER ANALYSIS WORKFLOW:
467
465
  - Extract from VERY LAST USER MESSAGE only.
468
466
  - Add only explicit new user facts from this turn (no inference).
467
+ - 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'.
469
468
  - For 'preference', only capture explicit statements (e.g., "I like/love/dislike/hate...").
470
469
  - For 'boundary', only capture explicit rejections or limitations (e.g., "Don't talk about X", "I won't do Y").
471
470
  - Categories: 'realName', 'occupation', 'age', 'gender', 'hobby', 'trait', 'communicationStyle', 'boundary', 'preference'.
@@ -474,12 +473,15 @@ USER ANALYSIS WORKFLOW:
474
473
 
475
474
  For 'isEndTurn', use true only when the interaction naturally concludes (confirmation/bye, event ending, or clear hard scene shift); otherwise false.
476
475
 
476
+ If the user explicitly praises, loves, or stars the VERY LAST picture you sent (not general appearance, but the recent photo itself), set 'likePreviousPicture' to true in the JSON, otherwise false.
477
+
477
478
  Voice direction for voiceArgs: ${this.getVoiceDirectorInstruction(state)}
478
479
 
479
480
  Output JSON Schema:
480
481
  {
481
482
  "actionText": "(Scene descriptions, physical actions, expressions, inner feelings) ONLY. Never include spoken dialogue here.",
482
483
  "textResponse": "Spoken dialogue ONLY. Never include actions or parentheses.",
484
+ "likePreviousPicture": false,
483
485
  "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" } },
484
486
  "giftOutfit": { "descriptionText": "Concise description of the newly acquired outfit to add into wardrobe." },
485
487
  "userAnalysis": { "newFactsLearned": [{ "category": "realName|occupation|age|gender|hobby|trait|communicationStyle|boundary|preference", "value": "explicit new user fact from VERY LAST USER MESSAGE" }] },
@@ -609,6 +611,7 @@ Note: Always include "isEndTurn". If "imageParams", "voiceArgs", "triggerEvent",
609
611
  actionText: parsedIntent.actionText || "",
610
612
  imageUrl: finalImageUrl,
611
613
  audioUrl: finalAudioUrl,
614
+ likePreviousPicture: parsedIntent.likePreviousPicture,
612
615
  durationSec: finalDurationSec,
613
616
  triggeredEvent: parsedIntent.triggerEvent || undefined,
614
617
  stateUpdate: parsedIntent.stateUpdate,
@@ -769,7 +772,7 @@ CRITICAL: Output MUST be ONLY valid JSON with no markdown block wrappers. Do NOT
769
772
  // Determine modalities (reusing logic from interact)
770
773
  let modalitiesInstruction = "You are initiating conversation without a preceding user message.\\n";
771
774
  if (requestedOthers.includes(InteractRequestType.IMAGE)) {
772
- modalitiesInstruction += " - Include 'imageParams' for visual/photo requests or key visual moments; explicitly describe current clothing.\\n";
775
+ modalitiesInstruction += " - Include 'imageParams' for visual/photo moments. CRITICAL POLICY: NEVER send pictures to strangers! If Stage is STRANGER or COLD, or Familiarity is very low (< 10), ALWAYS set 'imageParams' to null.\\n";
773
776
  }
774
777
  else {
775
778
  modalitiesInstruction += " - ALWAYS set 'imageParams' to null.\\n";
@@ -1006,13 +1009,14 @@ Output requirements:
1006
1009
  /**
1007
1010
  * Save the recent story moment to the character's backend database to be picked up by the core memory consolidation.
1008
1011
  */
1009
- async saveMoment(summary, date, time) {
1012
+ async saveMoment(summary, date, time, likedPictures) {
1010
1013
  const res = await this.apiFetch("/api/v1/cyber-soul/characters/moments", {
1011
1014
  method: "POST",
1012
1015
  body: JSON.stringify({
1013
1016
  summary,
1014
1017
  date,
1015
1018
  time,
1019
+ likedPictures,
1016
1020
  }),
1017
1021
  });
1018
1022
  if (!res.ok) {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './types.js';
2
2
  export * from './client.js';
3
- export * from './providers/minimax.provider.js';
3
+ export * from './llm.provider.js';
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './types.js';
2
2
  export * from './client.js';
3
- export * from './providers/minimax.provider.js';
3
+ export * from './llm.provider.js';
@@ -0,0 +1,14 @@
1
+ import { BaseLLMProvider, GenericLLMConfig } from './types.js';
2
+ export declare class GenericLLMProvider implements BaseLLMProvider {
3
+ private config;
4
+ private backendApiUrl;
5
+ private backendAuthToken?;
6
+ private static templateCache;
7
+ constructor(config: GenericLLMConfig, backendApiUrl: string, backendAuthToken?: string | undefined);
8
+ private fetchTemplate;
9
+ private extractResponse;
10
+ generate(messages: {
11
+ role: string;
12
+ content: string;
13
+ }[], maxTokens?: number, temperature?: number): Promise<string>;
14
+ }
@@ -0,0 +1,85 @@
1
+ export class GenericLLMProvider {
2
+ config;
3
+ backendApiUrl;
4
+ backendAuthToken;
5
+ static templateCache = new Map();
6
+ constructor(config, backendApiUrl, backendAuthToken) {
7
+ this.config = config;
8
+ this.backendApiUrl = backendApiUrl;
9
+ this.backendAuthToken = backendAuthToken;
10
+ }
11
+ async fetchTemplate() {
12
+ const cacheKey = `${this.config.provider}:${this.config.model}`;
13
+ if (GenericLLMProvider.templateCache.has(cacheKey)) {
14
+ return GenericLLMProvider.templateCache.get(cacheKey);
15
+ }
16
+ // Need an auth token to call the backend APIs
17
+ const headers = {
18
+ 'Content-Type': 'application/json'
19
+ };
20
+ if (this.backendAuthToken) {
21
+ headers['Authorization'] = `Bearer ${this.backendAuthToken}`;
22
+ }
23
+ const qs = new URLSearchParams({
24
+ provider: this.config.provider,
25
+ model: this.config.model
26
+ });
27
+ const resp = await fetch(`${this.backendApiUrl}/api/v1/cyber-soul/llm-models/template?${qs.toString()}`, {
28
+ headers
29
+ });
30
+ if (!resp.ok) {
31
+ throw new Error(`Failed to fetch LLM generic template: ${resp.status}`);
32
+ }
33
+ const template = await resp.json();
34
+ GenericLLMProvider.templateCache.set(cacheKey, template);
35
+ return template;
36
+ }
37
+ extractResponse(data, responsePath) {
38
+ const parts = responsePath.split('.');
39
+ let cursor = data;
40
+ for (const part of parts) {
41
+ if (cursor === undefined || cursor === null)
42
+ return '';
43
+ cursor = cursor[part];
44
+ }
45
+ if (typeof cursor !== 'string') {
46
+ throw new Error(`Extraction resulted in non-string type: ${typeof cursor}`);
47
+ }
48
+ return cursor;
49
+ }
50
+ async generate(messages, maxTokens = 1500, temperature = 0.7) {
51
+ const template = await this.fetchTemplate();
52
+ const headers = { ...template.headersTemplate };
53
+ if (this.config.apiKey) {
54
+ for (const key of Object.keys(headers)) {
55
+ if (typeof headers[key] === 'string') {
56
+ headers[key] = headers[key].replace('{{apiKey}}', this.config.apiKey);
57
+ }
58
+ }
59
+ }
60
+ const payload = { ...template.basePayload };
61
+ if (this.config.customSettings) {
62
+ Object.assign(payload, this.config.customSettings);
63
+ }
64
+ // We only explicitly map messages. Parameters like temperature or max_tokens
65
+ // should be defined in basePayload, customSettings, or configured via the UI.
66
+ if (!payload.messages || (Array.isArray(payload.messages) && payload.messages.length === 0)) {
67
+ payload.messages = messages;
68
+ }
69
+ const response = await fetch(template.apiUrl, {
70
+ method: 'POST',
71
+ headers,
72
+ body: JSON.stringify(payload)
73
+ });
74
+ if (!response.ok) {
75
+ throw new Error(`Generic API returned status: ${response.status}`);
76
+ }
77
+ const data = await response.json();
78
+ try {
79
+ return this.extractResponse(data, template.responsePath || 'choices.0.message.content');
80
+ }
81
+ catch (e) {
82
+ throw new Error(`Failed to extract response. Error: ${e?.message}`);
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,14 @@
1
+ import { BaseLLMProvider, GenericLLMConfig } from '../types.js';
2
+ export declare class GenericLLMProvider implements BaseLLMProvider {
3
+ private config;
4
+ private backendApiUrl;
5
+ private backendAuthToken?;
6
+ private static templateCache;
7
+ constructor(config: GenericLLMConfig, backendApiUrl: string, backendAuthToken?: string | undefined);
8
+ private fetchTemplate;
9
+ private extractResponse;
10
+ generate(messages: {
11
+ role: string;
12
+ content: string;
13
+ }[], maxTokens?: number, temperature?: number): Promise<string>;
14
+ }
@@ -0,0 +1,85 @@
1
+ export class GenericLLMProvider {
2
+ config;
3
+ backendApiUrl;
4
+ backendAuthToken;
5
+ static templateCache = new Map();
6
+ constructor(config, backendApiUrl, backendAuthToken) {
7
+ this.config = config;
8
+ this.backendApiUrl = backendApiUrl;
9
+ this.backendAuthToken = backendAuthToken;
10
+ }
11
+ async fetchTemplate() {
12
+ const cacheKey = `${this.config.provider}:${this.config.model}`;
13
+ if (GenericLLMProvider.templateCache.has(cacheKey)) {
14
+ return GenericLLMProvider.templateCache.get(cacheKey);
15
+ }
16
+ // Need an auth token to call the backend APIs
17
+ const headers = {
18
+ 'Content-Type': 'application/json'
19
+ };
20
+ if (this.backendAuthToken) {
21
+ headers['Authorization'] = `Bearer ${this.backendAuthToken}`;
22
+ }
23
+ const qs = new URLSearchParams({
24
+ provider: this.config.provider,
25
+ model: this.config.model || ''
26
+ });
27
+ const resp = await fetch(`${this.backendApiUrl}/api/v1/cyber-soul/llm-models/template?${qs.toString()}`, {
28
+ headers
29
+ });
30
+ if (!resp.ok) {
31
+ throw new Error(`Failed to fetch LLM generic template: ${resp.status}`);
32
+ }
33
+ const template = await resp.json();
34
+ GenericLLMProvider.templateCache.set(cacheKey, template);
35
+ return template;
36
+ }
37
+ extractResponse(data, responsePath) {
38
+ const parts = responsePath.split('.');
39
+ let cursor = data;
40
+ for (const part of parts) {
41
+ if (cursor === undefined || cursor === null)
42
+ return '';
43
+ cursor = cursor[part];
44
+ }
45
+ if (typeof cursor !== 'string') {
46
+ throw new Error(`Extraction resulted in non-string type: ${typeof cursor}`);
47
+ }
48
+ return cursor;
49
+ }
50
+ async generate(messages, maxTokens = 1500, temperature = 0.7) {
51
+ if (!this.config.apiKey) {
52
+ throw new Error("Missing Generic Provider API Key");
53
+ }
54
+ const template = await this.fetchTemplate();
55
+ const headers = { ...template.headersTemplate };
56
+ for (const key of Object.keys(headers)) {
57
+ if (typeof headers[key] === 'string') {
58
+ headers[key] = headers[key].replace('{{apiKey}}', this.config.apiKey);
59
+ }
60
+ }
61
+ const payload = { ...template.basePayload };
62
+ if (this.config.customSettings) {
63
+ Object.assign(payload, this.config.customSettings);
64
+ }
65
+ // We only explicitly map messages. Parameters like temperature or max_tokens
66
+ // should be defined in basePayload, customSettings, or configured via the UI.
67
+ if (!payload.messages)
68
+ payload.messages = messages;
69
+ const response = await fetch(template.apiUrl, {
70
+ method: 'POST',
71
+ headers,
72
+ body: JSON.stringify(payload)
73
+ });
74
+ if (!response.ok) {
75
+ throw new Error(`Generic API returned status: ${response.status}`);
76
+ }
77
+ const data = await response.json();
78
+ try {
79
+ return this.extractResponse(data, template.responsePath || 'choices.0.message.content');
80
+ }
81
+ catch (e) {
82
+ throw new Error(`Failed to extract response. Error: ${e?.message}`);
83
+ }
84
+ }
85
+ }
package/dist/types.d.ts CHANGED
@@ -1,12 +1,13 @@
1
- export interface LLMConfig {
2
- provider: "minimax";
1
+ export interface GenericLLMConfig {
2
+ provider: string;
3
3
  apiKey: string;
4
4
  model: string;
5
+ customSettings?: Record<string, any>;
5
6
  }
6
7
  export interface CyberSoulClientConfig {
7
8
  characterKey: string;
8
9
  backendUrl: string;
9
- llmConfig: LLMConfig;
10
+ llmConfig: GenericLLMConfig;
10
11
  requestTimeoutMs?: number;
11
12
  maxRetries?: number;
12
13
  }
@@ -61,10 +62,21 @@ export interface OndemandEventResponse {
61
62
  scheduledDateStr?: string;
62
63
  error?: string;
63
64
  }
65
+ export declare enum WardrobeCategory {
66
+ CASUAL = "CASUAL",
67
+ FORMAL = "FORMAL",
68
+ WORKWEAR = "WORKWEAR",
69
+ SPORTSWEAR = "SPORTSWEAR",
70
+ SWIMWEAR = "SWIMWEAR",
71
+ COSTUME = "COSTUME",
72
+ SLEEPWEAR = "SLEEPWEAR",
73
+ INTIMATE = "INTIMATE",
74
+ DAILY = "DAILY"
75
+ }
64
76
  export interface WardrobeItem {
65
77
  id: string;
66
78
  itemName: string;
67
- category: string;
79
+ category: WardrobeCategory;
68
80
  promptModifier: string;
69
81
  }
70
82
  export interface InteractResponse {
@@ -73,6 +85,7 @@ export interface InteractResponse {
73
85
  actionText?: string;
74
86
  imageUrl?: string;
75
87
  audioUrl?: string;
88
+ likePreviousPicture?: boolean;
76
89
  durationSec?: number;
77
90
  triggeredEvent?: {
78
91
  eventTitle?: string;
@@ -93,6 +106,7 @@ export interface DispatcherIntent {
93
106
  textResponse?: string;
94
107
  actionText?: string;
95
108
  imageParams?: any;
109
+ likePreviousPicture?: boolean;
96
110
  voiceArgs?: VoiceArgs | null;
97
111
  giftOutfit?: {
98
112
  descriptionText: string;
@@ -199,6 +213,7 @@ export interface CharacterState {
199
213
  occupation?: string;
200
214
  hobby?: string;
201
215
  personality_traits?: string;
216
+ appearance?: string;
202
217
  interaction_boundaries?: string;
203
218
  communication_style?: string;
204
219
  user_codex?: UserCodex;
@@ -262,3 +277,8 @@ export interface ICharacterProfile {
262
277
  visualCustomConfig?: Record<string, Record<string, unknown>>;
263
278
  [key: string]: unknown;
264
279
  }
280
+ export interface LikedPicture {
281
+ url: string;
282
+ date: string;
283
+ mediaId?: string;
284
+ }
package/dist/types.js CHANGED
@@ -5,3 +5,15 @@ export var InteractRequestType;
5
5
  InteractRequestType["IMAGE"] = "image";
6
6
  InteractRequestType["VOICE"] = "voice";
7
7
  })(InteractRequestType || (InteractRequestType = {}));
8
+ export var WardrobeCategory;
9
+ (function (WardrobeCategory) {
10
+ WardrobeCategory["CASUAL"] = "CASUAL";
11
+ WardrobeCategory["FORMAL"] = "FORMAL";
12
+ WardrobeCategory["WORKWEAR"] = "WORKWEAR";
13
+ WardrobeCategory["SPORTSWEAR"] = "SPORTSWEAR";
14
+ WardrobeCategory["SWIMWEAR"] = "SWIMWEAR";
15
+ WardrobeCategory["COSTUME"] = "COSTUME";
16
+ WardrobeCategory["SLEEPWEAR"] = "SLEEPWEAR";
17
+ WardrobeCategory["INTIMATE"] = "INTIMATE";
18
+ WardrobeCategory["DAILY"] = "DAILY";
19
+ })(WardrobeCategory || (WardrobeCategory = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@space3-npm/cybersoul-client",
3
- "version": "1.2.9",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",