Implement optional discussion mode
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import MusicAssistantCore
|
||||
import XCTest
|
||||
|
||||
final class SongProjectDiscussionDirectorTests: XCTestCase {
|
||||
func testDiscussBuildsARequestAndReturnsTrimmedQuestionsWithoutChangingProject() async throws {
|
||||
let project = SongProject(
|
||||
id: "discussion-project",
|
||||
title: "Discussion Project",
|
||||
idea: "Plan a cinematic chorus",
|
||||
conversationMode: .discuss,
|
||||
createdAt: Date(timeIntervalSince1970: 10),
|
||||
updatedAt: Date(timeIntervalSince1970: 20)
|
||||
)
|
||||
let aiService = RecordingDiscussionAIService(
|
||||
result: SongProjectDiscussionResult(
|
||||
questions: [" Should the chorus use a choir? ", " "],
|
||||
notes: ["Awaiting the user's choice."]
|
||||
)
|
||||
)
|
||||
let director = SongProjectDiscussionDirector(aiService: aiService)
|
||||
let conversation = [AIConversationMessage(role: .assistant, content: "What mood should lead?")]
|
||||
|
||||
let result = try await director.discuss(
|
||||
project: project,
|
||||
userMessage: " Keep the verses intimate. ",
|
||||
conversation: conversation,
|
||||
localeIdentifier: "en_US"
|
||||
)
|
||||
let request = await aiService.recordedRequests.first
|
||||
|
||||
XCTAssertEqual(request?.context.userInstruction, "Keep the verses intimate.")
|
||||
XCTAssertEqual(request?.context.conversation, conversation)
|
||||
XCTAssertEqual(request?.context.localeIdentifier, "en_US")
|
||||
XCTAssertEqual(request?.project, project)
|
||||
XCTAssertEqual(result.questions, ["Should the chorus use a choir?"])
|
||||
XCTAssertEqual(result.notes, ["Awaiting the user's choice."])
|
||||
}
|
||||
|
||||
func testDiscussRejectsAutoModeAndBlankMessagesBeforeCallingAI() async throws {
|
||||
let aiService = RecordingDiscussionAIService(
|
||||
result: SongProjectDiscussionResult(questions: ["Unused"])
|
||||
)
|
||||
let director = SongProjectDiscussionDirector(aiService: aiService)
|
||||
|
||||
do {
|
||||
_ = try await director.discuss(
|
||||
project: SongProject(title: "Auto", idea: "Auto", conversationMode: .auto),
|
||||
userMessage: "Ask a question."
|
||||
)
|
||||
XCTFail("Expected discussion mode validation to fail.")
|
||||
} catch let error as SongProjectDiscussionDirectorError {
|
||||
XCTAssertEqual(error, .discussionModeNotEnabled)
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try await director.discuss(
|
||||
project: SongProject(title: "Discuss", idea: "Discuss", conversationMode: .discuss),
|
||||
userMessage: " \n "
|
||||
)
|
||||
XCTFail("Expected blank message validation to fail.")
|
||||
} catch let error as SongProjectDiscussionDirectorError {
|
||||
XCTAssertEqual(error, .emptyUserMessage)
|
||||
}
|
||||
|
||||
let requestCount = await aiService.recordedRequests.count
|
||||
XCTAssertEqual(requestCount, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private actor RecordingDiscussionAIService: AIService {
|
||||
private(set) var recordedRequests: [SongProjectDiscussionRequest] = []
|
||||
private let result: SongProjectDiscussionResult
|
||||
|
||||
init(result: SongProjectDiscussionResult) {
|
||||
self.result = result
|
||||
}
|
||||
|
||||
func generateSongProject(from request: SongProjectGenerationRequest) async throws -> SongProjectGenerationResult {
|
||||
SongProjectGenerationResult(project: request.seedProject ?? SongProject(title: "Unused", idea: "Unused"))
|
||||
}
|
||||
|
||||
func discussSongProject(from request: SongProjectDiscussionRequest) async throws -> SongProjectDiscussionResult {
|
||||
recordedRequests.append(request)
|
||||
return result
|
||||
}
|
||||
|
||||
func reviseLyrics(from request: LyricsRevisionRequest) async throws -> LyricsRevisionResult {
|
||||
LyricsRevisionResult(lyrics: request.sourceLyrics)
|
||||
}
|
||||
|
||||
func proposeProjectUpdate(from request: SongProjectUpdateRequest) async throws -> SongProjectUpdateResult {
|
||||
SongProjectUpdateResult(project: request.project)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user