Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fdc53bf
WIP
amakropoulos Aug 13, 2025
bda6dff
Merge fdc53bf9e7b72d3ed871bf9d9a4fae8a09e50340 into 891497bf8ad6d10f9…
amakropoulos Aug 13, 2025
0f94f6f
update VERSION
amakropoulos Aug 13, 2025
728babc
working setup
amakropoulos Aug 15, 2025
ddc67c6
fix platform paths on postprocess
amakropoulos Aug 15, 2025
ff1afde
initial working LLM with LlamaLib
amakropoulos Aug 15, 2025
00a76ec
add NewtonSoft JSON dependency
amakropoulos Aug 15, 2025
bd1ec6d
add LlamaLib
amakropoulos Aug 15, 2025
bc74831
implementation of LLMAgent methods (untested)
amakropoulos Aug 15, 2025
8118aa5
allow empty templates
amakropoulos Aug 17, 2025
05caeea
small fixes mainly on the ChatAsync
amakropoulos Aug 17, 2025
23282d4
use ChatAsync instead of Chat
amakropoulos Aug 17, 2025
8762162
move completion parameters to LLMCaller
amakropoulos Aug 18, 2025
42ae20f
rename LLMCaller to LLMClient
amakropoulos Aug 18, 2025
5c62cec
simplify grammar by keeping the grammar value instead of the file
amakropoulos Aug 18, 2025
f778fb9
remove unused completion parameters
amakropoulos Aug 18, 2025
567ad3f
getters/setters for variables needing more actions
amakropoulos Aug 18, 2025
958f8b9
remove not needed classes
amakropoulos Aug 18, 2025
2614d20
general improvements and small fixes
amakropoulos Aug 19, 2025
18d1d1b
more changes
amakropoulos Aug 19, 2025
8f7f869
more improvements
amakropoulos Aug 19, 2025
c715ccf
check callback target for destruction
amakropoulos Aug 20, 2025
b9e9464
initial pass of basic unit test
amakropoulos Nov 11, 2025
116e41e
update to latest LlamaLib (remote changes)
amakropoulos Nov 13, 2025
548820b
simplify library finding
amakropoulos Nov 13, 2025
1425189
small fixes
amakropoulos Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/doxygen/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ PROJECT_NAME = "LLM for Unity"
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = v2.5.2
PROJECT_NUMBER = v3.0.0

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
Expand Down
2 changes: 1 addition & 1 deletion Editor/LLMBuildProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static void PostprocessIOSBuild(BuildTarget buildTarget, string outputPat

string libraryFile = LLMUnitySetup.RelativePath(LLMUnitySetup.SearchDirectory(outputPath, $"libundreamai_{buildTarget.ToString().ToLower()}.a"), outputPath);
string fileGuid = project.FindFileGuidByProjectPath(libraryFile);
if (string.IsNullOrEmpty(fileGuid)) Debug.LogError($"Library file {libraryFile} not found in project");
if (string.IsNullOrEmpty(fileGuid)) LLMUnitySetup.LogError($"Library file {libraryFile} not found in project");
else
{
foreach (var phaseGuid in project.GetAllBuildPhasesForTarget(unityMainTargetGuid))
Expand Down
22 changes: 5 additions & 17 deletions Editor/LLMCallerEditor.cs → Editor/LLMClientEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

namespace LLMUnity
{
[CustomEditor(typeof(LLMCaller), true)]
[CustomEditor(typeof(LLMClient), true)]
public class LLMCallerEditor : PropertyEditor {}

[CustomEditor(typeof(LLMCharacter), true)]
public class LLMCharacterEditor : LLMCallerEditor
[CustomEditor(typeof(LLMAgent), true)]
public class LLMAgentEditor : LLMCallerEditor
{
public override void AddModelSettings(SerializedObject llmScriptSO)
{
Expand All @@ -23,26 +23,14 @@ public override void AddModelSettings(SerializedObject llmScriptSO)
ShowPropertiesOfClass("", llmScriptSO, new List<Type> { typeof(ModelAttribute) }, false);

EditorGUILayout.BeginHorizontal();
GUILayout.Label("Grammar", GUILayout.Width(EditorGUIUtility.labelWidth));
if (GUILayout.Button("Load grammar", GUILayout.Width(buttonWidth)))
{
EditorApplication.delayCall += () =>
{
string path = EditorUtility.OpenFilePanelWithFilters("Select a gbnf grammar file", "", new string[] { "Grammar Files", "gbnf" });
string path = EditorUtility.OpenFilePanelWithFilters("Select a gbnf grammar file", "", new string[] { "Grammar Files", "json,gbnf" });
if (!string.IsNullOrEmpty(path))
{
((LLMCharacter)target).SetGrammar(path);
}
};
}
if (GUILayout.Button("Load JSON grammar", GUILayout.Width(buttonWidth)))
{
EditorApplication.delayCall += () =>
{
string path = EditorUtility.OpenFilePanelWithFilters("Select a json schema grammar file", "", new string[] { "Grammar Files", "json" });
if (!string.IsNullOrEmpty(path))
{
((LLMCharacter)target).SetJSONGrammar(path);
((LLMAgent)target).LoadGrammar(path);
}
};
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 16 additions & 41 deletions Editor/LLMEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,17 @@ void AddSSLLoad(string type, Callback<string> setterCallback)
}
}

void AddSSLInfo(string propertyName, string type, Callback<string> setterCallback)
{
string path = llmScriptSO.FindProperty(propertyName).stringValue;
if (path != "")
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("SSL " + type + " path", path);
if (GUILayout.Button(trashIcon, GUILayout.Height(actionColumnWidth), GUILayout.Width(actionColumnWidth))) setterCallback("");
EditorGUILayout.EndHorizontal();
}
}

EditorGUILayout.LabelField("Server Security Settings", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(llmScriptSO.FindProperty("APIKey"));
EditorGUILayout.PropertyField(llmScriptSO.FindProperty("_APIKey"));

if (llmScriptSO.FindProperty("advancedOptions").boolValue)
{
EditorGUILayout.BeginHorizontal();
AddSSLLoad("certificate", llmScript.SetSSLCert);
AddSSLLoad("key", llmScript.SetSSLKey);
AddSSLLoad("certificate", llmScript.SetSSLCertFromFile);
AddSSLLoad("key", llmScript.SetSSLKeyFromFile);
EditorGUILayout.EndHorizontal();
AddSSLInfo("SSLCertPath", "certificate", llmScript.SetSSLCert);
AddSSLInfo("SSLKeyPath", "key", llmScript.SetSSLKey);
EditorGUILayout.PropertyField(llmScriptSO.FindProperty("_SSLCert"));
EditorGUILayout.PropertyField(llmScriptSO.FindProperty("_SSLKey"));
}
Space();
}
Expand Down Expand Up @@ -111,7 +99,7 @@ public override void AddModelSettings(SerializedObject llmScriptSO)
if (llmScriptSO.FindProperty("advancedOptions").boolValue)
{
attributeClasses.Add(typeof(ModelAdvancedAttribute));
if (LLMUnitySetup.FullLlamaLib) attributeClasses.Add(typeof(ModelExtrasAttribute));
attributeClasses.Add(typeof(ModelExtrasAttribute));
}
ShowPropertiesOfClass("", llmScriptSO, attributeClasses, false);
Space();
Expand All @@ -126,10 +114,10 @@ static void ResetModelOptions()
{
List<string> existingOptions = new List<string>();
foreach (ModelEntry entry in LLMManager.modelEntries) existingOptions.Add(entry.url);
modelOptions = new List<string>(){"Download model", "Custom URL"};
modelNames = new List<string>(){null, null};
modelURLs = new List<string>(){null, null};
modelLicenses = new List<string>(){null, null};
modelOptions = new List<string>() { "Download model", "Custom URL" };
modelNames = new List<string>() { null, null };
modelURLs = new List<string>() { null, null };
modelLicenses = new List<string>() { null, null };
foreach (var entry in LLMUnitySetup.modelOptions)
{
string category = entry.Key;
Expand All @@ -146,9 +134,9 @@ static void ResetModelOptions()

float[] GetColumnWidths(bool expandedView)
{
List<float> widths = new List<float>(){actionColumnWidth, nameColumnWidth, templateColumnWidth};
if (expandedView) widths.AddRange(new List<float>(){textColumnWidth, textColumnWidth});
widths.AddRange(new List<float>(){includeInBuildColumnWidth, actionColumnWidth});
List<float> widths = new List<float>() { actionColumnWidth, nameColumnWidth, templateColumnWidth };
if (expandedView) widths.AddRange(new List<float>() { textColumnWidth, textColumnWidth });
widths.AddRange(new List<float>() { includeInBuildColumnWidth, actionColumnWidth });
return widths.ToArray();
}

Expand Down Expand Up @@ -351,19 +339,6 @@ void OnEnable()

DrawCopyableLabel(nameRect, entry.label, entry.filename);

if (!entry.lora)
{
string[] templateDescriptions = ChatTemplate.templatesDescription.Keys.ToList().ToArray();
string[] templates = ChatTemplate.templatesDescription.Values.ToList().ToArray();
int templateIndex = Array.IndexOf(templates, entry.chatTemplate);
int newTemplateIndex = EditorGUI.Popup(templateRect, templateIndex, templateDescriptions);
if (newTemplateIndex != templateIndex)
{
LLMManager.SetTemplate(entry.filename, templates[newTemplateIndex]);
UpdateModels();
}
}

if (expandedView)
{
if (hasURL)
Expand Down Expand Up @@ -440,14 +415,14 @@ private void DrawCopyableLabel(Rect rect, string label, string text = "")

private void CopyToClipboard(string text)
{
TextEditor te = new TextEditor {text = text};
TextEditor te = new TextEditor { text = text };
te.SelectAll();
te.Copy();
}

public void AddExtrasToggle()
{
if (ToggleButton("Use extras", LLMUnitySetup.FullLlamaLib)) LLMUnitySetup.SetFullLlamaLib(!LLMUnitySetup.FullLlamaLib);
if (ToggleButton("Use cuBLAS", LLMUnitySetup.CUBLAS)) LLMUnitySetup.SetCUBLAS(!LLMUnitySetup.CUBLAS);
}

public override void AddOptionsToggles(SerializedObject llmScriptSO)
Expand Down Expand Up @@ -481,7 +456,7 @@ public override void OnInspectorGUI()

AddOptionsToggles(llmScriptSO);
AddSetupSettings(llmScriptSO);
if (llmScriptSO.FindProperty("remote").boolValue) AddSecuritySettings(llmScriptSO, llmScript);
if (llmScriptSO.FindProperty("_remote").boolValue) AddSecuritySettings(llmScriptSO, llmScript);
AddModelLoadersSettings(llmScriptSO, llmScript);
AddChatSettings(llmScriptSO);

Expand Down
2 changes: 1 addition & 1 deletion Editor/PropertyEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public virtual bool ToggleButton(string text, bool activated)
public virtual void AddSetupSettings(SerializedObject llmScriptSO)
{
List<Type> attributeClasses = new List<Type>(){typeof(LocalRemoteAttribute)};
SerializedProperty remoteProperty = llmScriptSO.FindProperty("remote");
SerializedProperty remoteProperty = llmScriptSO.FindProperty("_remote");
if (remoteProperty != null) attributeClasses.Add(remoteProperty.boolValue ? typeof(RemoteAttribute) : typeof(LocalAttribute));
attributeClasses.Add(typeof(LLMAttribute));
if (llmScriptSO.FindProperty("advancedOptions").boolValue)
Expand Down
12 changes: 6 additions & 6 deletions Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ If the user's GPU is not supported, the LLM will fall back to the CPU
- `Debug` select to log the output of the model in the Unity Editor
- <details><summary>Advanced options</summary>

- <details><summary><code>Parallel Prompts</code> number of prompts / slots that can happen in parallel (default: -1 = number of LLMCharacter objects). Note that the context size is divided among the slots.</summary> If you want to retain as much context for the LLM and don't need all the characters present at the same time, you can set this number and specify the slot for each LLMCharacter object.
e.g. Setting `Parallel Prompts` to 1 and slot 0 for all LLMCharacter objects will use the full context, but the entire prompt will need to be computed (no caching) whenever a LLMCharacter object is used for chat. </details>
- <details><summary><code>Parallel Prompts</code> number of prompts / slots that can happen in parallel (default: -1 = number of LLMAgent objects). Note that the context size is divided among the slots.</summary> If you want to retain as much context for the LLM and don't need all the characters present at the same time, you can set this number and specify the slot for each LLMAgent object.
e.g. Setting `Parallel Prompts` to 1 and slot 0 for all LLMAgent objects will use the full context, but the entire prompt will need to be computed (no caching) whenever a LLMAgent object is used for chat. </details>
- `Dont Destroy On Load` select to not destroy the LLM GameObject when loading a new Scene

</details>

## Server Security Settings

- `API key` API key to use to allow access to requests from LLMCharacter objects (if `Remote` is set)
- `API key` API key to use to allow access to requests from LLMAgent objects (if `Remote` is set)
- <details><summary>Advanced options</summary>

- `Load SSL certificate` allows to load a SSL certificate for end-to-end encryption of requests (if `Remote` is set). Requires SSL key as well.
Expand Down Expand Up @@ -58,15 +58,15 @@ If the user's GPU is not supported, the LLM will fall back to the CPU

</details>

## LLMCharacter Settings
## LLMAgent Settings

- `Show/Hide Advanced Options` Toggle to show/hide advanced options from below
- `Log Level` select how verbose the log messages are
- `Use extras` select to install and allow the use of extra features (flash attention and IQ quants)

## 💻 Setup Settings
<div>
<img width="300" src=".github/LLMCharacter_GameObject.png" align="right"/>
<img width="300" src=".github/LLMAgent_GameObject.png" align="right"/>
</div>

- `Remote` whether the LLM used is remote or local
Expand Down Expand Up @@ -113,4 +113,4 @@ If it is not selected, the full reply from the model is received in one go
- `N Probs`: if greater than 0, the response also contains the probabilities of top N tokens for each generated token (default: 0)
- `Ignore Eos`: enable to ignore end of stream tokens and continue generating (default: false).

</details>
</details>
Loading