zc
This commit is contained in:
@@ -113,7 +113,8 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
- Do NOT split multi-item requests across turns.
|
- Do NOT split multi-item requests across turns.
|
||||||
5. **TOOLS**: You MAY call any tools listed in ""# TOOLS (AVAILABLE)"".
|
5. **TOOLS**: You MAY call any tools listed in ""# TOOLS (AVAILABLE)"".
|
||||||
6. **ANTI-HALLUCINATION**: Never invent tools, parameters, defNames, coordinates, or tool results. If a tool is needed but not available, output { ""tool_calls"": [] }.
|
6. **ANTI-HALLUCINATION**: Never invent tools, parameters, defNames, coordinates, or tool results. If a tool is needed but not available, output { ""tool_calls"": [] }.
|
||||||
7. **NO TAGS**: Do NOT use <think> tags, code fences, or any extra text outside JSON.";
|
7. **STEP BUDGET (OPTIONAL)**: You MAY include { ""meta"": { ""step_budget"": <positive integer> } } to request more tool steps for this turn.
|
||||||
|
8. **NO TAGS**: Do NOT use <think> tags, code fences, or any extra text outside JSON.";
|
||||||
|
|
||||||
public AIIntelligenceCore(World world) : base(world)
|
public AIIntelligenceCore(World world) : base(world)
|
||||||
{
|
{
|
||||||
@@ -923,14 +924,27 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int? ExtractStepBudget(string json)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(json)) return null;
|
||||||
|
var match = Regex.Match(json, "\"step_budget\"\\s*:\\s*\"?(\\d+)\"?", RegexOptions.IgnoreCase);
|
||||||
|
if (!match.Success) return null;
|
||||||
|
if (int.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static string BuildReactFormatFixInstruction(string previousOutput)
|
private static string BuildReactFormatFixInstruction(string previousOutput)
|
||||||
{
|
{
|
||||||
return "# FORMAT FIX (REACT JSON ONLY)\n" +
|
return "# FORMAT FIX (REACT JSON ONLY)\n" +
|
||||||
"Output valid JSON with fields thought/tool_calls.\n" +
|
"Output valid JSON with fields thought/tool_calls.\n" +
|
||||||
"If tools are needed, tool_calls must be non-empty.\n" +
|
"If tools are needed, tool_calls must be non-empty.\n" +
|
||||||
"If no tools are needed, output exactly: {\"tool_calls\": []} (you may include thought).\n" +
|
"If no tools are needed, output exactly: {\"tool_calls\": []} (you may include thought).\n" +
|
||||||
|
"You MAY include an optional meta block: {\"meta\":{\"step_budget\":<positive integer>}}.\n" +
|
||||||
"Do NOT output any text outside JSON.\n" +
|
"Do NOT output any text outside JSON.\n" +
|
||||||
"Schema: {\"thought\":\"...\",\"tool_calls\":[{\"type\":\"function\",\"function\":{\"name\":\"tool_name\",\"arguments\":{...}}}]}\n" +
|
"Schema: {\"thought\":\"...\",\"tool_calls\":[{\"type\":\"function\",\"function\":{\"name\":\"tool_name\",\"arguments\":{...}}}],\"meta\":{\"step_budget\":7}}\n" +
|
||||||
"\nPrevious output:\n" + TrimForPrompt(previousOutput, 600);
|
"\nPrevious output:\n" + TrimForPrompt(previousOutput, 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,8 +978,9 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
"You used tool names that are NOT available: " + invalidList + "\n" +
|
"You used tool names that are NOT available: " + invalidList + "\n" +
|
||||||
"Re-emit JSON with only available tools from # TOOLS (AVAILABLE).\n" +
|
"Re-emit JSON with only available tools from # TOOLS (AVAILABLE).\n" +
|
||||||
"If no tools are needed, output exactly: {\"tool_calls\": []}.\n" +
|
"If no tools are needed, output exactly: {\"tool_calls\": []}.\n" +
|
||||||
|
"You MAY include an optional meta block: {\"meta\":{\"step_budget\":<positive integer>}}.\n" +
|
||||||
"Do NOT output any text outside JSON.\n" +
|
"Do NOT output any text outside JSON.\n" +
|
||||||
"Schema: {\"thought\":\"...\",\"tool_calls\":[{\"type\":\"function\",\"function\":{\"name\":\"tool_name\",\"arguments\":{...}}}]}";
|
"Schema: {\"thought\":\"...\",\"tool_calls\":[{\"type\":\"function\",\"function\":{\"name\":\"tool_name\",\"arguments\":{...}}}],\"meta\":{\"step_budget\":7}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ShouldRetryTools(string response)
|
private static bool ShouldRetryTools(string response)
|
||||||
@@ -1832,13 +1847,16 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
int maxSteps = DefaultReactMaxSteps;
|
int maxSteps = DefaultReactMaxSteps;
|
||||||
float maxSeconds = DefaultReactMaxSeconds;
|
float maxSeconds = DefaultReactMaxSeconds;
|
||||||
|
|
||||||
|
int stepBudgetMax = int.MaxValue;
|
||||||
if (settings != null)
|
if (settings != null)
|
||||||
{
|
{
|
||||||
maxSteps = Math.Max(1, Math.Min(10, settings.reactMaxSteps));
|
stepBudgetMax = Math.Max(1, settings.reactMaxStepsMax);
|
||||||
maxSeconds = Mathf.Clamp(settings.reactMaxSeconds, 2f, 60f);
|
maxSteps = Math.Max(1, settings.reactMaxSteps);
|
||||||
|
maxSeconds = Math.Max(2f, settings.reactMaxSeconds);
|
||||||
}
|
}
|
||||||
_thinkingPhaseTotal = maxSteps;
|
_thinkingPhaseTotal = maxSteps;
|
||||||
string toolPhaseReplyCandidate = null;
|
string toolPhaseReplyCandidate = null;
|
||||||
|
bool budgetApplied = false;
|
||||||
for (int step = 1; step <= maxSteps; step++)
|
for (int step = 1; step <= maxSteps; step++)
|
||||||
{
|
{
|
||||||
if (Time.realtimeSinceStartup - startTime > maxSeconds)
|
if (Time.realtimeSinceStartup - startTime > maxSeconds)
|
||||||
@@ -1862,6 +1880,7 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
}
|
}
|
||||||
|
|
||||||
string normalizedResponse = NormalizeReactResponse(response);
|
string normalizedResponse = NormalizeReactResponse(response);
|
||||||
|
string parsedSource = normalizedResponse;
|
||||||
if (!JsonToolCallParser.TryParseToolCallsFromText(normalizedResponse, out var toolCalls, out string jsonFragment))
|
if (!JsonToolCallParser.TryParseToolCallsFromText(normalizedResponse, out var toolCalls, out string jsonFragment))
|
||||||
{
|
{
|
||||||
if (LooksLikeNaturalReply(normalizedResponse))
|
if (LooksLikeNaturalReply(normalizedResponse))
|
||||||
@@ -1890,6 +1909,27 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
parsedSource = normalizedFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!budgetApplied && !string.IsNullOrWhiteSpace(jsonFragment))
|
||||||
|
{
|
||||||
|
string budgetSource = jsonFragment;
|
||||||
|
int? requested = ExtractStepBudget(budgetSource);
|
||||||
|
if (!requested.HasValue)
|
||||||
|
{
|
||||||
|
requested = ExtractStepBudget(parsedSource);
|
||||||
|
}
|
||||||
|
if (requested.HasValue)
|
||||||
|
{
|
||||||
|
budgetApplied = true;
|
||||||
|
int clamped = Math.Max(1, Math.Min(stepBudgetMax, requested.Value));
|
||||||
|
if (clamped > maxSteps)
|
||||||
|
{
|
||||||
|
maxSteps = clamped;
|
||||||
|
_thinkingPhaseTotal = maxSteps;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var invalidTools = toolCalls
|
var invalidTools = toolCalls
|
||||||
@@ -1907,9 +1947,30 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
string correctionInstruction = BuildReactToolCorrectionInstruction(invalidTools);
|
string correctionInstruction = BuildReactToolCorrectionInstruction(invalidTools);
|
||||||
string correctedResponse = await client.GetChatCompletionAsync(correctionInstruction, reactContext, maxTokens: 1024, temperature: 0.1f, base64Image: base64Image);
|
string correctedResponse = await client.GetChatCompletionAsync(correctionInstruction, reactContext, maxTokens: 1024, temperature: 0.1f, base64Image: base64Image);
|
||||||
string normalizedCorrected = NormalizeReactResponse(correctedResponse);
|
string normalizedCorrected = NormalizeReactResponse(correctedResponse);
|
||||||
if (!string.IsNullOrEmpty(normalizedCorrected) &&
|
if (!string.IsNullOrEmpty(normalizedCorrected) &&
|
||||||
JsonToolCallParser.TryParseToolCallsFromText(normalizedCorrected, out toolCalls, out jsonFragment))
|
JsonToolCallParser.TryParseToolCallsFromText(normalizedCorrected, out toolCalls, out jsonFragment))
|
||||||
{
|
{
|
||||||
|
if (!budgetApplied && !string.IsNullOrWhiteSpace(jsonFragment))
|
||||||
|
{
|
||||||
|
string budgetSource = jsonFragment;
|
||||||
|
int? requested = ExtractStepBudget(budgetSource);
|
||||||
|
if (!requested.HasValue)
|
||||||
|
{
|
||||||
|
requested = ExtractStepBudget(normalizedCorrected);
|
||||||
|
}
|
||||||
|
if (requested.HasValue)
|
||||||
|
{
|
||||||
|
budgetApplied = true;
|
||||||
|
int clamped = Math.Max(1, Math.Min(stepBudgetMax, requested.Value));
|
||||||
|
if (clamped > maxSteps)
|
||||||
|
{
|
||||||
|
maxSteps = clamped;
|
||||||
|
_thinkingPhaseTotal = maxSteps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parsedSource = normalizedCorrected;
|
||||||
|
|
||||||
invalidTools = toolCalls
|
invalidTools = toolCalls
|
||||||
.Where(c => !IsToolAvailable(c.Name))
|
.Where(c => !IsToolAvailable(c.Name))
|
||||||
.Select(c => c.Name)
|
.Select(c => c.Name)
|
||||||
@@ -2046,7 +2107,9 @@ You are 'The Legion', a super AI of the Wula Empire. Your personality is authori
|
|||||||
private async Task<PhaseExecutionResult> ExecuteJsonToolsForStep(string json)
|
private async Task<PhaseExecutionResult> ExecuteJsonToolsForStep(string json)
|
||||||
{
|
{
|
||||||
string guidance = "ToolRunner Guidance: Continue with JSON only using {\"thought\":\"...\",\"tool_calls\":[...]}. " +
|
string guidance = "ToolRunner Guidance: Continue with JSON only using {\"thought\":\"...\",\"tool_calls\":[...]}. " +
|
||||||
"If no more tools are needed, output exactly: {\"tool_calls\": []}. Do NOT output any text outside JSON.";
|
"If no more tools are needed, output exactly: {\"tool_calls\": []}. " +
|
||||||
|
"You MAY include {\"meta\":{\"step_budget\":<positive integer>}} to request more steps. " +
|
||||||
|
"Do NOT output any text outside JSON.";
|
||||||
|
|
||||||
if (!JsonToolCallParser.TryParseToolCallsFromText(json ?? "", out var toolCalls, out string jsonFragment))
|
if (!JsonToolCallParser.TryParseToolCallsFromText(json ?? "", out var toolCalls, out string jsonFragment))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace WulaFallenEmpire
|
|||||||
public static bool _showVlmApiKey = false;
|
public static bool _showVlmApiKey = false;
|
||||||
private string _maxContextTokensBuffer;
|
private string _maxContextTokensBuffer;
|
||||||
private string _reactMaxStepsBuffer;
|
private string _reactMaxStepsBuffer;
|
||||||
|
private string _reactMaxStepsMaxBuffer;
|
||||||
private string _reactMaxSecondsBuffer;
|
private string _reactMaxSecondsBuffer;
|
||||||
|
|
||||||
public WulaFallenEmpireMod(ModContentPack content) : base(content)
|
public WulaFallenEmpireMod(ModContentPack content) : base(content)
|
||||||
@@ -98,9 +99,13 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
listingStandard.GapLine();
|
listingStandard.GapLine();
|
||||||
listingStandard.Label("<color=cyan>ReAct Loop Settings</color>");
|
listingStandard.Label("<color=cyan>ReAct Loop Settings</color>");
|
||||||
listingStandard.Label("Max Steps (1-10):");
|
listingStandard.Label("Default Steps:");
|
||||||
Rect stepsRect = listingStandard.GetRect(Text.LineHeight);
|
Rect stepsRect = listingStandard.GetRect(Text.LineHeight);
|
||||||
Widgets.TextFieldNumeric(stepsRect, ref settings.reactMaxSteps, ref _reactMaxStepsBuffer, 1, 20);
|
Widgets.TextFieldNumeric(stepsRect, ref settings.reactMaxSteps, ref _reactMaxStepsBuffer, 1, int.MaxValue);
|
||||||
|
|
||||||
|
listingStandard.Label("Max Steps Limit (step_budget upper bound):");
|
||||||
|
Rect stepsMaxRect = listingStandard.GetRect(Text.LineHeight);
|
||||||
|
Widgets.TextFieldNumeric(stepsMaxRect, ref settings.reactMaxStepsMax, ref _reactMaxStepsMaxBuffer, 1, int.MaxValue);
|
||||||
|
|
||||||
listingStandard.Label("Max Seconds (2-60):");
|
listingStandard.Label("Max Seconds (2-60):");
|
||||||
Rect secondsRect = listingStandard.GetRect(Text.LineHeight);
|
Rect secondsRect = listingStandard.GetRect(Text.LineHeight);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace WulaFallenEmpire
|
|||||||
public bool commentOnNegativeOnly = false;
|
public bool commentOnNegativeOnly = false;
|
||||||
public string extraPersonalityPrompt = "";
|
public string extraPersonalityPrompt = "";
|
||||||
public int reactMaxSteps = 4;
|
public int reactMaxSteps = 4;
|
||||||
|
public int reactMaxStepsMax = 7;
|
||||||
public float reactMaxSeconds = 60f;
|
public float reactMaxSeconds = 60f;
|
||||||
public bool showReactTraceInUI = false;
|
public bool showReactTraceInUI = false;
|
||||||
|
|
||||||
@@ -48,6 +49,7 @@ namespace WulaFallenEmpire
|
|||||||
Scribe_Values.Look(ref commentOnNegativeOnly, "commentOnNegativeOnly", false);
|
Scribe_Values.Look(ref commentOnNegativeOnly, "commentOnNegativeOnly", false);
|
||||||
Scribe_Values.Look(ref extraPersonalityPrompt, "extraPersonalityPrompt", "");
|
Scribe_Values.Look(ref extraPersonalityPrompt, "extraPersonalityPrompt", "");
|
||||||
Scribe_Values.Look(ref reactMaxSteps, "reactMaxSteps", 4);
|
Scribe_Values.Look(ref reactMaxSteps, "reactMaxSteps", 4);
|
||||||
|
Scribe_Values.Look(ref reactMaxStepsMax, "reactMaxStepsMax", 7);
|
||||||
Scribe_Values.Look(ref reactMaxSeconds, "reactMaxSeconds", 60f);
|
Scribe_Values.Look(ref reactMaxSeconds, "reactMaxSeconds", 60f);
|
||||||
Scribe_Values.Look(ref showReactTraceInUI, "showReactTraceInUI", false);
|
Scribe_Values.Look(ref showReactTraceInUI, "showReactTraceInUI", false);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user