@character-foundry/character-foundry 0.4.1 → 0.4.2-dev.1765997746
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/charx.cjs +17 -38
- package/dist/charx.cjs.map +1 -1
- package/dist/charx.d.cts +27 -18
- package/dist/charx.d.ts +27 -18
- package/dist/charx.js +17 -38
- package/dist/charx.js.map +1 -1
- package/dist/exporter.cjs +36 -40
- package/dist/exporter.cjs.map +1 -1
- package/dist/exporter.d.cts +27 -18
- package/dist/exporter.d.ts +27 -18
- package/dist/exporter.js +36 -40
- package/dist/exporter.js.map +1 -1
- package/dist/federation.cjs +104 -36
- package/dist/federation.cjs.map +1 -1
- package/dist/federation.d.cts +62 -18
- package/dist/federation.d.ts +62 -18
- package/dist/federation.js +104 -36
- package/dist/federation.js.map +1 -1
- package/dist/index.cjs +36 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -42
- package/dist/index.d.ts +63 -42
- package/dist/index.js +36 -40
- package/dist/index.js.map +1 -1
- package/dist/loader.cjs +103 -17
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.d.cts +56 -28
- package/dist/loader.d.ts +56 -28
- package/dist/loader.js +103 -17
- package/dist/loader.js.map +1 -1
- package/dist/lorebook.d.cts +51 -34
- package/dist/lorebook.d.ts +51 -34
- package/dist/normalizer.cjs +4 -4
- package/dist/normalizer.cjs.map +1 -1
- package/dist/normalizer.d.cts +90 -60
- package/dist/normalizer.d.ts +90 -60
- package/dist/normalizer.js +4 -4
- package/dist/normalizer.js.map +1 -1
- package/dist/png.cjs +4 -4
- package/dist/png.cjs.map +1 -1
- package/dist/png.d.cts +48 -32
- package/dist/png.d.ts +48 -32
- package/dist/png.js +4 -4
- package/dist/png.js.map +1 -1
- package/dist/schemas.cjs +9 -9
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +144 -96
- package/dist/schemas.d.ts +144 -96
- package/dist/schemas.js +9 -9
- package/dist/schemas.js.map +1 -1
- package/dist/voxta.cjs +23 -6
- package/dist/voxta.cjs.map +1 -1
- package/dist/voxta.d.cts +42 -28
- package/dist/voxta.d.ts +42 -28
- package/dist/voxta.js +23 -6
- package/dist/voxta.js.map +1 -1
- package/package.json +6 -6
package/dist/loader.js
CHANGED
|
@@ -462,7 +462,7 @@ var CCv2LorebookEntrySchema = z2.object({
|
|
|
462
462
|
content: z2.string(),
|
|
463
463
|
enabled: z2.boolean().default(true),
|
|
464
464
|
// Default to enabled if missing
|
|
465
|
-
insertion_order: z2.
|
|
465
|
+
insertion_order: z2.preprocess((v) => v ?? 0, z2.number().int()),
|
|
466
466
|
// Optional fields - be lenient with nulls since wild data has them
|
|
467
467
|
extensions: z2.record(z2.unknown()).optional(),
|
|
468
468
|
case_sensitive: z2.boolean().nullable().optional(),
|
|
@@ -473,7 +473,7 @@ var CCv2LorebookEntrySchema = z2.object({
|
|
|
473
473
|
selective: z2.boolean().nullable().optional(),
|
|
474
474
|
secondary_keys: z2.array(z2.string()).nullable().optional(),
|
|
475
475
|
constant: z2.boolean().nullable().optional(),
|
|
476
|
-
position: z2.union([z2.enum(["before_char", "after_char"]), z2.number().int(), z2.literal("")]).nullable().optional()
|
|
476
|
+
position: z2.union([z2.enum(["before_char", "after_char", "in_chat"]), z2.number().int(), z2.literal("")]).nullable().optional()
|
|
477
477
|
}).passthrough();
|
|
478
478
|
var CCv2CharacterBookSchema = z2.object({
|
|
479
479
|
name: z2.string().optional(),
|
|
@@ -527,7 +527,7 @@ var CCv3LorebookEntrySchema = z3.object({
|
|
|
527
527
|
content: z3.string(),
|
|
528
528
|
enabled: z3.boolean().default(true),
|
|
529
529
|
// Default to enabled if missing
|
|
530
|
-
insertion_order: z3.
|
|
530
|
+
insertion_order: z3.preprocess((v) => v ?? 0, z3.number().int()),
|
|
531
531
|
// Optional fields - be lenient with nulls since wild data has them
|
|
532
532
|
case_sensitive: z3.boolean().nullable().optional(),
|
|
533
533
|
name: z3.string().optional(),
|
|
@@ -537,7 +537,7 @@ var CCv3LorebookEntrySchema = z3.object({
|
|
|
537
537
|
selective: z3.boolean().nullable().optional(),
|
|
538
538
|
secondary_keys: z3.array(z3.string()).nullable().optional(),
|
|
539
539
|
constant: z3.boolean().nullable().optional(),
|
|
540
|
-
position: z3.union([z3.enum(["before_char", "after_char"]), z3.number().int(), z3.literal("")]).nullable().optional(),
|
|
540
|
+
position: z3.union([z3.enum(["before_char", "after_char", "in_chat"]), z3.number().int(), z3.literal("")]).nullable().optional(),
|
|
541
541
|
extensions: z3.record(z3.unknown()).optional(),
|
|
542
542
|
// v3 specific - also lenient with types since SillyTavern uses numbers for enums
|
|
543
543
|
automation_id: z3.string().optional(),
|
|
@@ -8697,7 +8697,7 @@ function defaultTokenCounter(_card) {
|
|
|
8697
8697
|
total: 0
|
|
8698
8698
|
};
|
|
8699
8699
|
}
|
|
8700
|
-
function
|
|
8700
|
+
function getCanonicalContentV1(card) {
|
|
8701
8701
|
const normalized = {
|
|
8702
8702
|
name: card.data.name,
|
|
8703
8703
|
description: card.data.description || "",
|
|
@@ -8719,6 +8719,69 @@ function getCanonicalContent(card) {
|
|
|
8719
8719
|
};
|
|
8720
8720
|
return JSON.stringify(normalized, Object.keys(normalized).sort());
|
|
8721
8721
|
}
|
|
8722
|
+
function stableStringify(value) {
|
|
8723
|
+
if (value === null) return "null";
|
|
8724
|
+
switch (typeof value) {
|
|
8725
|
+
case "string":
|
|
8726
|
+
return JSON.stringify(value);
|
|
8727
|
+
case "number":
|
|
8728
|
+
return Number.isFinite(value) ? String(value) : "null";
|
|
8729
|
+
case "boolean":
|
|
8730
|
+
return value ? "true" : "false";
|
|
8731
|
+
case "bigint":
|
|
8732
|
+
return JSON.stringify(value.toString());
|
|
8733
|
+
case "undefined":
|
|
8734
|
+
case "function":
|
|
8735
|
+
case "symbol":
|
|
8736
|
+
return "null";
|
|
8737
|
+
case "object": {
|
|
8738
|
+
if (Array.isArray(value)) {
|
|
8739
|
+
const parts2 = value.map((item) => {
|
|
8740
|
+
if (item === void 0 || typeof item === "function" || typeof item === "symbol") {
|
|
8741
|
+
return "null";
|
|
8742
|
+
}
|
|
8743
|
+
return stableStringify(item);
|
|
8744
|
+
});
|
|
8745
|
+
return `[${parts2.join(",")}]`;
|
|
8746
|
+
}
|
|
8747
|
+
const obj = value;
|
|
8748
|
+
const keys = Object.keys(obj).sort();
|
|
8749
|
+
const parts = [];
|
|
8750
|
+
for (const key of keys) {
|
|
8751
|
+
const v = obj[key];
|
|
8752
|
+
if (v === void 0 || typeof v === "function" || typeof v === "symbol") {
|
|
8753
|
+
continue;
|
|
8754
|
+
}
|
|
8755
|
+
parts.push(`${JSON.stringify(key)}:${stableStringify(v)}`);
|
|
8756
|
+
}
|
|
8757
|
+
return `{${parts.join(",")}}`;
|
|
8758
|
+
}
|
|
8759
|
+
default:
|
|
8760
|
+
return "null";
|
|
8761
|
+
}
|
|
8762
|
+
}
|
|
8763
|
+
function getCanonicalContentV2(card) {
|
|
8764
|
+
const normalized = {
|
|
8765
|
+
name: card.data.name,
|
|
8766
|
+
description: card.data.description || "",
|
|
8767
|
+
personality: card.data.personality || "",
|
|
8768
|
+
scenario: card.data.scenario || "",
|
|
8769
|
+
first_mes: card.data.first_mes || "",
|
|
8770
|
+
mes_example: card.data.mes_example || "",
|
|
8771
|
+
system_prompt: card.data.system_prompt || "",
|
|
8772
|
+
post_history_instructions: card.data.post_history_instructions || "",
|
|
8773
|
+
alternate_greetings: card.data.alternate_greetings || [],
|
|
8774
|
+
character_book: card.data.character_book ? {
|
|
8775
|
+
entries: (card.data.character_book.entries || []).map((e) => ({
|
|
8776
|
+
keys: e.keys,
|
|
8777
|
+
content: e.content,
|
|
8778
|
+
enabled: e.enabled
|
|
8779
|
+
}))
|
|
8780
|
+
} : null,
|
|
8781
|
+
creator_notes: card.data.creator_notes || ""
|
|
8782
|
+
};
|
|
8783
|
+
return stableStringify(normalized);
|
|
8784
|
+
}
|
|
8722
8785
|
function isWithinTolerance(clientValue, computedValue, tolerance) {
|
|
8723
8786
|
if (clientValue === void 0) return false;
|
|
8724
8787
|
if (computedValue === 0) return clientValue === 0;
|
|
@@ -8739,15 +8802,18 @@ async function validateClientMetadata(clientMetadata, parseResult, options = {})
|
|
|
8739
8802
|
const warnings = [];
|
|
8740
8803
|
const errors = [];
|
|
8741
8804
|
const computedTokens = countTokens(card);
|
|
8742
|
-
const
|
|
8743
|
-
const
|
|
8805
|
+
const canonicalContentV1 = getCanonicalContentV1(card);
|
|
8806
|
+
const canonicalContentV2 = getCanonicalContentV2(card);
|
|
8807
|
+
const computedHashV1 = await computeHash(canonicalContentV1);
|
|
8808
|
+
const computedHashV2 = await computeHash(canonicalContentV2);
|
|
8744
8809
|
const entries = card.data.character_book?.entries || [];
|
|
8745
8810
|
const computedHasLorebook = entries.length > 0;
|
|
8746
8811
|
const computedLorebookCount = entries.length;
|
|
8747
8812
|
const authoritative = {
|
|
8748
8813
|
name: card.data.name,
|
|
8749
8814
|
tokens: computedTokens,
|
|
8750
|
-
contentHash:
|
|
8815
|
+
contentHash: computedHashV1,
|
|
8816
|
+
contentHashV2: computedHashV2,
|
|
8751
8817
|
hasLorebook: computedHasLorebook,
|
|
8752
8818
|
lorebookEntriesCount: computedLorebookCount
|
|
8753
8819
|
};
|
|
@@ -8759,21 +8825,27 @@ async function validateClientMetadata(clientMetadata, parseResult, options = {})
|
|
|
8759
8825
|
withinTolerance: false
|
|
8760
8826
|
});
|
|
8761
8827
|
}
|
|
8762
|
-
|
|
8828
|
+
const matchesV1 = clientMetadata.contentHash === computedHashV1;
|
|
8829
|
+
const matchesV2 = clientMetadata.contentHash === computedHashV2;
|
|
8830
|
+
if (!matchesV1 && !matchesV2) {
|
|
8763
8831
|
const disc = {
|
|
8764
8832
|
field: "contentHash",
|
|
8765
8833
|
clientValue: clientMetadata.contentHash,
|
|
8766
|
-
computedValue:
|
|
8834
|
+
computedValue: computedHashV1,
|
|
8767
8835
|
withinTolerance: false
|
|
8768
8836
|
};
|
|
8769
8837
|
discrepancies.push(disc);
|
|
8770
8838
|
if (allowHashMismatch) {
|
|
8771
8839
|
warnings.push(
|
|
8772
|
-
`Content hash mismatch: client=${clientMetadata.contentHash.substring(0, 8)}..., server=${
|
|
8840
|
+
`Content hash mismatch: client=${clientMetadata.contentHash.substring(0, 8)}..., server(v1)=${computedHashV1.substring(0, 8)}..., server(v2)=${computedHashV2.substring(0, 8)}...`
|
|
8773
8841
|
);
|
|
8774
8842
|
} else {
|
|
8775
8843
|
errors.push("Content hash mismatch - possible tampering or encoding difference");
|
|
8776
8844
|
}
|
|
8845
|
+
} else if (matchesV1 && !matchesV2) {
|
|
8846
|
+
warnings.push(
|
|
8847
|
+
"Client contentHash matches legacy v1 canonicalization. Prefer authoritative.contentHashV2 for new storage."
|
|
8848
|
+
);
|
|
8777
8849
|
}
|
|
8778
8850
|
const tokenFields = [
|
|
8779
8851
|
"description",
|
|
@@ -8854,7 +8926,11 @@ async function validateClientMetadata(clientMetadata, parseResult, options = {})
|
|
|
8854
8926
|
};
|
|
8855
8927
|
}
|
|
8856
8928
|
async function computeContentHash(card) {
|
|
8857
|
-
const content =
|
|
8929
|
+
const content = getCanonicalContentV1(card);
|
|
8930
|
+
return sha256Hash(content);
|
|
8931
|
+
}
|
|
8932
|
+
async function computeContentHashV2(card) {
|
|
8933
|
+
const content = getCanonicalContentV2(card);
|
|
8858
8934
|
return sha256Hash(content);
|
|
8859
8935
|
}
|
|
8860
8936
|
function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
@@ -8870,15 +8946,18 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8870
8946
|
const warnings = [];
|
|
8871
8947
|
const errors = [];
|
|
8872
8948
|
const computedTokens = countTokens(card);
|
|
8873
|
-
const
|
|
8874
|
-
const
|
|
8949
|
+
const canonicalContentV1 = getCanonicalContentV1(card);
|
|
8950
|
+
const canonicalContentV2 = getCanonicalContentV2(card);
|
|
8951
|
+
const computedHashV1 = computeHash(canonicalContentV1);
|
|
8952
|
+
const computedHashV2 = computeHash(canonicalContentV2);
|
|
8875
8953
|
const entries = card.data.character_book?.entries || [];
|
|
8876
8954
|
const computedHasLorebook = entries.length > 0;
|
|
8877
8955
|
const computedLorebookCount = entries.length;
|
|
8878
8956
|
const authoritative = {
|
|
8879
8957
|
name: card.data.name,
|
|
8880
8958
|
tokens: computedTokens,
|
|
8881
|
-
contentHash:
|
|
8959
|
+
contentHash: computedHashV1,
|
|
8960
|
+
contentHashV2: computedHashV2,
|
|
8882
8961
|
hasLorebook: computedHasLorebook,
|
|
8883
8962
|
lorebookEntriesCount: computedLorebookCount
|
|
8884
8963
|
};
|
|
@@ -8890,11 +8969,13 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8890
8969
|
withinTolerance: false
|
|
8891
8970
|
});
|
|
8892
8971
|
}
|
|
8893
|
-
|
|
8972
|
+
const matchesV1 = clientMetadata.contentHash === computedHashV1;
|
|
8973
|
+
const matchesV2 = clientMetadata.contentHash === computedHashV2;
|
|
8974
|
+
if (!matchesV1 && !matchesV2) {
|
|
8894
8975
|
discrepancies.push({
|
|
8895
8976
|
field: "contentHash",
|
|
8896
8977
|
clientValue: clientMetadata.contentHash,
|
|
8897
|
-
computedValue:
|
|
8978
|
+
computedValue: computedHashV1,
|
|
8898
8979
|
withinTolerance: false
|
|
8899
8980
|
});
|
|
8900
8981
|
if (allowHashMismatch) {
|
|
@@ -8902,6 +8983,10 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8902
8983
|
} else {
|
|
8903
8984
|
errors.push("Content hash mismatch");
|
|
8904
8985
|
}
|
|
8986
|
+
} else if (matchesV1 && !matchesV2) {
|
|
8987
|
+
warnings.push(
|
|
8988
|
+
"Client contentHash matches legacy v1 canonicalization. Prefer authoritative.contentHashV2 for new storage."
|
|
8989
|
+
);
|
|
8905
8990
|
}
|
|
8906
8991
|
const tokenFields = [
|
|
8907
8992
|
"description",
|
|
@@ -8970,6 +9055,7 @@ function validateClientMetadataSync(clientMetadata, parseResult, options) {
|
|
|
8970
9055
|
}
|
|
8971
9056
|
export {
|
|
8972
9057
|
computeContentHash,
|
|
9058
|
+
computeContentHashV2,
|
|
8973
9059
|
detectFormat,
|
|
8974
9060
|
getContainerFormat,
|
|
8975
9061
|
mightBeCard,
|