2026-07-25 12:04:06 +08:00
package runtime
import (
2026-08-28 22:23:13 +08:00
"context"
"net/http"
2026-07-25 12:04:06 +08:00
"strings"
"testing"
2026-08-28 22:23:13 +08:00
"code.tczkiot.com/wlw/ai-agent/contract"
"code.tczkiot.com/wlw/ai-agent/internal/ai"
2026-08-21 00:41:07 +08:00
"code.tczkiot.com/wlw/ai-agent/internal/models"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/enums"
2026-07-25 12:04:06 +08:00
"github.com/glebarez/sqlite"
"github.com/mlogclub/simple/sqls"
"gorm.io/gorm"
)
2026-08-28 22:23:13 +08:00
type runtimePlatformAIProvider struct {}
func ( runtimePlatformAIProvider ) ModelSource ( context . Context ) ( string , error ) {
return contract . ModelSourcePlatform , nil
}
type runtimeVisionOnlyPlatformAIProvider struct {}
func ( runtimeVisionOnlyPlatformAIProvider ) ModelSource ( context . Context ) ( string , error ) {
return contract . ModelSourcePlatform , nil
}
func ( runtimeVisionOnlyPlatformAIProvider ) Config ( context . Context ) ( * contract . PlatformAIConfig , error ) {
return & contract . PlatformAIConfig {
APIKey : "platform-managed" ,
BaseURL : "https://platform.example/v1" ,
ChatEnabled : false ,
ChatModel : "qwen-plus" ,
VisionEnabled : true ,
VisionModel : "qwen3-vl-plus" ,
}, nil
}
func ( runtimeVisionOnlyPlatformAIProvider ) Status ( context . Context ) ( * contract . PlatformAIStatus , error ) {
return & contract . PlatformAIStatus { VisionEnabled : true , VisionModel : "qwen3-vl-plus" }, nil
}
func ( runtimePlatformAIProvider ) Config ( context . Context ) ( * contract . PlatformAIConfig , error ) {
return & contract . PlatformAIConfig {
APIKey : "license-signed" ,
BaseURL : "https://platform.example/v1" ,
ModelName : "platform-default" ,
TimeoutMS : 30000 ,
MaxRetryCount : 1 ,
HTTPClient : & http . Client {},
}, nil
}
func ( runtimePlatformAIProvider ) Status ( context . Context ) ( * contract . PlatformAIStatus , error ) {
return & contract . PlatformAIStatus { Enabled : true }, nil
}
2026-07-25 12:04:06 +08:00
func TestAgentApplicationServiceLoadsConsistentPersistedRequest ( t * testing . T ) {
db , err := gorm . Open ( sqlite . Open ( "file:" + strings . ReplaceAll ( t . Name (), "/" , "_" ) + "?mode=memory&cache=shared" ), & gorm . Config {})
if err != nil {
t . Fatalf ( "open sqlite: %v" , err )
}
if err := db . AutoMigrate ( & models . AIConfig {}, & models . AIAgent {}, & models . Conversation {}, & models . Message {}); err != nil {
t . Fatalf ( "auto migrate: %v" , err )
}
sqls . SetDB ( db )
config := & models . AIConfig { Status : enums . StatusOk , ModelName : "test-model" }
if err := db . Create ( config ). Error ; err != nil {
t . Fatalf ( "create config: %v" , err )
}
agent := & models . AIAgent { Name : "agent" , Status : enums . StatusOk , AIConfigID : config . ID }
if err := db . Create ( agent ). Error ; err != nil {
t . Fatalf ( "create agent: %v" , err )
}
conversation := & models . Conversation { AIAgentID : agent . ID }
if err := db . Create ( conversation ). Error ; err != nil {
t . Fatalf ( "create conversation: %v" , err )
}
message := & models . Message { ConversationID : conversation . ID , SenderType : enums . IMSenderTypeCustomer , MessageType : enums . IMMessageTypeText , Content : "hello" }
if err := db . Create ( message ). Error ; err != nil {
t . Fatalf ( "create message: %v" , err )
}
req , err := NewAgentApplicationService (). loadRequest ( ApplicationRunInput { ConversationID : conversation . ID , MessageID : message . ID , AIAgentID : agent . ID })
if err != nil {
t . Fatalf ( "loadRequest: %v" , err )
}
if req . Conversation . ID != conversation . ID || req . UserMessage . ID != message . ID || req . AIAgent . ID != agent . ID || req . AIConfig . ID != config . ID {
t . Fatalf ( "unexpected request: %#v" , req )
}
}
func TestAgentApplicationServiceRejectsMismatchedMessage ( t * testing . T ) {
service := NewAgentApplicationService ()
if _ , err := service . loadRequest ( ApplicationRunInput { ConversationID : 1 , MessageID : 0 , AIAgentID : 1 }); err == nil {
t . Fatal ( "expected invalid identifiers error" )
}
}
2026-08-28 22:23:13 +08:00
func TestResolveRuntimeAIConfigUsesPlatformWithoutCustomConfig ( t * testing . T ) {
ai . SetPlatformAIProvider ( runtimePlatformAIProvider {})
t . Cleanup ( func () { ai . SetPlatformAIProvider ( nil ) })
config , err := ResolveRuntimeAIConfig ( context . Background (), 0 )
if err != nil {
t . Fatalf ( "ResolveRuntimeAIConfig() error = %v" , err )
}
if ! config . Platform || config . ModelName != "platform-default" || config . APIKey != "license-signed" {
t . Fatalf ( "ResolveRuntimeAIConfig() = %+v" , config )
}
}
func TestResolveRuntimeAIConfigForImageUsesVisionWhenChatIsDisabled ( t * testing . T ) {
ai . SetPlatformAIProvider ( runtimeVisionOnlyPlatformAIProvider {})
t . Cleanup ( func () { ai . SetPlatformAIProvider ( nil ) })
config , err := ResolveRuntimeAIConfigForMessage ( context . Background (), 0 , enums . IMMessageTypeImage )
if err != nil {
t . Fatalf ( "ResolveRuntimeAIConfigForMessage(image) error = %v" , err )
}
if config . ModelName != "qwen3-vl-plus" || ! config . VisionEnabled {
t . Fatalf ( "ResolveRuntimeAIConfigForMessage(image) = %+v" , config )
}
if _ , err := ResolveRuntimeAIConfigForMessage ( context . Background (), 0 , enums . IMMessageTypeText ); err == nil || ! strings . Contains ( err . Error (), "chat model is not enabled" ) {
t . Fatalf ( "text must still require chat capability, got %v" , err )
}
}