已把工具调用从 XML 改成 OpenAI 兼容 JSON,并统一解析/执行流程。改动概览如下:
新增 JSON tool_calls 解析/序列化并替换核心执行与提示词为 JSON-only:JsonToolCallParser.cs、AIIntelligenceCore.cs 工具基类移除 XML 解析,统一 JSON 参数读取与类型转换辅助:AITool.cs 工具实现统一 JSON args/UsageSchema(含重写/修复):Tool_ModifyGoodwill.cs、Tool_SendReinforcement.cs、Tool_GetMapPawns.cs、Tool_GetMapResources.cs、Tool_GetAvailablePrefabs.cs、Tool_CallPrefabAirdrop.cs、Tool_CallBombardment.cs、Tool_GetAvailableBombardments.cs、Tool_GetPawnStatus.cs、Tool_GetRecentNotifications.cs、Tool_SearchThingDef.cs、Tool_SearchPawnKind.cs、Tool_ChangeExpression.cs、Tool_SetOverwatchMode.cs、Tool_RememberFact.cs、Tool_RecallMemories.cs、Tool_SpawnResources.cs、Tool_AnalyzeScreen.cs 轰炸相关解析统一到 JSON 字典并增强数值解析:BombardmentUtility.cs UI 对话展示改为剥离 JSON tool_calls:Overlay_WulaLink.cs、Dialog_AIConversation.cs
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
using WulaFallenEmpire.EventSystem.AI.Utils;
|
||||
|
||||
namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
{
|
||||
@@ -10,34 +12,141 @@ namespace WulaFallenEmpire.EventSystem.AI.Tools
|
||||
{
|
||||
public abstract string Name { get; }
|
||||
public abstract string Description { get; }
|
||||
public abstract string UsageSchema { get; } // XML schema description
|
||||
public abstract string UsageSchema { get; } // JSON schema description
|
||||
|
||||
public virtual string Execute(string args) => "Error: Synchronous execution not supported for this tool.";
|
||||
public virtual Task<string> ExecuteAsync(string args) => Task.FromResult(Execute(args));
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to parse XML arguments into a dictionary.
|
||||
/// Supports simple tags and CDATA blocks.
|
||||
/// Helper method to parse JSON arguments into a dictionary.
|
||||
/// </summary>
|
||||
protected Dictionary<string, string> ParseXmlArgs(string xml)
|
||||
protected Dictionary<string, object> ParseJsonArgs(string json)
|
||||
{
|
||||
var argsDict = new Dictionary<string, string>();
|
||||
if (string.IsNullOrEmpty(xml)) return argsDict;
|
||||
|
||||
// Regex to match <tag>value</tag> or <tag><![CDATA[value]]></tag>
|
||||
// Group 1: Tag name
|
||||
// Group 2: CDATA value
|
||||
// Group 3: Simple value
|
||||
var paramMatches = Regex.Matches(xml, @"<([a-zA-Z0-9_]+)>(?:<!\[CDATA\[(.*?)]]>|(.*?))</\1>", RegexOptions.Singleline);
|
||||
|
||||
foreach (Match match in paramMatches)
|
||||
var argsDict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
if (string.IsNullOrWhiteSpace(json)) return argsDict;
|
||||
if (JsonToolCallParser.TryParseObject(json, out Dictionary<string, object> parsed))
|
||||
{
|
||||
string key = match.Groups[1].Value;
|
||||
string value = match.Groups[2].Success ? match.Groups[2].Value : match.Groups[3].Value;
|
||||
argsDict[key] = value;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return argsDict;
|
||||
}
|
||||
|
||||
protected static bool TryGetString(Dictionary<string, object> args, string key, out string value)
|
||||
{
|
||||
value = null;
|
||||
if (args == null || string.IsNullOrWhiteSpace(key)) return false;
|
||||
if (args.TryGetValue(key, out object raw) && raw != null)
|
||||
{
|
||||
value = Convert.ToString(raw, CultureInfo.InvariantCulture);
|
||||
return !string.IsNullOrWhiteSpace(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static bool TryGetInt(Dictionary<string, object> args, string key, out int value)
|
||||
{
|
||||
value = 0;
|
||||
if (!TryGetNumber(args, key, out double number)) return false;
|
||||
value = (int)Math.Round(number);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static bool TryGetFloat(Dictionary<string, object> args, string key, out float value)
|
||||
{
|
||||
value = 0f;
|
||||
if (!TryGetNumber(args, key, out double number)) return false;
|
||||
value = (float)number;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static bool TryGetBool(Dictionary<string, object> args, string key, out bool value)
|
||||
{
|
||||
value = false;
|
||||
if (args == null || string.IsNullOrWhiteSpace(key)) return false;
|
||||
if (!args.TryGetValue(key, out object raw) || raw == null) return false;
|
||||
if (raw is bool b)
|
||||
{
|
||||
value = b;
|
||||
return true;
|
||||
}
|
||||
if (raw is string s && bool.TryParse(s, out bool parsed))
|
||||
{
|
||||
value = parsed;
|
||||
return true;
|
||||
}
|
||||
if (raw is long l)
|
||||
{
|
||||
value = l != 0;
|
||||
return true;
|
||||
}
|
||||
if (raw is double d)
|
||||
{
|
||||
value = Math.Abs(d) > 0.0001;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static bool TryGetObject(Dictionary<string, object> args, string key, out Dictionary<string, object> value)
|
||||
{
|
||||
value = null;
|
||||
if (args == null || string.IsNullOrWhiteSpace(key)) return false;
|
||||
if (args.TryGetValue(key, out object raw) && raw is Dictionary<string, object> dict)
|
||||
{
|
||||
value = dict;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static bool TryGetList(Dictionary<string, object> args, string key, out List<object> value)
|
||||
{
|
||||
value = null;
|
||||
if (args == null || string.IsNullOrWhiteSpace(key)) return false;
|
||||
if (args.TryGetValue(key, out object raw) && raw is List<object> list)
|
||||
{
|
||||
value = list;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static bool LooksLikeJson(string input)
|
||||
{
|
||||
return JsonToolCallParser.LooksLikeJson(input);
|
||||
}
|
||||
|
||||
private static bool TryGetNumber(Dictionary<string, object> args, string key, out double value)
|
||||
{
|
||||
value = 0;
|
||||
if (args == null || string.IsNullOrWhiteSpace(key)) return false;
|
||||
if (!args.TryGetValue(key, out object raw) || raw == null) return false;
|
||||
if (raw is double d)
|
||||
{
|
||||
value = d;
|
||||
return true;
|
||||
}
|
||||
if (raw is float f)
|
||||
{
|
||||
value = f;
|
||||
return true;
|
||||
}
|
||||
if (raw is int i)
|
||||
{
|
||||
value = i;
|
||||
return true;
|
||||
}
|
||||
if (raw is long l)
|
||||
{
|
||||
value = l;
|
||||
return true;
|
||||
}
|
||||
if (raw is string s && double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsed))
|
||||
{
|
||||
value = parsed;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user