@@ -10,7 +10,7 @@ import (
1010 "strings"
1111 "time"
1212
13- "github.com/cloudwego/eino/schema "
13+ "charm.land/fantasy "
1414 "github.com/mark3labs/mcphost/internal/agent"
1515 "github.com/mark3labs/mcphost/internal/config"
1616 "github.com/mark3labs/mcphost/internal/hooks"
@@ -608,13 +608,12 @@ func runNormalMode(ctx context.Context) error {
608608 tools := mcpAgent .GetTools ()
609609 var toolNames []string
610610 for _ , tool := range tools {
611- if info , err := tool .Info (ctx ); err == nil {
612- toolNames = append (toolNames , info .Name )
613- }
611+ info := tool .Info ()
612+ toolNames = append (toolNames , info .Name )
614613 }
615614
616615 // Main interaction logic
617- var messages []* schema .Message
616+ var messages []fantasy .Message
618617 var sessionManager * session.Manager
619618 if sessionPath != "" {
620619 _ , err := os .Stat (sessionPath )
@@ -637,7 +636,8 @@ func runNormalMode(ctx context.Context) error {
637636
638637 // Convert session messages to schema messages
639638 for _ , msg := range loadedSession .Messages {
640- messages = append (messages , msg .ConvertToSchemaMessage ())
639+ fantasyMsg := msg .ConvertToFantasyMessage ()
640+ messages = append (messages , fantasyMsg )
641641 }
642642
643643 // If we're also saving, use the loaded session with the session manager
@@ -658,9 +658,10 @@ func runNormalMode(ctx context.Context) error {
658658
659659 // Display all previous messages as they would have appeared
660660 for _ , sessionMsg := range loadedSession .Messages {
661- if sessionMsg .Role == "user" {
661+ switch sessionMsg .Role {
662+ case "user" :
662663 cli .DisplayUserMessage (sessionMsg .Content )
663- } else if sessionMsg . Role == "assistant" {
664+ case "assistant" :
664665 // Display tool calls if present
665666 if len (sessionMsg .ToolCalls ) > 0 {
666667 for _ , tc := range sessionMsg .ToolCalls {
@@ -679,7 +680,7 @@ func runNormalMode(ctx context.Context) error {
679680 if sessionMsg .Content != "" {
680681 cli .DisplayAssistantMessage (sessionMsg .Content )
681682 }
682- } else if sessionMsg . Role == "tool" {
683+ case "tool" :
683684 // Display tool result
684685 if sessionMsg .ToolCallID != "" {
685686 if toolCall , exists := toolCallMap [sessionMsg .ToolCallID ]; exists {
@@ -773,7 +774,7 @@ type AgenticLoopConfig struct {
773774}
774775
775776// addMessagesToHistory adds messages to the conversation history and saves to session if available
776- func addMessagesToHistory (messages * []* schema .Message , sessionManager * session.Manager , cli * ui.CLI , newMessages ... * schema .Message ) {
777+ func addMessagesToHistory (messages * []fantasy .Message , sessionManager * session.Manager , cli * ui.CLI , newMessages ... fantasy .Message ) {
777778 // Add to local history
778779 * messages = append (* messages , newMessages ... )
779780
@@ -790,7 +791,7 @@ func addMessagesToHistory(messages *[]*schema.Message, sessionManager *session.M
790791}
791792
792793// replaceMessagesHistory replaces the conversation history and saves to session if available
793- func replaceMessagesHistory (messages * []* schema .Message , sessionManager * session.Manager , cli * ui.CLI , newMessages []* schema .Message ) {
794+ func replaceMessagesHistory (messages * []fantasy .Message , sessionManager * session.Manager , cli * ui.CLI , newMessages []fantasy .Message ) {
794795 // Replace local history
795796 * messages = newMessages
796797
@@ -807,7 +808,7 @@ func replaceMessagesHistory(messages *[]*schema.Message, sessionManager *session
807808}
808809
809810// runAgenticLoop handles all execution modes with a single unified loop
810- func runAgenticLoop (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , messages []* schema .Message , config AgenticLoopConfig , hookExecutor * hooks.Executor ) error {
811+ func runAgenticLoop (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , messages []fantasy .Message , config AgenticLoopConfig , hookExecutor * hooks.Executor ) error {
811812 // Handle initial prompt for non-interactive modes
812813 if ! config .IsInteractive && config .InitialPrompt != "" {
813814 // Execute UserPromptSubmit hooks for non-interactive mode
@@ -837,7 +838,7 @@ func runAgenticLoop(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, mes
837838 }
838839
839840 // Create temporary messages with user input for processing (don't add to history yet)
840- tempMessages := append (messages , schema . UserMessage (config .InitialPrompt ))
841+ tempMessages := append (messages , fantasy . NewUserMessage (config .InitialPrompt ))
841842
842843 // Process the initial prompt with tool calls
843844 _ , conversationMessages , err := runAgenticStep (ctx , mcpAgent , cli , tempMessages , config , hookExecutor )
@@ -875,7 +876,7 @@ func runAgenticLoop(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, mes
875876}
876877
877878// runAgenticStep processes a single step of the agentic loop (handles tool calls)
878- func runAgenticStep (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , messages []* schema .Message , config AgenticLoopConfig , hookExecutor * hooks.Executor ) (* schema. Message , []* schema .Message , error ) {
879+ func runAgenticStep (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , messages []fantasy .Message , config AgenticLoopConfig , hookExecutor * hooks.Executor ) (* fantasy. Response , []fantasy .Message , error ) {
879880 var currentSpinner * ui.Spinner
880881
881882 // Start initial spinner (skip if quiet)
@@ -1153,29 +1154,38 @@ func runAgenticStep(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, mes
11531154 if len (messages ) > 0 {
11541155 // Find the last user message
11551156 for i := len (messages ) - 1 ; i >= 0 ; i -- {
1156- if messages [i ].Role == schema .User {
1157- lastUserMessage = messages [i ].Content
1157+ if messages [i ].Role == fantasy .MessageRoleUser {
1158+ // Extract text from message parts
1159+ for _ , part := range messages [i ].Content {
1160+ if tp , ok := part .(fantasy.TextPart ); ok {
1161+ lastUserMessage = tp .Text
1162+ break
1163+ }
1164+ }
11581165 break
11591166 }
11601167 }
11611168 }
11621169
1170+ // Get text content from response
1171+ responseText := response .Content .Text ()
1172+
11631173 // Update usage tracking for ALL responses (streaming and non-streaming)
11641174 if ! config .Quiet && cli != nil {
11651175 cli .UpdateUsageFromResponse (response , lastUserMessage )
11661176 }
11671177
11681178 // Display assistant response with model name
11691179 // Skip if: quiet mode, same content already displayed, or if streaming completed the full response
1170- streamedFullResponse := responseWasStreamed && streamingContent .String () == response . Content
1171- if ! config .Quiet && cli != nil && response . Content != lastDisplayedContent && response . Content != "" && ! streamedFullResponse {
1172- if err := cli .DisplayAssistantMessageWithModel (response . Content , config .ModelName ); err != nil {
1180+ streamedFullResponse := responseWasStreamed && streamingContent .String () == responseText
1181+ if ! config .Quiet && cli != nil && responseText != lastDisplayedContent && responseText != "" && ! streamedFullResponse {
1182+ if err := cli .DisplayAssistantMessageWithModel (responseText , config .ModelName ); err != nil {
11731183 cli .DisplayError (fmt .Errorf ("display error: %v" , err ))
11741184 return nil , nil , err
11751185 }
11761186 } else if config .Quiet {
11771187 // In quiet mode, only output the final response content to stdout
1178- fmt .Print (response . Content )
1188+ fmt .Print (responseText )
11791189 }
11801190
11811191 // Display usage information immediately after the response (for both streaming and non-streaming)
@@ -1191,15 +1201,14 @@ func runAgenticStep(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI, mes
11911201}
11921202
11931203// executeStopHook executes the Stop hook if a hook executor is available
1194- func executeStopHook (hookExecutor * hooks.Executor , response * schema. Message , stopReason string , modelName string ) {
1204+ func executeStopHook (hookExecutor * hooks.Executor , response * fantasy. Response , stopReason string , modelName string ) {
11951205 if hookExecutor != nil {
11961206 // Prepare metadata
11971207 var meta json.RawMessage
11981208 if response != nil {
1199- metaData := map [string ]interface {} {
1209+ metaData := map [string ]any {
12001210 "model" : modelName ,
1201- "role" : string (response .Role ),
1202- "has_tool_calls" : len (response .ToolCalls ) > 0 ,
1211+ "has_tool_calls" : len (response .Content .ToolCalls ()) > 0 ,
12031212 }
12041213 if metaBytes , err := json .Marshal (metaData ); err == nil {
12051214 meta = json .RawMessage (metaBytes )
@@ -1208,7 +1217,7 @@ func executeStopHook(hookExecutor *hooks.Executor, response *schema.Message, sto
12081217
12091218 responseContent := ""
12101219 if response != nil {
1211- responseContent = response .Content
1220+ responseContent = response .Content . Text ()
12121221 }
12131222
12141223 input := & hooks.StopInput {
@@ -1225,7 +1234,7 @@ func executeStopHook(hookExecutor *hooks.Executor, response *schema.Message, sto
12251234}
12261235
12271236// runInteractiveLoop handles the interactive portion of the agentic loop
1228- func runInteractiveLoop (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , messages []* schema .Message , config AgenticLoopConfig , hookExecutor * hooks.Executor ) error {
1237+ func runInteractiveLoop (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , messages []fantasy .Message , config AgenticLoopConfig , hookExecutor * hooks.Executor ) error {
12291238 for {
12301239 // Get user input
12311240 prompt , err := cli .GetPrompt ()
@@ -1292,7 +1301,7 @@ func runInteractiveLoop(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI,
12921301 cli .DisplayUserMessage (prompt )
12931302
12941303 // Create temporary messages with user input for processing
1295- tempMessages := append (messages , schema . UserMessage (prompt ))
1304+ tempMessages := append (messages , fantasy . NewUserMessage (prompt ))
12961305 // Process the user input with tool calls
12971306 _ , conversationMessages , err := runAgenticStep (ctx , mcpAgent , cli , tempMessages , config , hookExecutor )
12981307 if err != nil {
@@ -1312,7 +1321,7 @@ func runInteractiveLoop(ctx context.Context, mcpAgent *agent.Agent, cli *ui.CLI,
13121321}
13131322
13141323// runNonInteractiveMode handles the non-interactive mode execution
1315- func runNonInteractiveMode (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , prompt , modelName string , messages []* schema .Message , quiet , noExit bool , mcpConfig * config.Config , sessionManager * session.Manager , hookExecutor * hooks.Executor ) error {
1324+ func runNonInteractiveMode (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , prompt , modelName string , messages []fantasy .Message , quiet , noExit bool , mcpConfig * config.Config , sessionManager * session.Manager , hookExecutor * hooks.Executor ) error {
13161325 // Prepare data for slash commands (needed if continuing to interactive mode)
13171326 var serverNames []string
13181327 for name := range mcpConfig .MCPServers {
@@ -1322,9 +1331,8 @@ func runNonInteractiveMode(ctx context.Context, mcpAgent *agent.Agent, cli *ui.C
13221331 tools := mcpAgent .GetTools ()
13231332 var toolNames []string
13241333 for _ , tool := range tools {
1325- if info , err := tool .Info (ctx ); err == nil {
1326- toolNames = append (toolNames , info .Name )
1327- }
1334+ info := tool .Info ()
1335+ toolNames = append (toolNames , info .Name )
13281336 }
13291337
13301338 // Configure and run unified agentic loop
@@ -1345,7 +1353,7 @@ func runNonInteractiveMode(ctx context.Context, mcpAgent *agent.Agent, cli *ui.C
13451353}
13461354
13471355// runInteractiveMode handles the interactive mode execution
1348- func runInteractiveMode (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , serverNames , toolNames []string , modelName string , messages []* schema .Message , sessionManager * session.Manager , hookExecutor * hooks.Executor , approveToolRun bool ) error {
1356+ func runInteractiveMode (ctx context.Context , mcpAgent * agent.Agent , cli * ui.CLI , serverNames , toolNames []string , modelName string , messages []fantasy .Message , sessionManager * session.Manager , hookExecutor * hooks.Executor , approveToolRun bool ) error {
13491357 // Configure and run unified agentic loop
13501358 config := AgenticLoopConfig {
13511359 IsInteractive : true ,
0 commit comments