zc
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -2064,6 +2064,12 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
var client = new SimpleAIClient(apiKey, baseUrl, model, settings.useGeminiProtocol);
|
var client = new SimpleAIClient(apiKey, baseUrl, model, settings.useGeminiProtocol);
|
||||||
_currentClient = client;
|
_currentClient = client;
|
||||||
|
|
||||||
|
if (!settings.useGeminiProtocol)
|
||||||
|
{
|
||||||
|
await RunNativeToolLoopAsync(client, settings);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Model-Driven Vision: Start with null image. The model must request it using analyze_screen or capture_screen if needed.
|
// Model-Driven Vision: Start with null image. The model must request it using analyze_screen or capture_screen if needed.
|
||||||
string base64Image = null;
|
string base64Image = null;
|
||||||
|
|
||||||
@@ -2360,10 +2366,13 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
var successfulQueryTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var successfulQueryTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var successfulActionTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var successfulActionTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var failedActionTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var failedActionTools = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
bool loggedQueryPhase = false;
|
||||||
|
bool loggedActionPhase = false;
|
||||||
|
bool loggedReplyPhase = false;
|
||||||
|
|
||||||
int maxSteps = int.MaxValue;
|
int maxSteps = int.MaxValue;
|
||||||
float maxSeconds = Math.Max(2f, settings.reactMaxSeconds <= 0f ? DefaultReactMaxSeconds : settings.reactMaxSeconds);
|
float maxSeconds = Math.Max(2f, settings.reactMaxSeconds <= 0f ? DefaultReactMaxSeconds : settings.reactMaxSeconds);
|
||||||
_thinkingPhaseTotal = 0;
|
_thinkingPhaseTotal = 3;
|
||||||
int strictRetryCount = 0;
|
int strictRetryCount = 0;
|
||||||
int phaseRetryCount = 0;
|
int phaseRetryCount = 0;
|
||||||
const int MaxStrictRetries = 2;
|
const int MaxStrictRetries = 2;
|
||||||
@@ -2380,6 +2389,20 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Prefs.DevMode)
|
||||||
|
{
|
||||||
|
if (phase == RequestPhase.QueryTools && !loggedQueryPhase)
|
||||||
|
{
|
||||||
|
WulaLog.Debug("[WulaAI] ===== Turn 1/3 (QueryTools) =====");
|
||||||
|
loggedQueryPhase = true;
|
||||||
|
}
|
||||||
|
else if (phase == RequestPhase.ActionTools && !loggedActionPhase)
|
||||||
|
{
|
||||||
|
WulaLog.Debug("[WulaAI] ===== Turn 2/3 (ActionTools) =====");
|
||||||
|
loggedActionPhase = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetThinkingPhase(phase == RequestPhase.QueryTools ? 1 : 2, false);
|
SetThinkingPhase(phase == RequestPhase.QueryTools ? 1 : 2, false);
|
||||||
|
|
||||||
string systemInstruction = GetNativeSystemInstruction(phase);
|
string systemInstruction = GetNativeSystemInstruction(phase);
|
||||||
@@ -2389,7 +2412,8 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
messages,
|
messages,
|
||||||
tools,
|
tools,
|
||||||
maxTokens: 2048,
|
maxTokens: 2048,
|
||||||
temperature: 0.2f);
|
temperature: 0.2f,
|
||||||
|
toolChoice: "auto");
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
@@ -2624,7 +2648,13 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finalReply = await client.GetChatCompletionAsync(replyInstruction, BuildReplyHistory(), base64Image: null);
|
if (Prefs.DevMode && !loggedReplyPhase)
|
||||||
|
{
|
||||||
|
WulaLog.Debug("[WulaAI] ===== Turn 3/3 (Reply) =====");
|
||||||
|
loggedReplyPhase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalReply = await client.GetChatCompletionAsync(replyInstruction, BuildReplyHistory(), base64Image: null, toolChoice: "none");
|
||||||
if (string.IsNullOrEmpty(finalReply))
|
if (string.IsNullOrEmpty(finalReply))
|
||||||
{
|
{
|
||||||
AddAssistantMessage("Wula_AI_Error_ConnectionLost".Translate());
|
AddAssistantMessage("Wula_AI_Error_ConnectionLost".Translate());
|
||||||
@@ -2639,7 +2669,7 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
"\n\n# RETRY (REPLY OUTPUT)\n" +
|
"\n\n# RETRY (REPLY OUTPUT)\n" +
|
||||||
"Your last reply included tool call JSON or was empty. Tool calls are DISABLED.\n" +
|
"Your last reply included tool call JSON or was empty. Tool calls are DISABLED.\n" +
|
||||||
"You MUST reply in natural language only. Do NOT output any tool call JSON.\n";
|
"You MUST reply in natural language only. Do NOT output any tool call JSON.\n";
|
||||||
string retryReply = await client.GetChatCompletionAsync(retryReplyInstruction, BuildReplyHistory(), maxTokens: 256, temperature: 0.3f);
|
string retryReply = await client.GetChatCompletionAsync(retryReplyInstruction, BuildReplyHistory(), maxTokens: 256, temperature: 0.3f, toolChoice: "none");
|
||||||
if (!string.IsNullOrEmpty(retryReply))
|
if (!string.IsNullOrEmpty(retryReply))
|
||||||
{
|
{
|
||||||
finalReply = retryReply;
|
finalReply = retryReply;
|
||||||
@@ -2960,6 +2990,8 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
_useGemini = useGemini;
|
_useGemini = useGemini;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetChatCompletionAsync(string instruction, List<(string role, string message)> messages, int? maxTokens = null, float? temperature = null, string base64Image = null)
|
public async Task<string> GetChatCompletionAsync(string instruction, List<(string role, string message)> messages, int? maxTokens = null, float? temperature = null, string base64Image = null, string toolChoice = null)
|
||||||
{
|
{
|
||||||
// 1. Gemini Mode
|
// 1. Gemini Mode
|
||||||
if (_useGemini)
|
if (_useGemini)
|
||||||
@@ -101,6 +101,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
jsonBuilder.Append("\"stream\": false,");
|
jsonBuilder.Append("\"stream\": false,");
|
||||||
if (maxTokens.HasValue) jsonBuilder.Append($"\"max_tokens\": {Math.Max(1, maxTokens.Value)},");
|
if (maxTokens.HasValue) jsonBuilder.Append($"\"max_tokens\": {Math.Max(1, maxTokens.Value)},");
|
||||||
if (temperature.HasValue) jsonBuilder.Append($"\"temperature\": {temperature.Value.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture)},");
|
if (temperature.HasValue) jsonBuilder.Append($"\"temperature\": {temperature.Value.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture)},");
|
||||||
|
if (!string.IsNullOrWhiteSpace(toolChoice)) jsonBuilder.Append($"\"tool_choice\": \"{EscapeJson(toolChoice)}\",");
|
||||||
|
|
||||||
var validMessages = messages.Where(m =>
|
var validMessages = messages.Where(m =>
|
||||||
{
|
{
|
||||||
@@ -167,7 +168,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ChatCompletionResult> GetChatCompletionWithToolsAsync(string instruction, List<ChatMessage> messages, List<Dictionary<string, object>> tools, int? maxTokens = null, float? temperature = null)
|
public async Task<ChatCompletionResult> GetChatCompletionWithToolsAsync(string instruction, List<ChatMessage> messages, List<Dictionary<string, object>> tools, int? maxTokens = null, float? temperature = null, string toolChoice = null)
|
||||||
{
|
{
|
||||||
if (_useGemini)
|
if (_useGemini)
|
||||||
{
|
{
|
||||||
@@ -185,7 +186,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
if (_baseUrl.EndsWith("/chat/completions")) endpoint = _baseUrl;
|
if (_baseUrl.EndsWith("/chat/completions")) endpoint = _baseUrl;
|
||||||
else if (!_baseUrl.EndsWith("/v1")) endpoint = $"{_baseUrl}/v1/chat/completions";
|
else if (!_baseUrl.EndsWith("/v1")) endpoint = $"{_baseUrl}/v1/chat/completions";
|
||||||
|
|
||||||
string jsonBody = BuildChatRequestBody(instruction, messages, tools, maxTokens, temperature);
|
string jsonBody = BuildChatRequestBody(instruction, messages, tools, maxTokens, temperature, toolChoice);
|
||||||
string response = await SendRequestRawAsync(endpoint, jsonBody, _apiKey);
|
string response = await SendRequestRawAsync(endpoint, jsonBody, _apiKey);
|
||||||
if (response == null) return null;
|
if (response == null) return null;
|
||||||
|
|
||||||
@@ -306,7 +307,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string BuildChatRequestBody(string instruction, List<ChatMessage> messages, List<Dictionary<string, object>> tools, int? maxTokens, float? temperature)
|
private string BuildChatRequestBody(string instruction, List<ChatMessage> messages, List<Dictionary<string, object>> tools, int? maxTokens, float? temperature, string toolChoice)
|
||||||
{
|
{
|
||||||
var body = new Dictionary<string, object>
|
var body = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
@@ -316,6 +317,7 @@ namespace WulaFallenEmpire.EventSystem.AI
|
|||||||
|
|
||||||
if (maxTokens.HasValue) body["max_tokens"] = Math.Max(1, maxTokens.Value);
|
if (maxTokens.HasValue) body["max_tokens"] = Math.Max(1, maxTokens.Value);
|
||||||
if (temperature.HasValue) body["temperature"] = temperature.Value;
|
if (temperature.HasValue) body["temperature"] = temperature.Value;
|
||||||
|
if (!string.IsNullOrWhiteSpace(toolChoice)) body["tool_choice"] = toolChoice;
|
||||||
|
|
||||||
var messageList = new List<object>();
|
var messageList = new List<object>();
|
||||||
if (!string.IsNullOrEmpty(instruction))
|
if (!string.IsNullOrEmpty(instruction))
|
||||||
|
|||||||
Reference in New Issue
Block a user