mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 11:13:43 +08:00
Full-stack AI assistant built on Spring AI Alibaba. Features: ReAct Agent, Plan-and-Execute, MCP Protocol, Multi-Model, Multi-Channel. Apache-2.0 License
149 lines
5.6 KiB
Java
149 lines
5.6 KiB
Java
package vip.mate.agent;
|
||
|
||
import com.alibaba.cloud.ai.graph.NodeOutput;
|
||
import vip.mate.agent.graph.state.MateClawStateKeys;
|
||
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* Graph 事件发布工具
|
||
* <p>
|
||
* 所有方法都是 static,不做状态管理。
|
||
* 节点内部收集 List<GraphEvent>,最终写入 PENDING_EVENTS。
|
||
* StateGraph*Agent 从 NodeOutput 中读取这些事件。
|
||
*
|
||
* @author MateClaw Team
|
||
*/
|
||
public final class GraphEventPublisher {
|
||
|
||
private GraphEventPublisher() {}
|
||
|
||
// ===== 事件类型常量 =====
|
||
public static final String EVENT_PHASE = "phase";
|
||
public static final String EVENT_TOOL_START = "tool_call_started";
|
||
public static final String EVENT_TOOL_COMPLETE = "tool_call_completed";
|
||
public static final String EVENT_PLAN_CREATED = "plan_created";
|
||
public static final String EVENT_STEP_STARTED = "plan_step_started";
|
||
public static final String EVENT_STEP_COMPLETED = "plan_step_completed";
|
||
public static final String EVENT_TOOL_APPROVAL_REQUESTED = "tool_approval_requested";
|
||
|
||
/**
|
||
* 事件记录
|
||
*/
|
||
public record GraphEvent(String type, Map<String, Object> data, long timestamp) {}
|
||
|
||
// ===== 静态工厂方法 =====
|
||
|
||
public static GraphEvent phase(String phase, Map<String, Object> extra) {
|
||
long ts = System.currentTimeMillis();
|
||
Map<String, Object> data = new java.util.HashMap<>(extra);
|
||
data.put("phase", phase);
|
||
data.put("timestamp", ts);
|
||
return new GraphEvent(EVENT_PHASE, Map.copyOf(data), ts);
|
||
}
|
||
|
||
public static GraphEvent toolStart(String toolName, String arguments) {
|
||
long ts = System.currentTimeMillis();
|
||
return new GraphEvent(EVENT_TOOL_START, Map.of(
|
||
"toolName", toolName,
|
||
"arguments", arguments != null ? arguments : "",
|
||
"timestamp", ts
|
||
), ts);
|
||
}
|
||
|
||
public static GraphEvent toolComplete(String toolName, String result, boolean success) {
|
||
long ts = System.currentTimeMillis();
|
||
return new GraphEvent(EVENT_TOOL_COMPLETE, Map.of(
|
||
"toolName", toolName,
|
||
"result", result != null ? truncateResult(result) : "",
|
||
"success", success,
|
||
"timestamp", ts
|
||
), ts);
|
||
}
|
||
|
||
public static GraphEvent planCreated(Long planId, List<String> steps) {
|
||
long ts = System.currentTimeMillis();
|
||
return new GraphEvent(EVENT_PLAN_CREATED, Map.of(
|
||
"planId", planId,
|
||
"steps", steps,
|
||
"timestamp", ts
|
||
), ts);
|
||
}
|
||
|
||
public static GraphEvent stepStarted(int index, String title) {
|
||
long ts = System.currentTimeMillis();
|
||
return new GraphEvent(EVENT_STEP_STARTED, Map.of(
|
||
"index", index,
|
||
"title", title != null ? title : "",
|
||
"timestamp", ts
|
||
), ts);
|
||
}
|
||
|
||
public static GraphEvent stepCompleted(int index, String result) {
|
||
long ts = System.currentTimeMillis();
|
||
return new GraphEvent(EVENT_STEP_COMPLETED, Map.of(
|
||
"index", index,
|
||
"result", result != null ? truncateResult(result) : "",
|
||
"timestamp", ts
|
||
), ts);
|
||
}
|
||
|
||
public static GraphEvent toolApprovalRequested(String pendingId, String toolName,
|
||
String arguments, String reason) {
|
||
long ts = System.currentTimeMillis();
|
||
return new GraphEvent(EVENT_TOOL_APPROVAL_REQUESTED, Map.of(
|
||
"pendingId", pendingId,
|
||
"toolName", toolName != null ? toolName : "",
|
||
"arguments", arguments != null ? truncateResult(arguments) : "",
|
||
"reason", reason != null ? reason : "",
|
||
"timestamp", ts
|
||
), ts);
|
||
}
|
||
|
||
/**
|
||
* 增强版审批事件(包含 findings、severity、summary)
|
||
*/
|
||
public static GraphEvent toolApprovalRequested(String pendingId, String toolName,
|
||
String arguments, String reason,
|
||
String summary, String maxSeverity,
|
||
List<Map<String, Object>> findings) {
|
||
long ts = System.currentTimeMillis();
|
||
java.util.Map<String, Object> data = new java.util.LinkedHashMap<>();
|
||
data.put("pendingId", pendingId);
|
||
data.put("toolName", toolName != null ? toolName : "");
|
||
data.put("arguments", arguments != null ? truncateForBroadcast(arguments) : "");
|
||
data.put("reason", reason != null ? reason : "");
|
||
data.put("summary", summary);
|
||
data.put("maxSeverity", maxSeverity);
|
||
data.put("findings", findings != null ? findings : List.of());
|
||
data.put("timestamp", ts);
|
||
return new GraphEvent(EVENT_TOOL_APPROVAL_REQUESTED, Map.copyOf(data), ts);
|
||
}
|
||
|
||
// ===== 提取方法 =====
|
||
|
||
/**
|
||
* 从 NodeOutput 中提取 PENDING_EVENTS
|
||
*/
|
||
@SuppressWarnings("unchecked")
|
||
public static List<GraphEvent> extractEvents(NodeOutput output) {
|
||
if (output == null || output.state() == null) {
|
||
return List.of();
|
||
}
|
||
return output.state().<List<GraphEvent>>value(MateClawStateKeys.PENDING_EVENTS)
|
||
.orElse(List.of());
|
||
}
|
||
|
||
private static String truncateResult(String result) {
|
||
return result.length() > 500 ? result.substring(0, 500) + "..." : result;
|
||
}
|
||
|
||
/**
|
||
* 截断字符串用于直推广播(公共方法,供 Node 直接构造广播数据时使用)
|
||
*/
|
||
public static String truncateForBroadcast(String text) {
|
||
return truncateResult(text);
|
||
}
|
||
}
|