diff --git a/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentComponent.java b/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentComponent.java index 8c533d7c2..e64dd0d9b 100644 --- a/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentComponent.java +++ b/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentComponent.java @@ -1,29 +1,32 @@ package com.yomahub.liteflow.agent.component; import com.yomahub.liteflow.agent.exception.AgentConfigException; -import com.yomahub.liteflow.agent.exception.AgentInvocationException; import com.yomahub.liteflow.agent.model.ModelSpec; import com.yomahub.liteflow.core.NodeComponent; import com.yomahub.liteflow.property.LiteflowConfigGetter; import com.yomahub.liteflow.property.agent.AgentConfig; import com.yomahub.liteflow.slot.Slot; import com.yomahub.liteflow.util.ConversationIdGenerator; +import io.agentscope.core.ReActAgent; +import io.agentscope.core.agent.RuntimeContext; import io.agentscope.core.hook.Hook; import io.agentscope.core.message.Msg; +import io.agentscope.core.message.UserMessage; import io.agentscope.core.model.Model; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.Map; /** * 封装 agentscope agent 的 LiteFlow 抽象组件。 * - *

状态:v2 迁移进行中(Task 0 green-commit 基底)。 - * 本类已删除所有依赖 agentscope 1.0 已删类型(session 管理 / skill / 工具 / - * 流式事件桥接)的实现,{@link #process()} 当前抛出 - * {@link AgentInvocationException}。后续 Task 2.x 会基于 v2 - * {@code HarnessAgent} 重建 {@code process()}。受保护方法签名保持不变, - * 子类实现与业务侧代码无需改动。 + *

状态:v2(RC3)非流式实现。 + * {@link #process()} 通过 {@link ReactAgentFactory#getOrCreate} 取按组件类缓存的无状态 + * {@code ReActAgent} 单例,按 {@code (conversationId, agentKey)} 构造 + * {@code RuntimeContext(userId, sessionId)},调 {@code agent.call(List<Msg>, RuntimeContext).block()} + * 拿到回复后交给 {@link #handleReply(Msg)} 写回 slot。流式({@code streamEvents})留给 Task 6.1。 * *

子类必须提供 {@link #model()}、{@link #systemPrompt()} 和 {@link #userPrompt()}。 * 可选覆写方法用于自定义工具、钩子和生命周期回调;当前均为空实现或读 @@ -34,8 +37,10 @@ import java.util.Map; * *

会话标识被拆为两层: *

* *

{@link #process()} 方法被声明为 {@code final},由框架统一保证。 @@ -209,14 +214,72 @@ public abstract class ReActAgentComponent extends NodeComponent { /* ===== 框架 final 执行体 ===== */ /** - * v2 迁移期 stub。当前抛出 {@link AgentInvocationException}, - * 由 Task 2.x 基于 v2 {@code HarnessAgent} 重建。 + * 端到端非流式执行(RC3)。 + * + *

流程: + *

    + *
  1. 取全局 {@link #agentConfig()}(与 {@code buildModel()} 读取的是同一份配置, + * 保证 stateStore 与 model 配置一致——Task 2.2 review 的 cfg 一致性要求)。
  2. + *
  3. 用 {@link ReactAgentFactory#getOrCreate} 取按组件类缓存的无状态 + * {@link ReActAgent} 单例。
  4. + *
  5. 解析 {@code conversationId} / {@code agentKey},写回 slot,并构造对应的 + * {@link RuntimeContext}({@code userId=conversationId, sessionId=agentKey})。
  6. + *
  7. 把 {@link ReActAgentContext}(含 runtimeContext)挂到 slot attachment 上, + * 使 {@link #ctx()} 在 {@code agent.call(...)} 触发的工具回调内可用。
  8. + *
  9. 调 {@code agent.call(List.of(new UserMessage(userPrompt())), rc).block()} + * 阻塞拿回复,交 {@link #handleReply(Msg)} 处理。
  10. + *
  11. {@code finally} 中摘除 ctx,避免跨 invocation 悬挂引用。
  12. + *
+ * + *

非流式:本方法始终用 {@code call(...)}。流式({@code streamEvents})桥接 + * 由 Task 6.1 单独实现,不在本方法范围内。 * *

签名保持 {@code final},与 1.0 一致。 */ @Override public final void process() { - throw new AgentInvocationException( - "ReActAgentComponent v2 migration in progress; process() is rebuilt in Task 2.3"); + AgentConfig cfg = agentConfig(); + ReActAgent agent = ReactAgentFactory.getOrCreate(this, cfg); + + Slot slot = getSlot(); + String cid = resolveConversationId(); + slot.setConversationId(cid); + String akey = agentKey(); + RuntimeContext rc = runtimeContext(cid, akey); + + ReActAgentContext ctx = new ReActAgentContext(slot, cid, akey, workspaceRoot(cfg, cid)); + ctx.setRuntimeContext(rc); + slot.setAttachment(ctxKey(), ctx); + try { + Msg reply = agent.call(List.of(new UserMessage(userPrompt())), rc).block(); + handleReply(reply); + } finally { + slot.removeAttachment(ctxKey()); + } + } + + /** + * 构造本次调用的 {@link RuntimeContext}。标识映射(spec §4.1): + * {@code userId = conversationId}、{@code sessionId = agentKey}。 + * + *

声明为 {@code protected} 便于子类在需要时覆写(例如注入额外 typed extras)。 + */ + protected RuntimeContext runtimeContext(String conversationId, String agentKey) { + return RuntimeContext.builder().userId(conversationId).sessionId(agentKey).build(); + } + + /** + * 返回本次调用使用的 workspace 根目录(仅用于 {@link ReActAgentContext#getWorkspaceDir()} + * 暴露给业务/未来工具;RC3 核心 {@code ReActAgent} 无 {@code .workspace()}, + * 此值传给 agent builder)。 + * + *

RC3-core 暂用 cfg 配置的单根目录;workspace 用户分桶由后续 GA/HarnessAgent 处理。 + */ + protected Path workspaceRoot(AgentConfig cfg, String conversationId) { + String root = cfg.getWorkspace().getRoot(); + if (root == null || root.isBlank()) { + return Paths.get(System.getProperty("java.io.tmpdir"), "liteflow-agent-workspace"); + } + return Paths.get(root); } } diff --git a/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentContext.java b/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentContext.java index 09ad8a509..535e7f5af 100644 --- a/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentContext.java +++ b/liteflow-react-agent/liteflow-react-agent-core/src/main/java/com/yomahub/liteflow/agent/component/ReActAgentContext.java @@ -1,6 +1,7 @@ package com.yomahub.liteflow.agent.component; import com.yomahub.liteflow.slot.Slot; +import io.agentscope.core.agent.RuntimeContext; import io.agentscope.core.model.ChatUsage; import java.nio.file.Path; @@ -30,6 +31,7 @@ public class ReActAgentContext { private final String conversationId; private final String agentKey; private final Path workspaceDir; + private RuntimeContext runtimeContext; public ReActAgentContext(Slot slot, String conversationId, String agentKey, Path workspaceDir) { this.slot = Objects.requireNonNull(slot, "slot"); @@ -46,6 +48,22 @@ public class ReActAgentContext { public Path getWorkspaceDir() { return workspaceDir; } + /** + * 本次 {@code process()} 调用注入给底层 {@code ReActAgent.call(...)} 的 + * {@link RuntimeContext}。由 {@link ReActAgentComponent#process()} 在构造 ctx 后、 + * 调 {@code agent.call(...)} 前设置。 + * + *

标识映射:{@code runtimeContext.userId = conversationId}、 + * {@code runtimeContext.sessionId = agentKey}(spec §4.1)。 + * + * @return 本次调用使用的 {@link RuntimeContext};在 {@code process()} 生命周期外为 {@code null} + */ + public RuntimeContext getRuntimeContext() { return runtimeContext; } + + public void setRuntimeContext(RuntimeContext runtimeContext) { + this.runtimeContext = runtimeContext; + } + /** * 由框架注入:本次 {@code process()} 调用使用的 token 累加 hook。 * diff --git a/liteflow-testcase-el/liteflow-testcase-el-react-agent/src/test/java/com/yomahub/liteflow/test/agent/support/LiveTestSupport.java b/liteflow-testcase-el/liteflow-testcase-el-react-agent/src/test/java/com/yomahub/liteflow/test/agent/support/LiveTestSupport.java index 617af0d6b..a73afc5b5 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-react-agent/src/test/java/com/yomahub/liteflow/test/agent/support/LiveTestSupport.java +++ b/liteflow-testcase-el/liteflow-testcase-el-react-agent/src/test/java/com/yomahub/liteflow/test/agent/support/LiveTestSupport.java @@ -1,5 +1,6 @@ package com.yomahub.liteflow.test.agent.support; +import com.yomahub.liteflow.agent.component.ReactAgentFactory; import com.yomahub.liteflow.agent.model.ModelSpec; import com.yomahub.liteflow.agent.openai.OpenAICompatible; import com.yomahub.liteflow.property.LiteflowConfig; @@ -7,18 +8,17 @@ import com.yomahub.liteflow.property.agent.AgentConfig; import com.yomahub.liteflow.property.agent.PlatformCredential; import org.junit.jupiter.api.Assumptions; -import java.lang.reflect.Method; - /** * 整个模块唯一共享的「凭据/skip/重置」插管。 * - *

按用户约定:不同 package 之间只共享这一层(凭据解析、无 key 即 skip、SessionManager 重置); + *

按用户约定:不同 package 之间只共享这一层(凭据解析、无 key 即 skip、agent 运行时缓存重置); * 其余 agent 组件、辅助节点、探针、flow xml、application.properties 一律每个 package 各自冗余。 * *

提供: *