diff --git a/Source/Private/Core/N2CSerializer.cpp b/Source/Private/Core/N2CSerializer.cpp index 02f56b7..afab0e7 100644 --- a/Source/Private/Core/N2CSerializer.cpp +++ b/Source/Private/Core/N2CSerializer.cpp @@ -751,7 +751,7 @@ bool FN2CSerializer::ParseFlowsFromJson(const TSharedPtr& JsonObjec { if (DataFlow.Value->Type == EJson::String) { - OutFlows.Data.Add(DataFlow.Key, DataFlow.Value->AsString()); + OutFlows.Data.Add(FString(DataFlow.Key.ToView()), DataFlow.Value->AsString()); } } diff --git a/Source/Private/LLM/Providers/N2CLMStudioResponseParser.cpp b/Source/Private/LLM/Providers/N2CLMStudioResponseParser.cpp index 2cea8fc..d5d2ea7 100644 --- a/Source/Private/LLM/Providers/N2CLMStudioResponseParser.cpp +++ b/Source/Private/LLM/Providers/N2CLMStudioResponseParser.cpp @@ -40,6 +40,35 @@ bool UN2CLMStudioResponseParser::ParseLLMResponse( return false; } + // Some reasoning models served through LM Studio return the final structured output + // in reasoning_content while leaving content empty. + if (MessageContent.TrimStartAndEnd().IsEmpty()) + { + const TArray>* ChoicesArray = nullptr; + if (JsonObject->TryGetArrayField(TEXT("choices"), ChoicesArray) && ChoicesArray && ChoicesArray->Num() > 0) + { + const TSharedPtr ChoiceObject = (*ChoicesArray)[0]->AsObject(); + if (ChoiceObject.IsValid()) + { + const TSharedPtr MessageObject = ChoiceObject->GetObjectField(TEXT("message")); + if (MessageObject.IsValid()) + { + FString ReasoningContent; + if (MessageObject->TryGetStringField(TEXT("reasoning_content"), ReasoningContent) && + !ReasoningContent.TrimStartAndEnd().IsEmpty()) + { + MessageContent = ReasoningContent; + FN2CLogger::Get().Log( + TEXT("Using LM Studio reasoning_content because message content was empty"), + EN2CLogSeverity::Info, + TEXT("LMStudioResponseParser") + ); + } + } + } + } + } + // Extract usage information (OpenAI-compatible format) const TSharedPtr UsageObject = JsonObject->GetObjectField(TEXT("usage")); if (UsageObject.IsValid()) @@ -80,7 +109,9 @@ bool UN2CLMStudioResponseParser::ParseLLMResponse( } // Log model info if available - const TSharedPtr ModelInfoObject = JsonObject->GetObjectField(TEXT("model_info")); + const TSharedPtr ModelInfoObject = JsonObject->HasTypedField(TEXT("model_info")) + ? JsonObject->GetObjectField(TEXT("model_info")) + : nullptr; if (ModelInfoObject.IsValid()) { FString Architecture, Quantization, Format; diff --git a/Source/Private/LLM/Providers/N2CLMStudioService.cpp b/Source/Private/LLM/Providers/N2CLMStudioService.cpp index 94a6550..f0696ec 100644 --- a/Source/Private/LLM/Providers/N2CLMStudioService.cpp +++ b/Source/Private/LLM/Providers/N2CLMStudioService.cpp @@ -97,15 +97,26 @@ FString UN2CLMStudioService::FormatRequestPayload(const FString& UserMessage, co // Prepend user message text if configured const UN2CSettings* Settings = GetDefault(); - if (Settings && !Settings->LMStudioPrependedModelCommand.IsEmpty()) + if (Settings) { - FinalUserMessage = Settings->LMStudioPrependedModelCommand + TEXT("\n\n") + FinalUserMessage; - + PayloadBuilder->SetMaxTokens(Settings->LMStudioMaxTokens); + FN2CLogger::Get().Log( - FString::Printf(TEXT("Prepended model command text: %s"), *Settings->LMStudioPrependedModelCommand), + FString::Printf(TEXT("Using LM Studio max tokens: %d"), Settings->LMStudioMaxTokens), EN2CLogSeverity::Debug, TEXT("LMStudioService") ); + + if (!Settings->LMStudioPrependedModelCommand.IsEmpty()) + { + FinalUserMessage = Settings->LMStudioPrependedModelCommand + TEXT("\n\n") + FinalUserMessage; + + FN2CLogger::Get().Log( + FString::Printf(TEXT("Prepended model command text: %s"), *Settings->LMStudioPrependedModelCommand), + EN2CLogSeverity::Debug, + TEXT("LMStudioService") + ); + } } // Add messages - LM Studio supports system prompts diff --git a/Source/Public/Core/N2CSettings.h b/Source/Public/Core/N2CSettings.h index baa3676..bc09094 100644 --- a/Source/Public/Core/N2CSettings.h +++ b/Source/Public/Core/N2CSettings.h @@ -439,6 +439,11 @@ class NODETOCODE_API UN2CSettings : public UDeveloperSettings UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category = "Node to Code | LLM Services | LM Studio", meta=(DisplayName="Server Endpoint")) FString LMStudioEndpoint = "http://localhost:1234"; + + /** LM Studio maximum output tokens */ + UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category = "Node to Code | LLM Services | LM Studio", + meta=(DisplayName="Max Tokens", ClampMin="1", UIMin="1")) + int32 LMStudioMaxTokens = 32768; /** LM Studio Prepended Model Command - Text to prepend to user messages (e.g., '/no_think' to disable thinking for reasoning models, or other model-specific commands). This text will appear at the start of each user message. */ UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category = "Node to Code | LLM Services | LM Studio",