66 lines
3.1 KiB
TypeScript
66 lines
3.1 KiB
TypeScript
import type { AgentCallRecord, AgentRunSnapshot } from "./protocol";
|
|
|
|
// A spontaneous download command is not an unfinished image edit. Keep genuine
|
|
// download requests and all editor panels waiting for their actual interaction.
|
|
export function isAncillaryDownload(snapshot: AgentRunSnapshot, call: AgentCallRecord) {
|
|
const intent = [snapshot.objective, ...snapshot.inputs.map(input => input.text)].join("\n")
|
|
.replace(/(?:不要|无需|不需要|不用|不必|禁止|别)(?:再|主动|自动|继续)?\s*(?:下载|导出|保存.{0,8}(?:本地|电脑))|(?:do\s+not|don't|never)\s+(?:download|export)/gi, "");
|
|
return call.name === "image_download" && call.status === "succeeded" &&
|
|
call.output?.mode === "interactive" && finalResultNodeIds(snapshot).length > 0 &&
|
|
!/下载|导出|保存.*(?:本地|电脑)|download|export/i.test(intent);
|
|
}
|
|
|
|
/** This command merely adds an existing image to the composer. It does not
|
|
* open an editor or require the user to supply files/confirm a media operation. */
|
|
export function isCompletedComposerReference(call: AgentCallRecord) {
|
|
return call.name === "image_add_to_chat" && call.status === "succeeded" &&
|
|
call.output?.status === "succeeded" && call.output?.mode === "interactive";
|
|
}
|
|
|
|
export function requiresCanvasInteraction(snapshot: AgentRunSnapshot, call: AgentCallRecord) {
|
|
return call.output?.mode === "interactive" && !isAncillaryDownload(snapshot, call) && !isCompletedComposerReference(call);
|
|
}
|
|
|
|
export function finalImageResultNodeIds(
|
|
snapshot: AgentRunSnapshot,
|
|
nodes: Array<{ id: string; type: string }>,
|
|
) {
|
|
const images = new Set(nodes.filter((node) => node.type === "image").map((node) => node.id));
|
|
return finalResultNodeIds(snapshot).filter((id) => images.has(id));
|
|
}
|
|
|
|
export function finalResultNodeIds(snapshot: AgentRunSnapshot) {
|
|
const consumed = new Set(
|
|
snapshot.calls
|
|
.filter(
|
|
(call) => Array.isArray(call.output?.createdNodeIds) && call.output.createdNodeIds.length,
|
|
)
|
|
.flatMap((call) => sourceIds(call.input, call.output)),
|
|
);
|
|
return snapshot.resultNodeIds.filter((id) => !consumed.has(id));
|
|
}
|
|
function sourceIds(input: Record<string, unknown>, output?: Record<string, unknown>) {
|
|
return [
|
|
...(Array.isArray(input.referenceNodeIds) ? input.referenceNodeIds : []),
|
|
...(Array.isArray(input.nodeIds) ? input.nodeIds : []),
|
|
...(Array.isArray(output?.outputs) ? output.outputs.map((item) => item?.sourceNodeId) : []),
|
|
].filter((id): id is string => typeof id === "string");
|
|
}
|
|
export function originalSourceNodeIds(snapshot: AgentRunSnapshot, nodeIds: string[]) {
|
|
const visited = new Set<string>();
|
|
const originals = new Set<string>();
|
|
const visit = (id: string) => {
|
|
if (visited.has(id)) return;
|
|
visited.add(id);
|
|
const producer = snapshot.calls.find(
|
|
(call) =>
|
|
Array.isArray(call.output?.createdNodeIds) && call.output.createdNodeIds.includes(id),
|
|
);
|
|
const sources = producer ? sourceIds(producer.input, producer.output) : [];
|
|
if (sources.length) sources.forEach(visit);
|
|
else if (!snapshot.resultNodeIds.includes(id)) originals.add(id);
|
|
};
|
|
nodeIds.forEach(visit);
|
|
return [...originals];
|
|
}
|