def compose(query:, network:, channel:, asker:, fetch:, runner:, store: RabbotDb,
profiles: [], model: AGENT_MODEL)
if AiGuard.system_request?(query.to_s)
return { success: false, text: AiGuard.rejection_message }
end
raw = fetch_lyrics(query, fetch: fetch)
return { success: false, text: NO_LYRICS_MESSAGE } unless raw
original_lines = SingFormat.merge_lyric_lines(
SingFormat.normalize_lyrics(raw[:lyrics]).split("\n")
)
return { success: false, text: NO_LYRICS_MESSAGE } if original_lines.empty?
channel_lines = SingaiContext.build_channel_lines(network: network, channel: channel, store: store)
fandom_lines = SingaiContext.build_fandom_lines(profiles: profiles)
prompt = SingaiPrompt.build_agent_prompt(
artist: raw[:artist],
title: raw[:title],
original_lines: original_lines,
channel_lines: channel_lines,
fandom_lines: fandom_lines,
asker: asker,
channel: channel
)
return { success: false, text: prompt } if prompt == AiGuard.rejection_message
result = AiAgent.run_agent(prompt, model: model, runner: runner)
unless result.success?
message = result.text.to_s.strip
return { success: false, text: message.empty? ? "AI lyric rewrite failed." : message }
end
filtered = AiGuard.filter_output(result.text)
return { success: false, text: filtered } if filtered == AiGuard.rejection_message
ai_lines = SingaiMerge.parse_ai_lyrics(filtered)
merged = SingaiMerge.merge_lyrics(original_lines, ai_lines)
body = merged.join("\n")
{
success: true,
text: SingFormat.format_lyrics(raw[:artist], raw[:title], body),
model: result.model || model,
duration_s: result.duration_s
}
end