Refactor generateRaw/generateQuietPrompt calls (#4277)

* generateQuietPrompt: Update to object arguments

* generateRaw: Update to object arguments

* Fix jsdoc

* Fix lint

* Unwrap JSON schema options

* Remove default args from gen call
This commit is contained in:
Cohee
2025-07-15 23:11:31 +03:00
committed by GitHub
parent f8f9ee8a0e
commit 1a92157643
7 changed files with 90 additions and 48 deletions
+45 -32
View File
@@ -2330,37 +2330,43 @@ export function getStoppingStrings(isImpersonate, isContinue) {
/**
* Background generation based on the provided prompt.
* @param {string} quietPrompt Instruction prompt for the AI
* @param {boolean} [quietToLoud] Whether the message should be sent in a foreground (loud) or background (quiet) mode
* @param {boolean} [skipWIAN] Whether to skip addition of World Info and Author's Note into the prompt
* @param {string} [quietImage] Image to use for the quiet prompt
* @param {string} [quietName] Name to use for the quiet prompt (defaults to "System:")
* @param {number} [responseLength] Maximum response length. If unset, the global default value is used.
* @param {number} [forceChId] Character ID to use for this generation run. Works in groups only.
* @param {AdditionalRequestOptions} [options={}] Additional generation request options.
* @typedef {object} GenerateQuietPromptParams
* @prop {string} [quietPrompt] Instruction prompt for the AI
* @prop {boolean} [quietToLoud] Whether the message should be sent in a foreground (loud) or background (quiet) mode
* @prop {boolean} [skipWIAN] Whether to skip addition of World Info and Author's Note into the prompt
* @prop {string} [quietImage] Image to use for the quiet prompt
* @prop {string} [quietName] Name to use for the quiet prompt (defaults to "System:")
* @prop {number} [responseLength] Maximum response length. If unset, the global default value is used.
* @prop {number} [forceChId] Character ID to use for this generation run. Works in groups only.
* @prop {object} [jsonSchema] JSON schema to use for the structured generation. Usually requires a special instruction.
* @param {GenerateQuietPromptParams} params Parameters for the quiet prompt generation
* @returns {Promise<string>} Generated text. If using structured output, will contain a serialized JSON object.
*/
export async function generateQuietPrompt(quietPrompt, quietToLoud = false, skipWIAN = false, quietImage = null, quietName = null, responseLength = null, forceChId = null, { jsonSchema } = {}) {
console.log('got into genQuietPrompt');
export async function generateQuietPrompt({ quietPrompt = '', quietToLoud = false, skipWIAN = false, quietImage = null, quietName = null, responseLength = null, forceChId = null, jsonSchema = null } = {}) {
if (arguments.length > 0 && typeof arguments[0] !== 'object') {
console.trace('generateQuietPrompt called with positional arguments. Please use an object instead.');
[quietPrompt, quietToLoud, skipWIAN, quietImage, quietName, responseLength, forceChId, jsonSchema] = arguments;
}
const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
let eventHook = () => { };
try {
/** @type {GenerateOptions} */
const options = {
quiet_prompt: quietPrompt,
quietToLoud,
skipWIAN: skipWIAN,
const generateOptions = {
quiet_prompt: quietPrompt ?? '',
quietToLoud: quietToLoud ?? false,
skipWIAN: skipWIAN ?? false,
force_name2: true,
quietImage: quietImage,
quietName: quietName,
force_chid: forceChId,
jsonSchema: jsonSchema,
quietImage: quietImage ?? null,
quietName: quietName ?? null,
force_chid: forceChId ?? null,
jsonSchema: jsonSchema ?? null,
};
if (responseLengthCustomized) {
TempResponseLength.save(main_api, responseLength);
eventHook = TempResponseLength.setupEventHook(main_api);
}
const result = await Generate('quiet', options);
const result = await Generate('quiet', generateOptions);
return removeReasoningFromString(result);
} finally {
if (responseLengthCustomized && TempResponseLength.isCustomized()) {
@@ -3121,18 +3127,25 @@ export function createRawPrompt(prompt, api, instructOverride, quietToLoud, syst
/**
* Generates a message using the provided prompt.
* If the prompt is an array of chat-style messages and not using chat completion, it will be converted to a text prompt.
* @param {string | object[]} prompt Prompt to generate a message from. Can be a string or an array of chat-style messages, i.e. [{role: '', content: ''}, ...]
* @param {string} api API to use. Main API is used if not specified.
* @param {boolean} instructOverride true to override instruct mode, false to use the default value
* @param {boolean} quietToLoud true to generate a message in system mode, false to generate a message in character mode
* @param {string} [systemPrompt] System prompt to use.
* @param {number} [responseLength] Maximum response length. If unset, the global default value is used.
* @param {boolean} [trimNames] Whether to allow trimming "{{user}}:" and "{{char}}:" from the response.
* @param {string} [prefill] An optional prefill for the prompt.
* @param {AdditionalRequestOptions} [options] Additional options for generation
* @typedef {object} GenerateRawParams
* @prop {string | object[]} [prompt] Prompt to generate a message from. Can be a string or an array of chat-style messages, i.e. [{role: '', content: ''}, ...]
* @prop {string} [api] API to use. Main API is used if not specified.
* @prop {boolean} [instructOverride] true to override instruct mode, false to use the default value
* @prop {boolean} [quietToLoud] true to generate a message in system mode, false to generate a message in character mode
* @prop {string} [systemPrompt] System prompt to use.
* @prop {number} [responseLength] Maximum response length. If unset, the global default value is used.
* @prop {boolean} [trimNames] Whether to allow trimming "{{user}}:" and "{{char}}:" from the response.
* @prop {string} [prefill] An optional prefill for the prompt.
* @prop {object} [jsonSchema] JSON schema to use for the structured generation. Usually requires a special instruction.
* @param {GenerateRawParams} params Parameters for generating a message
* @returns {Promise<string>} Generated message
*/
export async function generateRaw(prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, trimNames = true, prefill = '', options = {}) {
export async function generateRaw({ prompt = '', api = null, instructOverride = false, quietToLoud = false, systemPrompt = '', responseLength = null, trimNames = true, prefill = '', jsonSchema = null } = {}) {
if (arguments.length > 0 && typeof arguments[0] !== 'object') {
console.trace('generateRaw called with positional arguments. Please use an object instead.');
[prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, trimNames, prefill, jsonSchema] = arguments;
}
if (!api) {
api = main_api;
}
@@ -3184,7 +3197,7 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
if (api === 'koboldhorde') {
data = await generateHorde(prompt.toString(), generateData, abortController.signal, false);
} else if (api === 'openai') {
data = await sendOpenAIRequest('quiet', generateData, abortController.signal, options);
data = await sendOpenAIRequest('quiet', generateData, abortController.signal, { jsonSchema });
} else {
const generateUrl = getGenerateUrl(api);
const response = await fetch(generateUrl, {
@@ -3209,7 +3222,7 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
throw new Error(data.response);
}
if (options?.jsonSchema) {
if (jsonSchema) {
return extractJsonFromData(data, { mainApi: api });
}
@@ -9315,7 +9328,7 @@ function addDebugFunctions() {
registerDebugFunction('generationTest', 'Send a generation request', 'Generates text using the currently selected API.', async () => {
const text = prompt('Input text:', 'Hello');
toastr.info('Working on it...');
const message = await generateRaw(text, null, false, false);
const message = await generateRaw({ prompt: text });
alert(message);
});
registerDebugFunction('toggleEventTracing', 'Toggle event tracing', 'Useful to see what triggered a certain event.', () => {
+1 -1
View File
@@ -421,7 +421,7 @@ async function autoBackgroundCommand() {
const list = options.map(option => `- ${option.text}`).join('\n');
const prompt = stringFormat(autoBgPrompt, list);
const reply = await generateQuietPrompt(prompt, false, false);
const reply = await generateQuietPrompt({ quietPrompt: prompt });
const fuse = new Fuse(options, { keys: ['text'] });
const bestMatch = fuse.search(reply, { limit: 1 });
@@ -1,6 +1,6 @@
import { Fuse } from '../../../lib.js';
import { characters, eventSource, event_types, generateQuietPrompt, generateRaw, getRequestHeaders, main_api, online_status, saveSettingsDebounced, substituteParams, substituteParamsExtended, system_message_types, this_chid } from '../../../script.js';
import { characters, eventSource, event_types, generateQuietPrompt, generateRaw, getRequestHeaders, online_status, saveSettingsDebounced, substituteParams, substituteParamsExtended, system_message_types, this_chid } from '../../../script.js';
import { dragElement, isMobile } from '../../RossAscends-mods.js';
import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';
import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js';
@@ -1056,10 +1056,10 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin
inApiCall = true;
switch (extension_settings.expressions.promptType) {
case PROMPT_TYPE.raw:
emotionResponse = await generateRaw(text, main_api, false, false, prompt);
emotionResponse = await generateRaw({ prompt: text, systemPrompt: prompt });
break;
case PROMPT_TYPE.full:
emotionResponse = await generateQuietPrompt(prompt, false, false);
emotionResponse = await generateQuietPrompt({ quietPrompt: prompt });
break;
}
} finally {
+15 -3
View File
@@ -506,7 +506,7 @@ async function summarizeCallback(args, text) {
case summary_sources.extras:
return await callExtrasSummarizeAPI(text);
case summary_sources.main:
return removeReasoningFromString(await generateRaw(text, '', false, false, prompt, extension_settings.memory.overrideResponseLength));
return removeReasoningFromString(await generateRaw({ prompt: text, systemPrompt: prompt, responseLength: extension_settings.memory.overrideResponseLength }));
case summary_sources.webllm: {
const messages = [{ role: 'system', content: prompt }, { role: 'user', content: text }].filter(m => m.content);
const params = extension_settings.memory.overrideResponseLength > 0 ? { max_tokens: extension_settings.memory.overrideResponseLength } : {};
@@ -677,7 +677,13 @@ async function summarizeChatMain(context, force, skipWIAN) {
if (prompt_builders.DEFAULT === extension_settings.memory.prompt_builder) {
try {
inApiCall = true;
summary = await generateQuietPrompt(prompt, false, skipWIAN, '', '', extension_settings.memory.overrideResponseLength);
/** @type {import('../../../script.js').GenerateQuietPromptParams} */
const params = {
quietPrompt: prompt,
skipWIAN: skipWIAN,
responseLength: extension_settings.memory.overrideResponseLength,
};
summary = await generateQuietPrompt(params);
} finally {
inApiCall = false;
}
@@ -701,7 +707,13 @@ async function summarizeChatMain(context, force, skipWIAN) {
return null;
}
const rawSummary = await generateRaw(rawPrompt, '', false, false, prompt, extension_settings.memory.overrideResponseLength);
/** @type {import('../../../script.js').GenerateRawParams} */
const params = {
prompt: rawPrompt,
systemPrompt: prompt,
responseLength: extension_settings.memory.overrideResponseLength,
};
const rawSummary = await generateRaw(params);
summary = removeReasoningFromString(rawSummary);
index = lastUsedIndex;
} finally {
@@ -2726,7 +2726,7 @@ function getUserAvatarUrl() {
* @returns {Promise<string>} - A promise that resolves when the prompt generation completes.
*/
async function generatePrompt(quietPrompt) {
const reply = await generateQuietPrompt(quietPrompt, false, false);
const reply = await generateQuietPrompt({ quietPrompt });
const processedReply = processReply(reply);
if (!processedReply) {
+4 -4
View File
@@ -257,17 +257,17 @@ async function summarizeExtra(element) {
/**
* Summarizes messages using the main API method.
* @param {HashedMessage} element hashed message
* @returns {Promise<boolean>} Sucess
* @returns {Promise<boolean>} Success
*/
async function summarizeMain(element) {
element.text = removeReasoningFromString(await generateRaw(element.text, '', false, false, settings.summary_prompt));
element.text = removeReasoningFromString(await generateRaw({ prompt: element.text, systemPrompt: settings.summary_prompt }));
return true;
}
/**
* Summarizes messages using WebLLM.
* @param {HashedMessage} element hashed message
* @returns {Promise<boolean>} Sucess
* @returns {Promise<boolean>} Success
*/
async function summarizeWebLLM(element) {
if (!isWebLlmSupported()) {
@@ -1751,7 +1751,7 @@ jQuery(async () => {
$('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);
[event_types.SECRET_WRITTEN, event_types.SECRET_DELETED, event_types.SECRET_ROTATED].forEach(event => {
eventSource.on(event, (/** @type {string} */ key)=> {
eventSource.on(event, (/** @type {string} */ key) => {
if (key !== SECRET_KEYS.NOMICAI) return;
$('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]);
});
+21 -4
View File
@@ -3645,7 +3645,17 @@ async function generateRawCallback(args, value) {
}
setEphemeralStopStrings(resolveVariable(args?.stop));
const result = await generateRaw(value, '', isFalseBoolean(args?.instruct), quietToLoud, systemPrompt, length, trimNames, prefillPrompt);
/** @type {import('../script.js').GenerateRawParams} */
const params = {
prompt: value,
instructOverride: isFalseBoolean(args?.instruct),
quietToLoud: quietToLoud,
systemPrompt: systemPrompt,
responseLength: length,
trimNames: trimNames,
prefill: prefillPrompt,
};
const result = await generateRaw(params);
return result;
} catch (err) {
console.error('Error on /genraw generation', err);
@@ -3681,7 +3691,14 @@ async function generateCallback(args, value) {
setEphemeralStopStrings(resolveVariable(args?.stop));
const name = args?.name;
const char = findChar({ name: name });
const result = await generateQuietPrompt(value, quietToLoud, false, '', char?.name ?? name, length);
/** @type {import('../script.js').GenerateQuietPromptParams} */
const params = {
quietPrompt: value,
quietToLoud: quietToLoud,
quietName: char?.name ?? name,
responseLength: length,
};
const result = await generateQuietPrompt(params);
return result;
} catch (err) {
console.error('Error on /gen generation', err);
@@ -4352,7 +4369,7 @@ export async function generateSystemMessage(_, prompt) {
// Generate and regex the output if applicable
toastr.info('Please wait', 'Generating...');
let message = await generateQuietPrompt(prompt, false, false);
let message = await generateQuietPrompt({ quietPrompt: prompt });
message = getRegexedString(message, regex_placement.SLASH_COMMAND);
sendNarratorMessage(_, message);
@@ -4609,7 +4626,7 @@ export async function promptQuietForLoudResponse(who, text) {
//text = `${text}${power_user.instruct.enabled ? '' : '\n'}${(power_user.always_force_name2 && who != 'raw') ? characters[character_id].name + ":" : ""}`
let reply = await generateQuietPrompt(text, true, false);
let reply = await generateQuietPrompt({ quietPrompt: text, quietToLoud: true });
text = await getRegexedString(reply, regex_placement.SLASH_COMMAND);
const message = {