fast-tavern 0.1.0
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 +202 -0
- package/dist/index.cjs +647 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +462 -0
- package/dist/index.d.ts +462 -0
- package/dist/index.js +627 -0
- package/dist/index.js.map +1 -0
- package/package.json +31 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __export = (target, all) => {
|
|
5
|
+
for (var name in all)
|
|
6
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// src/core/channels/gemini.ts
|
|
10
|
+
function isGeminiContents(v) {
|
|
11
|
+
return Array.isArray(v) && v.every(
|
|
12
|
+
(x) => typeof x === "object" && x !== null && "role" in x && "parts" in x && Array.isArray(x.parts)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
function toInternalFromGemini(input) {
|
|
16
|
+
return (input || []).map((m) => ({
|
|
17
|
+
role: m.role,
|
|
18
|
+
parts: (m.parts || []).map((p) => ({ text: p.text ?? "" }))
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
function fromInternalToGemini(internal) {
|
|
22
|
+
return internal;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/core/channels/openai.ts
|
|
26
|
+
function isOpenAIMessages(v) {
|
|
27
|
+
return Array.isArray(v) && v.every(
|
|
28
|
+
(x) => typeof x === "object" && x !== null && "role" in x && "content" in x && typeof x.content === "string"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
function toInternalFromOpenAI(input) {
|
|
32
|
+
return (input || []).map((m) => ({
|
|
33
|
+
role: m.role === "assistant" ? "model" : m.role,
|
|
34
|
+
parts: [{ text: m.content ?? "" }]
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
function fromInternalToOpenAI(internal) {
|
|
38
|
+
return (internal || []).map((m) => ({
|
|
39
|
+
role: m.role === "model" ? "assistant" : m.role,
|
|
40
|
+
content: (m.parts || []).map((p) => p.text ?? "").join("")
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/core/channels/simple.ts
|
|
45
|
+
function isSimpleMessages(v) {
|
|
46
|
+
return Array.isArray(v) && v.every(
|
|
47
|
+
(x) => typeof x === "object" && x !== null && "role" in x && "text" in x && typeof x.text === "string"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function toInternalFromSimple(input) {
|
|
51
|
+
return (input || []).map((m) => ({
|
|
52
|
+
role: m.role === "assistant" || m.role === "model" ? "model" : m.role,
|
|
53
|
+
parts: [{ text: m.text ?? "" }]
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
function fromInternalToSimple(internal) {
|
|
57
|
+
return (internal || []).map((m) => ({
|
|
58
|
+
role: m.role,
|
|
59
|
+
text: (m.parts || []).map((p) => p.text ?? "").join("")
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/core/channels/tagged.ts
|
|
64
|
+
function isTaggedContents(v) {
|
|
65
|
+
return Array.isArray(v) && v.every(
|
|
66
|
+
(x) => typeof x === "object" && x !== null && "tag" in x && "target" in x && "text" in x
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function toInternalFromTagged(input) {
|
|
70
|
+
return (input || []).map((m) => ({
|
|
71
|
+
role: m.role,
|
|
72
|
+
parts: [{ text: m.text ?? "" }]
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
function fromInternalToTagged(_internal) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
"fromInternalToTagged is not supported: tagged output should be produced by prompt assembly stage."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/core/channels/text.ts
|
|
82
|
+
function isTextInput(v) {
|
|
83
|
+
return typeof v === "string" || Array.isArray(v) && v.every((x) => typeof x === "string");
|
|
84
|
+
}
|
|
85
|
+
function toInternalFromText(input) {
|
|
86
|
+
const text = Array.isArray(input) ? input.join("\n") : input ?? "";
|
|
87
|
+
return [{ role: "user", parts: [{ text }] }];
|
|
88
|
+
}
|
|
89
|
+
function fromInternalToText(internal) {
|
|
90
|
+
return (internal || []).map((m) => (m.parts || []).map((p) => p.text ?? "").join("")).join("\n");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/core/channels/detect.ts
|
|
94
|
+
function detectMessageFormat(input) {
|
|
95
|
+
if (isTextInput(input)) return "text";
|
|
96
|
+
if (isGeminiContents(input)) return "gemini";
|
|
97
|
+
if (isOpenAIMessages(input)) return "openai";
|
|
98
|
+
if (isTaggedContents(input)) return "tagged";
|
|
99
|
+
if (isSimpleMessages(input)) return "simple";
|
|
100
|
+
return "simple";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/core/convert.ts
|
|
104
|
+
function convertMessagesIn(input, format = "auto") {
|
|
105
|
+
const detected = format === "auto" ? detectMessageFormat(input) : format;
|
|
106
|
+
if (detected === "text") {
|
|
107
|
+
return { detected, internal: toInternalFromText(input) };
|
|
108
|
+
}
|
|
109
|
+
if (detected === "gemini") {
|
|
110
|
+
return { detected, internal: toInternalFromGemini(input) };
|
|
111
|
+
}
|
|
112
|
+
if (detected === "openai") {
|
|
113
|
+
return { detected, internal: toInternalFromOpenAI(input) };
|
|
114
|
+
}
|
|
115
|
+
if (detected === "tagged") {
|
|
116
|
+
return { detected, internal: toInternalFromTagged(input) };
|
|
117
|
+
}
|
|
118
|
+
return { detected, internal: toInternalFromSimple(input) };
|
|
119
|
+
}
|
|
120
|
+
function convertMessagesOut(internal, format) {
|
|
121
|
+
if (format === "gemini") return fromInternalToGemini(internal);
|
|
122
|
+
if (format === "openai") return fromInternalToOpenAI(internal);
|
|
123
|
+
if (format === "simple") return fromInternalToSimple(internal);
|
|
124
|
+
if (format === "text") return fromInternalToText(internal);
|
|
125
|
+
return internal;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/core/modules/history/factories.ts
|
|
129
|
+
var History = {
|
|
130
|
+
gemini: (messages) => ({
|
|
131
|
+
format: "gemini",
|
|
132
|
+
messages
|
|
133
|
+
}),
|
|
134
|
+
openai: (messages) => ({
|
|
135
|
+
format: "openai",
|
|
136
|
+
messages
|
|
137
|
+
}),
|
|
138
|
+
simple: (messages) => ({
|
|
139
|
+
format: "simple",
|
|
140
|
+
messages
|
|
141
|
+
}),
|
|
142
|
+
tagged: (messages) => ({
|
|
143
|
+
format: "tagged",
|
|
144
|
+
messages
|
|
145
|
+
}),
|
|
146
|
+
text: (text) => ({
|
|
147
|
+
format: "text",
|
|
148
|
+
text
|
|
149
|
+
}),
|
|
150
|
+
auto: (input) => ({
|
|
151
|
+
format: "auto",
|
|
152
|
+
input
|
|
153
|
+
})
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// src/core/modules/history/guards.ts
|
|
157
|
+
function isHistoryInput(v) {
|
|
158
|
+
return typeof v === "object" && v !== null && "format" in v && typeof v.format === "string";
|
|
159
|
+
}
|
|
160
|
+
function normalizeHistoryFormat(format) {
|
|
161
|
+
return format ?? "auto";
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/core/modules/worldbook/testCondition.ts
|
|
165
|
+
function testCondition(condition, text) {
|
|
166
|
+
if (!condition || condition.trim() === "") return true;
|
|
167
|
+
const kwMatch = condition.match(/<<keywords:(.+)>>/i);
|
|
168
|
+
if (kwMatch?.[1]) {
|
|
169
|
+
const keywords = kwMatch[1].split(",").map((k) => k.trim());
|
|
170
|
+
return keywords.some((k) => k && text.includes(k));
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const regex = new RegExp(condition, "i");
|
|
174
|
+
return regex.test(text);
|
|
175
|
+
} catch {
|
|
176
|
+
return text.includes(condition);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/core/modules/inputs/normalizeRegexes.ts
|
|
181
|
+
function isRegexRuleArray(v) {
|
|
182
|
+
return Array.isArray(v) && v.every((x) => typeof x === "object" && x !== null && "find_regex" in x);
|
|
183
|
+
}
|
|
184
|
+
function normalizeRegexes(input) {
|
|
185
|
+
if (!input) return [];
|
|
186
|
+
const files = [];
|
|
187
|
+
if (Array.isArray(input)) {
|
|
188
|
+
if (isRegexRuleArray(input)) {
|
|
189
|
+
files.push(input);
|
|
190
|
+
} else {
|
|
191
|
+
files.push(...input);
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
files.push(input);
|
|
195
|
+
}
|
|
196
|
+
const out = [];
|
|
197
|
+
for (const item of files) {
|
|
198
|
+
if (!item) continue;
|
|
199
|
+
if (isRegexRuleArray(item)) {
|
|
200
|
+
out.push(...item);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (typeof item === "object" && item !== null && "find_regex" in item) {
|
|
204
|
+
out.push(item);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (typeof item === "object" && item !== null && Array.isArray(item.regex_rules)) {
|
|
208
|
+
out.push(...item.regex_rules);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (typeof item === "object" && item !== null && Array.isArray(item.rules)) {
|
|
212
|
+
out.push(...item.rules);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/core/modules/inputs/normalizeWorldbooks.ts
|
|
220
|
+
function isWorldbookEntryArray(v) {
|
|
221
|
+
return Array.isArray(v) && v.every((x) => typeof x === "object" && x !== null && "content" in x);
|
|
222
|
+
}
|
|
223
|
+
function normalizeOne(item) {
|
|
224
|
+
const normalizeEntry = (e) => {
|
|
225
|
+
if (!e || typeof e !== "object") return null;
|
|
226
|
+
const position = e.position;
|
|
227
|
+
if (position !== "before_char" && position !== "after_char" && position !== "fixed") return null;
|
|
228
|
+
const role = e.role ?? "user";
|
|
229
|
+
const orderRaw = e.order;
|
|
230
|
+
const order = Number.isFinite(orderRaw) ? Number(orderRaw) : NaN;
|
|
231
|
+
if (!Number.isFinite(order)) return null;
|
|
232
|
+
if (position === "fixed") {
|
|
233
|
+
const depthRaw = e.depth;
|
|
234
|
+
const depth = Number.isFinite(depthRaw) ? Number(depthRaw) : NaN;
|
|
235
|
+
if (!Number.isFinite(depth)) return null;
|
|
236
|
+
return {
|
|
237
|
+
...e,
|
|
238
|
+
role,
|
|
239
|
+
position,
|
|
240
|
+
order,
|
|
241
|
+
depth
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
...e,
|
|
246
|
+
role,
|
|
247
|
+
position,
|
|
248
|
+
order
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
const normalizeEntries = (entries) => {
|
|
252
|
+
return (entries || []).map(normalizeEntry).filter((x) => Boolean(x));
|
|
253
|
+
};
|
|
254
|
+
if (isWorldbookEntryArray(item)) return normalizeEntries(item);
|
|
255
|
+
if (typeof item === "object" && item !== null && Array.isArray(item.entries)) {
|
|
256
|
+
if (item.enabled === false) return [];
|
|
257
|
+
return normalizeEntries(item.entries);
|
|
258
|
+
}
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
function normalizeWorldbooks(input) {
|
|
262
|
+
if (!input) return [];
|
|
263
|
+
const files = [];
|
|
264
|
+
if (Array.isArray(input)) {
|
|
265
|
+
if (isWorldbookEntryArray(input)) {
|
|
266
|
+
files.push(input);
|
|
267
|
+
} else {
|
|
268
|
+
files.push(...input);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
files.push(input);
|
|
272
|
+
}
|
|
273
|
+
const out = [];
|
|
274
|
+
for (const file of files) {
|
|
275
|
+
if (!file) continue;
|
|
276
|
+
out.push(...normalizeOne(file));
|
|
277
|
+
}
|
|
278
|
+
return out;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/core/modules/worldbook/getActiveEntries.ts
|
|
282
|
+
function getActiveEntries(params) {
|
|
283
|
+
const { contextText = "", globalEntries = [], presetWorldbook, characterWorldbook } = params;
|
|
284
|
+
const filterEntry = (e) => {
|
|
285
|
+
if (e.enabled === false) return false;
|
|
286
|
+
if (e.mode === "always") return true;
|
|
287
|
+
if (e.mode === "conditional") return testCondition(e.condition, contextText);
|
|
288
|
+
return true;
|
|
289
|
+
};
|
|
290
|
+
const entries = [];
|
|
291
|
+
(globalEntries || []).filter(filterEntry).forEach((e, idx) => {
|
|
292
|
+
entries.push({ ...e, _source: `global-${idx}` });
|
|
293
|
+
});
|
|
294
|
+
const presetEntries = normalizeWorldbooks(presetWorldbook);
|
|
295
|
+
presetEntries.filter(filterEntry).forEach((e) => {
|
|
296
|
+
entries.push({ ...e, _source: "preset" });
|
|
297
|
+
});
|
|
298
|
+
const characterEntries = normalizeWorldbooks(characterWorldbook);
|
|
299
|
+
characterEntries.filter(filterEntry).forEach((e) => {
|
|
300
|
+
entries.push({ ...e, _source: "character" });
|
|
301
|
+
});
|
|
302
|
+
return entries.sort((a, b) => {
|
|
303
|
+
if (a.order !== b.order) return a.order - b.order;
|
|
304
|
+
const getPrio = (src) => {
|
|
305
|
+
if (src === "character") return 3;
|
|
306
|
+
if (src === "preset") return 2;
|
|
307
|
+
return 1;
|
|
308
|
+
};
|
|
309
|
+
return getPrio(a._source) - getPrio(b._source);
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/core/modules/regex/applyRegex.ts
|
|
314
|
+
function applyRegex(text, params) {
|
|
315
|
+
let result = text ?? "";
|
|
316
|
+
const { rules, target, view, placement } = params;
|
|
317
|
+
for (const rule of rules) {
|
|
318
|
+
if (!rule?.enabled) continue;
|
|
319
|
+
if (!(rule.views || []).includes(view)) continue;
|
|
320
|
+
if (placement && rule.placement !== placement) continue;
|
|
321
|
+
const mappedTarget = target === "model" || target === "chat_history" ? ["model", "chat_history", "assistant_response"] : [target];
|
|
322
|
+
const isMatch = (rule.targets || []).some((t) => mappedTarget.includes(t)) || target === "model" && (rule.targets || []).includes("chat_history") || target === "user" && (rule.targets || []).includes("chat_history");
|
|
323
|
+
if (!isMatch) continue;
|
|
324
|
+
try {
|
|
325
|
+
const re = new RegExp(rule.find_regex, "g");
|
|
326
|
+
result = result.replace(re, rule.replace_regex);
|
|
327
|
+
} catch {
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/core/modules/regex/mergeRegexRules.ts
|
|
335
|
+
function normalizeView(v) {
|
|
336
|
+
return v === "assistant_view" ? "model_view" : v;
|
|
337
|
+
}
|
|
338
|
+
function mergeRegexRules(params) {
|
|
339
|
+
const all = [];
|
|
340
|
+
all.push(...params.globalRules || []);
|
|
341
|
+
all.push(...params.presetRules || []);
|
|
342
|
+
all.push(...params.characterRules || []);
|
|
343
|
+
return all.map((r) => ({
|
|
344
|
+
...r,
|
|
345
|
+
views: (r.views || []).map(normalizeView)
|
|
346
|
+
}));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/core/modules/macro/replaceMacros.ts
|
|
350
|
+
function replaceMacros(text, macros) {
|
|
351
|
+
if (!text) return "";
|
|
352
|
+
let out = text;
|
|
353
|
+
if (macros.user !== void 0) {
|
|
354
|
+
out = out.replace(/<<user>>/g, String(macros.user));
|
|
355
|
+
}
|
|
356
|
+
out = out.replace(/\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g, (_m, key) => {
|
|
357
|
+
if (Object.prototype.hasOwnProperty.call(macros, key)) return String(macros[key]);
|
|
358
|
+
return _m;
|
|
359
|
+
});
|
|
360
|
+
return out;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// src/core/modules/assemble/assembleTaggedPromptList.ts
|
|
364
|
+
function mapRole(role) {
|
|
365
|
+
return role;
|
|
366
|
+
}
|
|
367
|
+
function isFixedPromptBlock(b) {
|
|
368
|
+
return b.position === "fixed";
|
|
369
|
+
}
|
|
370
|
+
function isFixedWorldbookEntry(e) {
|
|
371
|
+
return e.position === "fixed";
|
|
372
|
+
}
|
|
373
|
+
function assembleTaggedPromptList(params) {
|
|
374
|
+
const {
|
|
375
|
+
presetBlocks,
|
|
376
|
+
activeEntries,
|
|
377
|
+
chatHistory,
|
|
378
|
+
positionMap = { before_char: "charBefore", after_char: "charAfter" }
|
|
379
|
+
} = params;
|
|
380
|
+
const result = [];
|
|
381
|
+
const enabledBlocks = (presetBlocks || []).filter((b) => b.enabled !== false);
|
|
382
|
+
const relativeBlocks = enabledBlocks.filter((b) => b.position === "relative");
|
|
383
|
+
for (const block of relativeBlocks) {
|
|
384
|
+
const slotEntries = (activeEntries || []).filter((e) => {
|
|
385
|
+
if (isFixedWorldbookEntry(e)) return false;
|
|
386
|
+
const mappedPos = positionMap[e.position] || e.position;
|
|
387
|
+
return mappedPos === block.identifier;
|
|
388
|
+
}).sort((a, b) => a.order - b.order);
|
|
389
|
+
for (const entry of slotEntries) {
|
|
390
|
+
result.push({
|
|
391
|
+
tag: `Worldbook: ${entry.name}`,
|
|
392
|
+
target: "world_book",
|
|
393
|
+
role: mapRole(entry.role),
|
|
394
|
+
text: entry.content
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
if (block.identifier === "chatHistory") {
|
|
398
|
+
let dialogueList = (chatHistory || []).map((node) => ({
|
|
399
|
+
tag: `History: ${node.role}`,
|
|
400
|
+
// system 属于聊天历史的一部分:这里用 chat_history 目标以便 regex 可覆盖
|
|
401
|
+
target: node.role === "user" ? "user" : node.role === "model" ? "model" : "chat_history",
|
|
402
|
+
role: node.role,
|
|
403
|
+
text: node.text
|
|
404
|
+
}));
|
|
405
|
+
const presetInjections = enabledBlocks.filter(
|
|
406
|
+
(b) => isFixedPromptBlock(b) && typeof b.depth === "number" && Number.isFinite(b.depth) && typeof b.order === "number" && Number.isFinite(b.order)
|
|
407
|
+
);
|
|
408
|
+
const worldbookInjections = (activeEntries || []).filter(
|
|
409
|
+
(e) => isFixedWorldbookEntry(e) && typeof e.depth === "number" && Number.isFinite(e.depth) && typeof e.order === "number" && Number.isFinite(e.order)
|
|
410
|
+
);
|
|
411
|
+
const allInjections = [
|
|
412
|
+
...presetInjections.map((b) => ({
|
|
413
|
+
tag: `Preset: ${b.name}`,
|
|
414
|
+
target: "preset",
|
|
415
|
+
role: mapRole(b.role),
|
|
416
|
+
text: b.content || "",
|
|
417
|
+
depth: b.depth,
|
|
418
|
+
order: b.order
|
|
419
|
+
})),
|
|
420
|
+
...worldbookInjections.map((e) => ({
|
|
421
|
+
tag: `Worldbook: ${e.name}`,
|
|
422
|
+
target: "world_book",
|
|
423
|
+
role: mapRole(e.role),
|
|
424
|
+
text: e.content,
|
|
425
|
+
depth: e.depth,
|
|
426
|
+
order: e.order
|
|
427
|
+
}))
|
|
428
|
+
].sort((a, b) => {
|
|
429
|
+
if (a.depth !== b.depth) return a.depth - b.depth;
|
|
430
|
+
return a.order - b.order;
|
|
431
|
+
});
|
|
432
|
+
for (const item of allInjections) {
|
|
433
|
+
const targetIndex = Math.max(0, dialogueList.length - item.depth);
|
|
434
|
+
dialogueList.splice(targetIndex, 0, {
|
|
435
|
+
tag: item.tag,
|
|
436
|
+
target: item.target,
|
|
437
|
+
role: item.role,
|
|
438
|
+
text: item.text
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
result.push(...dialogueList);
|
|
442
|
+
} else if (block.content) {
|
|
443
|
+
result.push({
|
|
444
|
+
tag: `Preset: ${block.name}`,
|
|
445
|
+
target: "preset",
|
|
446
|
+
role: mapRole(block.role),
|
|
447
|
+
text: block.content
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/core/modules/pipeline/processContentStages.ts
|
|
455
|
+
function processContentStages(text, params) {
|
|
456
|
+
const raw = text ?? "";
|
|
457
|
+
const afterPreRegex = applyRegex(raw, {
|
|
458
|
+
rules: params.rules,
|
|
459
|
+
target: params.target,
|
|
460
|
+
view: params.view,
|
|
461
|
+
placement: "before_macro"
|
|
462
|
+
});
|
|
463
|
+
const afterMacro = replaceMacros(afterPreRegex, params.macros);
|
|
464
|
+
const afterPostRegex = applyRegex(afterMacro, {
|
|
465
|
+
rules: params.rules,
|
|
466
|
+
target: params.target,
|
|
467
|
+
view: params.view,
|
|
468
|
+
placement: "after_macro"
|
|
469
|
+
});
|
|
470
|
+
return { raw, afterPreRegex, afterMacro, afterPostRegex };
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/core/modules/pipeline/compileTaggedStages.ts
|
|
474
|
+
function compileTaggedStages(tagged, params) {
|
|
475
|
+
const perItem = [];
|
|
476
|
+
const raw = (tagged || []).map((i) => ({ ...i }));
|
|
477
|
+
const afterPreRegex = [];
|
|
478
|
+
const afterMacro = [];
|
|
479
|
+
const afterPostRegex = [];
|
|
480
|
+
for (const item of raw) {
|
|
481
|
+
const s = processContentStages(item.text, {
|
|
482
|
+
target: item.target,
|
|
483
|
+
view: params.view,
|
|
484
|
+
rules: params.rules,
|
|
485
|
+
macros: params.macros
|
|
486
|
+
});
|
|
487
|
+
perItem.push({
|
|
488
|
+
tag: item.tag,
|
|
489
|
+
role: item.role,
|
|
490
|
+
target: item.target,
|
|
491
|
+
...s
|
|
492
|
+
});
|
|
493
|
+
afterPreRegex.push({ ...item, text: s.afterPreRegex });
|
|
494
|
+
afterMacro.push({ ...item, text: s.afterMacro });
|
|
495
|
+
afterPostRegex.push({ ...item, text: s.afterPostRegex });
|
|
496
|
+
}
|
|
497
|
+
return {
|
|
498
|
+
stages: { raw, afterPreRegex, afterMacro, afterPostRegex },
|
|
499
|
+
perItem
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/core/modules/build/buildPrompt.ts
|
|
504
|
+
function geminiContentsToChatHistory(contents) {
|
|
505
|
+
return (contents || []).map((m) => ({
|
|
506
|
+
role: m.role,
|
|
507
|
+
text: (m.parts || []).map((p) => p.text ?? "").join("")
|
|
508
|
+
}));
|
|
509
|
+
}
|
|
510
|
+
function taggedToGemini(tagged) {
|
|
511
|
+
return (tagged || []).map((item) => ({
|
|
512
|
+
role: item.role,
|
|
513
|
+
parts: [{ text: item.text ?? "" }]
|
|
514
|
+
}));
|
|
515
|
+
}
|
|
516
|
+
function applySystemRolePolicy(internal, policy) {
|
|
517
|
+
if (policy === "keep") return internal;
|
|
518
|
+
return (internal || []).map((m) => ({
|
|
519
|
+
...m,
|
|
520
|
+
role: m.role === "system" ? "user" : m.role
|
|
521
|
+
}));
|
|
522
|
+
}
|
|
523
|
+
function buildPrompt(params) {
|
|
524
|
+
const { preset, character, globals, history, historyFormat, macros, view, options } = params;
|
|
525
|
+
const historyConv = (() => {
|
|
526
|
+
if (isHistoryInput(history)) {
|
|
527
|
+
if (history.format === "text") {
|
|
528
|
+
return convertMessagesIn(history.text, "text");
|
|
529
|
+
}
|
|
530
|
+
if (history.format === "auto") {
|
|
531
|
+
return convertMessagesIn(history.input, "auto");
|
|
532
|
+
}
|
|
533
|
+
return convertMessagesIn(history.messages, history.format);
|
|
534
|
+
}
|
|
535
|
+
return convertMessagesIn(history, normalizeHistoryFormat(historyFormat));
|
|
536
|
+
})();
|
|
537
|
+
const detectedHistoryFormat = historyConv.detected;
|
|
538
|
+
const internalHistory = historyConv.internal;
|
|
539
|
+
const chatHistory = geminiContentsToChatHistory(internalHistory);
|
|
540
|
+
const recentN = options?.recentHistoryForWorldbook ?? 5;
|
|
541
|
+
const recentHistoryText = chatHistory.slice(-recentN).map((n) => n.text).join("\n");
|
|
542
|
+
const globalWorldbookEntries = normalizeWorldbooks(globals?.worldbooks);
|
|
543
|
+
const activeEntries = getActiveEntries({
|
|
544
|
+
contextText: recentHistoryText,
|
|
545
|
+
globalEntries: globalWorldbookEntries,
|
|
546
|
+
presetWorldbook: preset.world_book,
|
|
547
|
+
characterWorldbook: character?.world_book
|
|
548
|
+
});
|
|
549
|
+
const tagged = assembleTaggedPromptList({
|
|
550
|
+
presetBlocks: preset.prompts,
|
|
551
|
+
activeEntries,
|
|
552
|
+
chatHistory,
|
|
553
|
+
positionMap: options?.positionMap
|
|
554
|
+
});
|
|
555
|
+
const globalRegexRules = normalizeRegexes(globals?.regexes);
|
|
556
|
+
const rules = mergeRegexRules({
|
|
557
|
+
globalRules: globalRegexRules,
|
|
558
|
+
presetRules: preset.regex_rules,
|
|
559
|
+
characterRules: character?.regex_rules
|
|
560
|
+
});
|
|
561
|
+
const compiled = compileTaggedStages(tagged, { view, rules, macros });
|
|
562
|
+
const taggedStages = compiled.stages;
|
|
563
|
+
const perItem = compiled.perItem;
|
|
564
|
+
const internalStages = {
|
|
565
|
+
raw: taggedToGemini(taggedStages.raw),
|
|
566
|
+
afterPreRegex: taggedToGemini(taggedStages.afterPreRegex),
|
|
567
|
+
afterMacro: taggedToGemini(taggedStages.afterMacro),
|
|
568
|
+
afterPostRegex: taggedToGemini(taggedStages.afterPostRegex)
|
|
569
|
+
};
|
|
570
|
+
const defaultOutputFormat = isHistoryInput(history) ? history.format === "auto" ? detectedHistoryFormat : history.format : detectedHistoryFormat;
|
|
571
|
+
const outputFormat = params.outputFormat ?? defaultOutputFormat;
|
|
572
|
+
const systemRolePolicy = params.systemRolePolicy ?? "keep";
|
|
573
|
+
const outputStages = outputFormat === "tagged" ? taggedStages : {
|
|
574
|
+
raw: convertMessagesOut(
|
|
575
|
+
applySystemRolePolicy(internalStages.raw, systemRolePolicy),
|
|
576
|
+
outputFormat
|
|
577
|
+
),
|
|
578
|
+
afterPreRegex: convertMessagesOut(
|
|
579
|
+
applySystemRolePolicy(internalStages.afterPreRegex, systemRolePolicy),
|
|
580
|
+
outputFormat
|
|
581
|
+
),
|
|
582
|
+
afterMacro: convertMessagesOut(
|
|
583
|
+
applySystemRolePolicy(internalStages.afterMacro, systemRolePolicy),
|
|
584
|
+
outputFormat
|
|
585
|
+
),
|
|
586
|
+
afterPostRegex: convertMessagesOut(
|
|
587
|
+
applySystemRolePolicy(internalStages.afterPostRegex, systemRolePolicy),
|
|
588
|
+
outputFormat
|
|
589
|
+
)
|
|
590
|
+
};
|
|
591
|
+
return {
|
|
592
|
+
detectedHistoryFormat,
|
|
593
|
+
outputFormat,
|
|
594
|
+
systemRolePolicy,
|
|
595
|
+
activeWorldbookEntries: activeEntries,
|
|
596
|
+
mergedRegexRules: rules,
|
|
597
|
+
stages: {
|
|
598
|
+
tagged: taggedStages,
|
|
599
|
+
internal: internalStages,
|
|
600
|
+
output: outputStages,
|
|
601
|
+
perItem
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// src/core/channels/index.ts
|
|
607
|
+
var channels_exports = {};
|
|
608
|
+
__export(channels_exports, {
|
|
609
|
+
detectMessageFormat: () => detectMessageFormat,
|
|
610
|
+
fromInternalToGemini: () => fromInternalToGemini,
|
|
611
|
+
fromInternalToOpenAI: () => fromInternalToOpenAI,
|
|
612
|
+
fromInternalToSimple: () => fromInternalToSimple,
|
|
613
|
+
fromInternalToTagged: () => fromInternalToTagged,
|
|
614
|
+
fromInternalToText: () => fromInternalToText,
|
|
615
|
+
isGeminiContents: () => isGeminiContents,
|
|
616
|
+
isOpenAIMessages: () => isOpenAIMessages,
|
|
617
|
+
isSimpleMessages: () => isSimpleMessages,
|
|
618
|
+
isTaggedContents: () => isTaggedContents,
|
|
619
|
+
isTextInput: () => isTextInput,
|
|
620
|
+
toInternalFromGemini: () => toInternalFromGemini,
|
|
621
|
+
toInternalFromOpenAI: () => toInternalFromOpenAI,
|
|
622
|
+
toInternalFromSimple: () => toInternalFromSimple,
|
|
623
|
+
toInternalFromTagged: () => toInternalFromTagged,
|
|
624
|
+
toInternalFromText: () => toInternalFromText
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
exports.Channels = channels_exports;
|
|
628
|
+
exports.History = History;
|
|
629
|
+
exports.applyRegex = applyRegex;
|
|
630
|
+
exports.assembleTaggedPromptList = assembleTaggedPromptList;
|
|
631
|
+
exports.buildPrompt = buildPrompt;
|
|
632
|
+
exports.compileTaggedStages = compileTaggedStages;
|
|
633
|
+
exports.convertMessagesIn = convertMessagesIn;
|
|
634
|
+
exports.convertMessagesOut = convertMessagesOut;
|
|
635
|
+
exports.detectMessageFormat = detectMessageFormat;
|
|
636
|
+
exports.getActiveEntries = getActiveEntries;
|
|
637
|
+
exports.isHistoryInput = isHistoryInput;
|
|
638
|
+
exports.isTextInput = isTextInput;
|
|
639
|
+
exports.mergeRegexRules = mergeRegexRules;
|
|
640
|
+
exports.normalizeHistoryFormat = normalizeHistoryFormat;
|
|
641
|
+
exports.normalizeRegexes = normalizeRegexes;
|
|
642
|
+
exports.normalizeWorldbooks = normalizeWorldbooks;
|
|
643
|
+
exports.processContentStages = processContentStages;
|
|
644
|
+
exports.replaceMacros = replaceMacros;
|
|
645
|
+
exports.testCondition = testCondition;
|
|
646
|
+
//# sourceMappingURL=index.cjs.map
|
|
647
|
+
//# sourceMappingURL=index.cjs.map
|