unified-entity-card 0.1.0 → 0.1.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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Lightweight helpers for creating and validating Unified Entity Cards.
4
4
 
5
+ npm: https://www.npmjs.com/package/unified-entity-card
6
+
5
7
  ## Usage
6
8
 
7
9
  ```js
@@ -20,3 +22,5 @@ if (!result.ok) {
20
22
  ```
21
23
 
22
24
  `app_specific_settings` is treated as an opaque object. Validation focuses on schema, kind, and payload structure.
25
+
26
+ If `systemPrompt` is a template ID, pass `{ systemPromptIsId: true }` to `createCharacterUEC`. It will store the prompt as `_ID:<id>`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unified-entity-card",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Unified Entity Card helpers for creating and validating UEC files.",
5
5
  "keywords": [
6
6
  "uec",
package/src/index.d.ts CHANGED
@@ -37,11 +37,18 @@ export interface CharacterScene {
37
37
  content: string;
38
38
  direction?: string;
39
39
  createdAt?: number;
40
- variants?: unknown[];
40
+ variants?: MessageVariant[];
41
41
  selectedVariantId?: string | null;
42
42
  [key: string]: unknown;
43
43
  }
44
44
 
45
+ export interface MessageVariant {
46
+ id: string;
47
+ content: string;
48
+ createdAt: number;
49
+ [key: string]: unknown;
50
+ }
51
+
45
52
  export interface VoiceConfig {
46
53
  source: string;
47
54
  providerId: string;
@@ -53,15 +60,15 @@ export interface CharacterPayload {
53
60
  id: string;
54
61
  name: string;
55
62
  description?: string;
56
- avatarPath?: string | null;
57
- backgroundImagePath?: string | null;
63
+ avatar?: string | null;
64
+ chatBackground?: string | null;
58
65
  definitions?: string;
59
66
  tags?: string[];
60
67
  rules?: string[];
61
68
  scenes?: CharacterScene[];
62
69
  defaultSceneId?: string | null;
63
70
  defaultModelId?: string | null;
64
- promptTemplateId?: string | null;
71
+ systemPrompt?: string | null;
65
72
  voiceConfig?: VoiceConfig | null;
66
73
  voiceAutoplay?: boolean;
67
74
  createdAt?: number;
@@ -73,7 +80,7 @@ export interface PersonaPayload {
73
80
  id: string;
74
81
  title: string;
75
82
  description?: string;
76
- avatarPath?: string | null;
83
+ avatar?: string | null;
77
84
  isDefault?: boolean;
78
85
  createdAt?: number;
79
86
  updatedAt?: number;
@@ -116,6 +123,7 @@ export function createUEC(input: {
116
123
  appSpecificSettings?: UecAppSpecificSettings;
117
124
  meta?: UecMeta;
118
125
  extensions?: UecExtensions;
126
+ systemPromptIsId?: boolean;
119
127
  }): UecUnion;
120
128
 
121
129
  export function createCharacterUEC(
@@ -125,7 +133,8 @@ export function createCharacterUEC(
125
133
  appSpecificSettings?: UecAppSpecificSettings;
126
134
  meta?: UecMeta;
127
135
  extensions?: UecExtensions;
128
- }
136
+ systemPromptIsId?: boolean;
137
+ },
129
138
  ): UecCharacter;
130
139
 
131
140
  export function createPersonaUEC(
@@ -135,11 +144,17 @@ export function createPersonaUEC(
135
144
  appSpecificSettings?: UecAppSpecificSettings;
136
145
  meta?: UecMeta;
137
146
  extensions?: UecExtensions;
138
- }
147
+ },
139
148
  ): UecPersona;
140
149
 
141
- export function validateUEC(value: unknown, options?: ValidateOptions): ValidationResult;
150
+ export function validateUEC(
151
+ value: unknown,
152
+ options?: ValidateOptions,
153
+ ): ValidationResult;
142
154
 
143
- export function isUEC(value: unknown, options?: ValidateOptions): value is UecUnion;
155
+ export function isUEC(
156
+ value: unknown,
157
+ options?: ValidateOptions,
158
+ ): value is UecUnion;
144
159
 
145
160
  export function assertUEC(value: unknown, options?: ValidateOptions): UecUnion;
package/src/index.js CHANGED
@@ -23,15 +23,33 @@ const optionalStringArray = (value) =>
23
23
  value === undefined ||
24
24
  (Array.isArray(value) && value.every((item) => isString(item)));
25
25
 
26
- const optionalUnknownArray = (value) =>
27
- value === undefined || (Array.isArray(value) && value.length >= 0);
28
-
29
26
  const optionalObject = (value) => value === undefined || isPlainObject(value);
30
27
 
31
28
  const pushError = (errors, path, message) => {
32
29
  errors.push(`${path}: ${message}`);
33
30
  };
34
31
 
32
+ const normalizeSystemPrompt = (payload, systemPromptIsId) => {
33
+ if (!systemPromptIsId) {
34
+ return payload;
35
+ }
36
+
37
+ if (!isPlainObject(payload)) {
38
+ return payload;
39
+ }
40
+
41
+ const systemPrompt = payload.systemPrompt;
42
+ if (!isString(systemPrompt)) {
43
+ return payload;
44
+ }
45
+
46
+ if (systemPrompt.startsWith("_ID:")) {
47
+ return payload;
48
+ }
49
+
50
+ return { ...payload, systemPrompt: `_ID:${systemPrompt}` };
51
+ };
52
+
35
53
  const validateSchema = (schema, errors) => {
36
54
  if (!isPlainObject(schema)) {
37
55
  pushError(errors, "schema", "must be an object");
@@ -122,8 +140,30 @@ const validateScene = (scene, path, errors, options) => {
122
140
  pushError(errors, `${path}.createdAt`, "must be a number");
123
141
  }
124
142
 
125
- if (!optionalUnknownArray(scene.variants)) {
126
- pushError(errors, `${path}.variants`, "must be an array");
143
+ if (scene.variants !== undefined) {
144
+ if (!Array.isArray(scene.variants)) {
145
+ pushError(errors, `${path}.variants`, "must be an array");
146
+ } else {
147
+ scene.variants.forEach((variant, index) => {
148
+ const variantPath = `${path}.variants[${index}]`;
149
+ if (!isPlainObject(variant)) {
150
+ pushError(errors, variantPath, "must be an object");
151
+ return;
152
+ }
153
+
154
+ if (!isString(variant.id)) {
155
+ pushError(errors, `${variantPath}.id`, "must be a string");
156
+ }
157
+
158
+ if (!isString(variant.content)) {
159
+ pushError(errors, `${variantPath}.content`, "must be a string");
160
+ }
161
+
162
+ if (!isNumber(variant.createdAt)) {
163
+ pushError(errors, `${variantPath}.createdAt`, "must be a number");
164
+ }
165
+ });
166
+ }
127
167
  }
128
168
 
129
169
  if (
@@ -192,16 +232,12 @@ const validateCharacterPayload = (payload, errors, options) => {
192
232
  pushError(errors, "payload.tags", "must be an array of strings");
193
233
  }
194
234
 
195
- if (!optionalString(payload.avatarPath)) {
196
- pushError(errors, "payload.avatarPath", "must be a string or null");
235
+ if (!optionalString(payload.avatar)) {
236
+ pushError(errors, "payload.avatar", "must be a string or null");
197
237
  }
198
238
 
199
- if (!optionalString(payload.backgroundImagePath)) {
200
- pushError(
201
- errors,
202
- "payload.backgroundImagePath",
203
- "must be a string or null",
204
- );
239
+ if (!optionalString(payload.chatBackground)) {
240
+ pushError(errors, "payload.chatBackground", "must be a string or null");
205
241
  }
206
242
 
207
243
  if (!optionalStringArray(payload.rules)) {
@@ -226,8 +262,8 @@ const validateCharacterPayload = (payload, errors, options) => {
226
262
  pushError(errors, "payload.defaultModelId", "must be a string or null");
227
263
  }
228
264
 
229
- if (!optionalString(payload.promptTemplateId)) {
230
- pushError(errors, "payload.promptTemplateId", "must be a string or null");
265
+ if (!optionalString(payload.systemPrompt)) {
266
+ pushError(errors, "payload.systemPrompt", "must be a string or null");
231
267
  }
232
268
 
233
269
  validateVoiceConfig(payload.voiceConfig, errors);
@@ -285,8 +321,8 @@ const validatePersonaPayload = (payload, errors, options) => {
285
321
  pushError(errors, "payload.description", "must be a string");
286
322
  }
287
323
 
288
- if (!optionalString(payload.avatarPath)) {
289
- pushError(errors, "payload.avatarPath", "must be a string or null");
324
+ if (!optionalString(payload.avatar)) {
325
+ pushError(errors, "payload.avatar", "must be a string or null");
290
326
  }
291
327
 
292
328
  if (!optionalBoolean(payload.isDefault)) {
@@ -323,6 +359,7 @@ export const createUEC = ({
323
359
  appSpecificSettings,
324
360
  meta,
325
361
  extensions,
362
+ systemPromptIsId,
326
363
  } = {}) => {
327
364
  if (!kind) {
328
365
  throw new Error("kind is required");
@@ -332,10 +369,15 @@ export const createUEC = ({
332
369
  throw new Error("payload must be an object");
333
370
  }
334
371
 
372
+ const normalizedPayload =
373
+ kind === "character"
374
+ ? normalizeSystemPrompt(payload, systemPromptIsId)
375
+ : payload;
376
+
335
377
  return {
336
378
  schema: { ...DEFAULT_SCHEMA, ...(schema || {}) },
337
379
  kind,
338
- payload,
380
+ payload: normalizedPayload,
339
381
  app_specific_settings: appSpecificSettings || {},
340
382
  meta: meta || {},
341
383
  extensions: extensions || {},