WorkflowContext.java 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package com.agent.management.engine;
  2. import lombok.extern.slf4j.Slf4j;
  3. import java.nio.file.Path;
  4. import java.util.*;
  5. import java.util.concurrent.ConcurrentHashMap;
  6. /**
  7. * 工作流执行上下文
  8. * 携带节点间传递的变量、工作目录和累积节点输出
  9. */
  10. @Slf4j
  11. public class WorkflowContext {
  12. private final Long workflowId;
  13. private final String runId;
  14. /** 扁平变量表,所有节点的输出变量合并于此(向后兼容 {{varName}} 模板渲染) */
  15. private final Map<String, Object> variables = new ConcurrentHashMap<>();
  16. /**
  17. * 节点级隔离输出表:nodeId -> {varName -> value}。
  18. * 用于实现变量作用域隔离,避免不同分支的同名输出相互覆盖。
  19. */
  20. private final Map<String, Map<String, Object>> nodeScopedOutputs = new ConcurrentHashMap<>();
  21. /** 初始运行输入,与节点输出隔离保存 */
  22. private final Map<String, Object> initialInputs;
  23. /** 本次运行的工作目录,所有节点共享 */
  24. private final Path workingDir;
  25. /** 累积记录每个节点的输出(按执行顺序) */
  26. private final List<NodeOutput> nodeOutputs = Collections.synchronizedList(new ArrayList<>());
  27. /**
  28. * 命名空间扩展槽:承载未来扩展的上下文 section(如 _git / _memory / _runtime)。
  29. * key 以 "_" 开头表示系统级;用户节点不直接读写,仅 executor 内部使用。
  30. */
  31. private final Map<String, Object> sections = new ConcurrentHashMap<>();
  32. /**
  33. * 节点流式事件回调;由引擎在节点执行前注入,executor 通过它实时推送 thinking / 工具增量。
  34. * 为 null 表示当前节点不需要流式推送(向后兼容)。
  35. */
  36. private NodeStreamSink streamSink;
  37. public WorkflowContext(Long workflowId, String runId, Path workingDir, Map<String, Object> initialInputs) {
  38. this.workflowId = workflowId;
  39. this.runId = runId;
  40. this.workingDir = workingDir;
  41. this.initialInputs = initialInputs == null ? Map.of() : new LinkedHashMap<>(initialInputs);
  42. if (initialInputs != null) {
  43. this.variables.putAll(initialInputs);
  44. }
  45. }
  46. public Long getWorkflowId() { return workflowId; }
  47. public String getRunId() { return runId; }
  48. public Map<String, Object> getVariables() { return variables; }
  49. public Path getWorkingDir() { return workingDir; }
  50. public List<NodeOutput> getNodeOutputs() { return Collections.unmodifiableList(nodeOutputs); }
  51. public Map<String, Object> getSections() { return sections; }
  52. public Object getSection(String name) { return sections.get(name); }
  53. public void putSection(String name, Object value) { sections.put(name, value); }
  54. public NodeStreamSink getStreamSink() { return streamSink; }
  55. public void setStreamSink(NodeStreamSink streamSink) { this.streamSink = streamSink; }
  56. /**
  57. * 获取初始运行输入(与节点输出隔离)。
  58. */
  59. public Map<String, Object> getInitialInputs() {
  60. return Collections.unmodifiableMap(initialInputs);
  61. }
  62. public void setVariable(String key, Object value) {
  63. variables.put(key, value);
  64. }
  65. public Object getVariable(String key) {
  66. return variables.get(key);
  67. }
  68. /**
  69. * 记录节点输出:同时更新扁平变量、节点级隔离输出和累积输出列表。
  70. * 变量覆盖检测:若 key 已存在(被上游节点写过),记录 WARN 日志,便于 debug。
  71. */
  72. public void setNodeOutput(String nodeId, Map<String, Object> output) {
  73. if (output != null) {
  74. setNodeScopedOutput(nodeId, output);
  75. for (Map.Entry<String, Object> e : output.entrySet()) {
  76. Object existing = variables.put(e.getKey(), e.getValue());
  77. if (existing != null) {
  78. log.warn("[WorkflowContext] 变量 {} 被节点 {} 覆盖(旧值类型={})",
  79. e.getKey(), nodeId, existing.getClass().getSimpleName());
  80. }
  81. }
  82. nodeOutputs.add(new NodeOutput(nodeId, output));
  83. }
  84. }
  85. /**
  86. * 以节点级命名空间保存节点输出。
  87. */
  88. public void setNodeScopedOutput(String nodeId, Map<String, Object> output) {
  89. if (output == null || output.isEmpty()) {
  90. return;
  91. }
  92. nodeScopedOutputs.compute(nodeId, (k, existing) -> {
  93. Map<String, Object> map = existing == null ? new LinkedHashMap<>() : new LinkedHashMap<>(existing);
  94. map.putAll(output);
  95. return map;
  96. });
  97. }
  98. /**
  99. * 获取指定节点的命名空间输出。
  100. */
  101. public Map<String, Object> getNodeScopedOutput(String nodeId) {
  102. Map<String, Object> map = nodeScopedOutputs.get(nodeId);
  103. return map == null ? Map.of() : Collections.unmodifiableMap(map);
  104. }
  105. /**
  106. * 获取全部节点命名空间输出(只读)。
  107. */
  108. public Map<String, Map<String, Object>> getAllNodeScopedOutputs() {
  109. return Collections.unmodifiableMap(nodeScopedOutputs);
  110. }
  111. /**
  112. * 计算当前 variables 的全量快照(深拷贝),用于 debug 视图。
  113. */
  114. public Map<String, Object> snapshotVariables() {
  115. return new LinkedHashMap<>(variables);
  116. }
  117. }