54 lines
2.6 KiB
TypeScript
54 lines
2.6 KiB
TypeScript
/** User image controls are execution constraints, separate from the planning model. */
|
|
export type AgentImageParameters = {
|
|
aspectRatio?: string;
|
|
imageSize?: string;
|
|
imageCount?: number;
|
|
n?: number;
|
|
quality?: "auto" | "low" | "medium" | "high";
|
|
size?: string;
|
|
negativePrompt?: string;
|
|
promptExtend?: boolean;
|
|
watermark?: boolean;
|
|
seed?: number;
|
|
};
|
|
export type AgentImagePreferences = { modelId?: string; parameters?: AgentImageParameters };
|
|
|
|
export function applyAgentImagePreferences<T extends Record<string, unknown>>(
|
|
input: T,
|
|
preferences?: AgentImagePreferences,
|
|
): T & AgentImageParameters & { modelId?: string } {
|
|
const parameters = Object.fromEntries(Object.entries(preferences?.parameters || {})
|
|
.filter(([, value]) => value !== undefined));
|
|
const count = preferences?.parameters?.imageCount ?? preferences?.parameters?.n;
|
|
return {
|
|
...input,
|
|
...parameters,
|
|
...(count !== undefined ? { imageCount: count } : {}),
|
|
...(preferences?.modelId ? { modelId: preferences.modelId } : {}),
|
|
};
|
|
}
|
|
|
|
export function agentProviderImageParameters(parameters: AgentImageParameters) {
|
|
return Object.fromEntries(["quality", "size", "watermark", "seed"].flatMap(key => {
|
|
const value = parameters[key as keyof AgentImageParameters];
|
|
return value !== undefined ? [[key, value]] : [];
|
|
}));
|
|
}
|
|
|
|
/** Only user controls or an explicit instruction pin a model; the planner's own
|
|
* modelId and a preset default remain eligible for automatic recovery. */
|
|
export function resolveUserImageModel(text: string, entries: Array<{ model: { id: string; modelId: string; displayName?: string | null } }>, selectedId?: string) {
|
|
if (selectedId) return selectedId;
|
|
const names = entries.flatMap(({ model }) => [model.modelId, model.displayName].filter((name): name is string => Boolean(name && name.length >= 4)).map(name => ({ id: model.id, name })))
|
|
.sort((a, b) => b.name.length - a.name.length);
|
|
const matches: Array<{ id: string; index: number; length: number }> = [];
|
|
for (const { id, name } of names) {
|
|
const escaped = name.split(/[\s_-]+/).map(part => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("[\\s_-]*");
|
|
const pattern = new RegExp(`(?:使用|选择|指定|通过|用)\\s*(?:模型\\s*)?${escaped}(?![a-z0-9.-])`, "ig");
|
|
for (const match of text.matchAll(pattern)) {
|
|
if (!/(?:不要|不|别|禁止|无需)\s*$/.test(text.slice(Math.max(0, match.index! - 8), match.index!))) matches.push({ id, index: match.index!, length: name.length });
|
|
}
|
|
}
|
|
return matches.sort((a, b) => b.index - a.index || b.length - a.length)[0]?.id;
|
|
}
|