|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AI.Workflow
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 工作流状态,在整个流程中唯一,我们使用它来负责节点之间传递数据,避免每个节点添加输入输出接口
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class WorkflowState : ICloneable
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly Dictionary<string, object> _slots = new();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 关联的工作流 ID
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string? WorkflowId { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前执行的节点 ID
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string? CurrentNodeId { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 状态创建时间
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取指定键的值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">值类型</typeparam>
|
|
|
|
|
|
/// <param name="key">键名</param>
|
|
|
|
|
|
/// <returns>值</returns>
|
|
|
|
|
|
/// <exception cref="KeyNotFoundException">当键不存在时抛出</exception>
|
|
|
|
|
|
public T Get<T>(string key) where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_slots.TryGetValue(key, out var value))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new KeyNotFoundException($"Key '{key}' not found in workflow state");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (T)value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 尝试获取指定键的值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">值类型</typeparam>
|
|
|
|
|
|
/// <param name="key">键名</param>
|
|
|
|
|
|
/// <param name="value">输出值</param>
|
|
|
|
|
|
/// <returns>如果键存在返回 true,否则返回 false</returns>
|
|
|
|
|
|
public bool TryGet<T>(string key, out T? value) where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_slots.TryGetValue(key, out var obj) && obj is T typedValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
value = typedValue;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
value = null;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 设置指定键的值
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">值类型</typeparam>
|
|
|
|
|
|
/// <param name="key">键名</param>
|
|
|
|
|
|
/// <param name="value">值</param>
|
|
|
|
|
|
/// <exception cref="ArgumentNullException">当键或值为空时抛出</exception>
|
|
|
|
|
|
public void Set<T>(string key, T value) where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentNullException(nameof(key), "Key cannot be null or whitespace");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (value == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentNullException(nameof(value), "Value cannot be null");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_slots[key] = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 检查指定键是否存在
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="key">键名</param>
|
|
|
|
|
|
/// <returns>如果键存在返回 true</returns>
|
|
|
|
|
|
public bool ContainsKey(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
return _slots.ContainsKey(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 移除指定键
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="key">键名</param>
|
|
|
|
|
|
/// <returns>如果成功移除返回 true</returns>
|
|
|
|
|
|
public bool Remove(string key)
|
|
|
|
|
|
{
|
|
|
|
|
|
return _slots.Remove(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 清空所有数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
|
{
|
|
|
|
|
|
_slots.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取所有键
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>键集合</returns>
|
|
|
|
|
|
public IEnumerable<string> GetKeys()
|
|
|
|
|
|
{
|
|
|
|
|
|
return _slots.Keys;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 克隆工作流状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>新的工作流状态副本</returns>
|
|
|
|
|
|
public object Clone()
|
|
|
|
|
|
{
|
|
|
|
|
|
var json = JsonSerializer.Serialize(_slots);
|
|
|
|
|
|
var copySlots = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
|
|
|
|
|
|
|
|
|
|
|
|
var copy = new WorkflowState
|
|
|
|
|
|
{
|
|
|
|
|
|
WorkflowId = WorkflowId,
|
|
|
|
|
|
CurrentNodeId = CurrentNodeId,
|
|
|
|
|
|
CreatedAt = CreatedAt
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (copySlots != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var kvp in copySlots)
|
|
|
|
|
|
{
|
|
|
|
|
|
copy._slots[kvp.Key] = kvp.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|