import Foundation public struct PrivateApplicationRules: Equatable, Sendable { public let content: String public init?(content: String?) { guard let content else { return nil } let trimmedContent = content.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmedContent.isEmpty else { return nil } self.content = trimmedContent } } public protocol ApplicationRuleProviding: Sendable { func privateApplicationRules() throws -> PrivateApplicationRules? } public struct StaticApplicationRuleProvider: ApplicationRuleProviding { private let rules: PrivateApplicationRules? public init(rules: PrivateApplicationRules?) { self.rules = rules } public func privateApplicationRules() throws -> PrivateApplicationRules? { rules } } public final class ApplicationRuleInjectingAIService: AIService, Sendable { private let baseService: any AIService private let ruleProvider: any ApplicationRuleProviding public init( baseService: any AIService, ruleProvider: any ApplicationRuleProviding ) { self.baseService = baseService self.ruleProvider = ruleProvider } public func generateSongProject(from request: SongProjectGenerationRequest) async throws -> SongProjectGenerationResult { try await baseService.generateSongProject(from: requestWithInjectedRules(request)) } public func reviseLyrics(from request: LyricsRevisionRequest) async throws -> LyricsRevisionResult { try await baseService.reviseLyrics(from: requestWithInjectedRules(request)) } public func proposeProjectUpdate(from request: SongProjectUpdateRequest) async throws -> SongProjectUpdateResult { try await baseService.proposeProjectUpdate(from: requestWithInjectedRules(request)) } private func requestWithInjectedRules(_ request: SongProjectGenerationRequest) throws -> SongProjectGenerationRequest { var request = request request.context.injectPrivateApplicationRules(try ruleProvider.privateApplicationRules()) return request } private func requestWithInjectedRules(_ request: LyricsRevisionRequest) throws -> LyricsRevisionRequest { var request = request request.context.injectPrivateApplicationRules(try ruleProvider.privateApplicationRules()) return request } private func requestWithInjectedRules(_ request: SongProjectUpdateRequest) throws -> SongProjectUpdateRequest { var request = request request.context.injectPrivateApplicationRules(try ruleProvider.privateApplicationRules()) return request } }