mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-11-02 22:16:58 +08:00
fix(agent): migrate deprecated AgentScope hooks to middleware (#675)
This commit is contained in:
parent
e46f176697
commit
952f73ddfa
@ -12,9 +12,6 @@ import io.agentscope.core.agent.Agent;
|
|||||||
import io.agentscope.core.agent.RuntimeContext;
|
import io.agentscope.core.agent.RuntimeContext;
|
||||||
import io.agentscope.core.event.AgentEvent;
|
import io.agentscope.core.event.AgentEvent;
|
||||||
import io.agentscope.core.event.RequestStopEvent;
|
import io.agentscope.core.event.RequestStopEvent;
|
||||||
import io.agentscope.core.hook.Hook;
|
|
||||||
import io.agentscope.core.hook.HookEvent;
|
|
||||||
import io.agentscope.core.hook.PostReasoningEvent;
|
|
||||||
import io.agentscope.core.message.ContentBlock;
|
import io.agentscope.core.message.ContentBlock;
|
||||||
import io.agentscope.core.message.GenerateReason;
|
import io.agentscope.core.message.GenerateReason;
|
||||||
import io.agentscope.core.message.Msg;
|
import io.agentscope.core.message.Msg;
|
||||||
@ -22,7 +19,7 @@ import io.agentscope.core.message.TextBlock;
|
|||||||
import io.agentscope.core.message.ToolUseBlock;
|
import io.agentscope.core.message.ToolUseBlock;
|
||||||
import io.agentscope.core.middleware.AgentInput;
|
import io.agentscope.core.middleware.AgentInput;
|
||||||
import io.agentscope.core.middleware.MiddlewareBase;
|
import io.agentscope.core.middleware.MiddlewareBase;
|
||||||
import io.agentscope.core.middleware.ModelCallInput;
|
import io.agentscope.core.middleware.ReasoningInput;
|
||||||
import io.agentscope.core.model.ChatResponse;
|
import io.agentscope.core.model.ChatResponse;
|
||||||
import io.agentscope.core.model.GenerateOptions;
|
import io.agentscope.core.model.GenerateOptions;
|
||||||
import io.agentscope.core.model.Model;
|
import io.agentscope.core.model.Model;
|
||||||
@ -186,7 +183,6 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
.name("native-policy-driver")
|
.name("native-policy-driver")
|
||||||
.model(session.model())
|
.model(session.model())
|
||||||
.toolkit(toolkit)
|
.toolkit(toolkit)
|
||||||
.hook(session)
|
|
||||||
.middleware(toolkit.boundaryMiddleware())
|
.middleware(toolkit.boundaryMiddleware())
|
||||||
.middleware(session.middleware())
|
.middleware(session.middleware())
|
||||||
.maxIters(hardRoundCeiling + 1)
|
.maxIters(hardRoundCeiling + 1)
|
||||||
@ -208,7 +204,7 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class Session implements Hook {
|
private final class Session {
|
||||||
private final RunState state;
|
private final RunState state;
|
||||||
private final Sinks.Many<RunStep> steps = Sinks.many().unicast().onBackpressureBuffer();
|
private final Sinks.Many<RunStep> steps = Sinks.many().unicast().onBackpressureBuffer();
|
||||||
private final AtomicBoolean cancelled = new AtomicBoolean();
|
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||||
@ -288,18 +284,10 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
return Mono.fromCallable(
|
return Mono.fromCallable(
|
||||||
() -> {
|
() -> {
|
||||||
ensureRunning();
|
ensureRunning();
|
||||||
if (terminal || rounds >= hardRoundCeiling)
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Unexpected SDK model call beyond application"
|
|
||||||
+ " boundary");
|
|
||||||
rounds++;
|
|
||||||
state.applyPatch(Map.of(TOOL_CALLS, List.of()));
|
|
||||||
node(REASONING_NODE, policies.reasoning());
|
|
||||||
reasoningRoute = edge(policies.afterReasoning());
|
|
||||||
List<ContentBlock> blocks = new ArrayList<>();
|
List<ContentBlock> blocks = new ArrayList<>();
|
||||||
scratchArguments.clear();
|
scratchArguments.clear();
|
||||||
for (AssistantMessage.ToolCall call :
|
for (AssistantMessage.ToolCall call :
|
||||||
ACTION_NODE.equals(reasoningRoute)
|
!terminal && ACTION_NODE.equals(reasoningRoute)
|
||||||
? calls()
|
? calls()
|
||||||
: List.<AssistantMessage.ToolCall>of()) {
|
: List.<AssistantMessage.ToolCall>of()) {
|
||||||
if (call.id() == null
|
if (call.id() == null
|
||||||
@ -352,8 +340,8 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
.reduce((first, last) -> last)
|
.reduce((first, last) -> last)
|
||||||
.map(AssistantMessage::getText)
|
.map(AssistantMessage::getText)
|
||||||
.orElse("");
|
.orElse("");
|
||||||
// SDK drops fully empty responses before its
|
// Keep a visible SDK scratch response even when
|
||||||
// post-reasoning routing hook.
|
// the application policy produced no visible text.
|
||||||
// This marker exists only in discarded SDK scratch
|
// This marker exists only in discarded SDK scratch
|
||||||
// history, never application history.
|
// history, never application history.
|
||||||
blocks.add(
|
blocks.add(
|
||||||
@ -367,7 +355,9 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
return ChatResponse.builder()
|
return ChatResponse.builder()
|
||||||
.content(blocks)
|
.content(blocks)
|
||||||
.finishReason(
|
.finishReason(
|
||||||
calls().isEmpty() ? "stop" : "tool_calls")
|
terminal || calls().isEmpty()
|
||||||
|
? "stop"
|
||||||
|
: "tool_calls")
|
||||||
.build();
|
.build();
|
||||||
})
|
})
|
||||||
.subscribeOn(Schedulers.boundedElastic())
|
.subscribeOn(Schedulers.boundedElastic())
|
||||||
@ -480,52 +470,51 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public <T extends HookEvent> Mono<T> onEvent(T event) {
|
* Prepare one application policy round before entering the SDK reasoning core. Middleware
|
||||||
if (!(event instanceof PostReasoningEvent post)) return Mono.just(event);
|
* repeats policy-only routes without fabricating tool calls. Actual tool batches still return
|
||||||
return Mono.fromCallable(
|
* to the SDK's native reasoning/acting iteration.
|
||||||
() -> {
|
*/
|
||||||
ensureRunning();
|
private boolean prepareReasoning() throws Exception {
|
||||||
String route =
|
ensureRunning();
|
||||||
Objects.requireNonNull(
|
if (terminal) return false;
|
||||||
reasoningRoute,
|
if (rounds >= hardRoundCeiling) {
|
||||||
"Reasoning route must be captured once");
|
ceiling();
|
||||||
if (ACTION_NODE.equals(route)) {
|
return false;
|
||||||
if (calls().isEmpty())
|
}
|
||||||
throw new IllegalStateException(
|
rounds++;
|
||||||
"Action route requires real tool calls");
|
state.applyPatch(Map.of(TOOL_CALLS, List.of()));
|
||||||
return event;
|
node(REASONING_NODE, policies.reasoning());
|
||||||
}
|
reasoningRoute =
|
||||||
switch (route) {
|
Objects.requireNonNull(
|
||||||
case REASONING_NODE -> {
|
edge(policies.afterReasoning()),
|
||||||
if (rounds >= hardRoundCeiling) {
|
"Reasoning route must be captured once");
|
||||||
ceiling();
|
switch (reasoningRoute) {
|
||||||
post.stopAgent();
|
case ACTION_NODE -> {
|
||||||
} else post.gotoReasoning();
|
if (calls().isEmpty())
|
||||||
}
|
throw new IllegalStateException("Action route requires real tool calls");
|
||||||
case SUMMARIZING_NODE -> {
|
return false;
|
||||||
node(SUMMARIZING_NODE, policies.summarizing());
|
}
|
||||||
if (rounds >= hardRoundCeiling) {
|
case REASONING_NODE -> {
|
||||||
ceiling();
|
if (rounds >= hardRoundCeiling) ceiling();
|
||||||
post.stopAgent();
|
return !terminal;
|
||||||
} else post.gotoReasoning();
|
}
|
||||||
}
|
case SUMMARIZING_NODE -> {
|
||||||
case LIMIT_EXCEEDED_NODE -> {
|
node(SUMMARIZING_NODE, policies.summarizing());
|
||||||
node(LIMIT_EXCEEDED_NODE, policies.limitExceeded());
|
if (rounds >= hardRoundCeiling) ceiling();
|
||||||
if (finish(true)) post.gotoReasoning();
|
return !terminal;
|
||||||
else post.stopAgent();
|
}
|
||||||
}
|
case LIMIT_EXCEEDED_NODE -> {
|
||||||
case FINAL_ANSWER_NODE -> {
|
node(LIMIT_EXCEEDED_NODE, policies.limitExceeded());
|
||||||
if (finish(true)) post.gotoReasoning();
|
return finish(true);
|
||||||
else post.stopAgent();
|
}
|
||||||
}
|
case FINAL_ANSWER_NODE -> {
|
||||||
default ->
|
return finish(true);
|
||||||
throw new IllegalArgumentException(
|
}
|
||||||
"Unsupported reasoning route: " + route);
|
default ->
|
||||||
}
|
throw new IllegalArgumentException(
|
||||||
return event;
|
"Unsupported reasoning route: " + reasoningRoute);
|
||||||
})
|
}
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MiddlewareBase middleware() {
|
private MiddlewareBase middleware() {
|
||||||
@ -540,17 +529,25 @@ public final class NativePolicyDriver implements AgentRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<AgentEvent> onModelCall(
|
public Flux<AgentEvent> onReasoning(
|
||||||
Agent agent,
|
Agent agent,
|
||||||
RuntimeContext context,
|
RuntimeContext context,
|
||||||
ModelCallInput input,
|
ReasoningInput input,
|
||||||
Function<ModelCallInput, Flux<AgentEvent>> next) {
|
Function<ReasoningInput, Flux<AgentEvent>> next) {
|
||||||
if (terminal || rounds >= hardRoundCeiling)
|
return Mono.fromCallable(Session.this::prepareReasoning)
|
||||||
return Flux.just(
|
.subscribeOn(Schedulers.boundedElastic())
|
||||||
new RequestStopEvent(
|
.repeat(() -> !terminal && !ACTION_NODE.equals(reasoningRoute))
|
||||||
"application_terminal",
|
.thenMany(Flux.defer(() -> next.apply(input)))
|
||||||
GenerateReason.MIDDLEWARE_STOP_REQUESTED));
|
.concatWith(
|
||||||
return next.apply(input);
|
Flux.defer(
|
||||||
|
() ->
|
||||||
|
terminal
|
||||||
|
? Flux.just(
|
||||||
|
new RequestStopEvent(
|
||||||
|
"application_terminal",
|
||||||
|
GenerateReason
|
||||||
|
.MIDDLEWARE_STOP_REQUESTED))
|
||||||
|
: Flux.empty()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,22 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
class NativePolicyDriverTest {
|
class NativePolicyDriverTest {
|
||||||
|
@Test
|
||||||
|
void nativeRuntimeDoesNotLinkToForRemovalHookApi() throws Exception {
|
||||||
|
var types = new java.util.ArrayDeque<Class<?>>();
|
||||||
|
types.add(NativePolicyDriver.class);
|
||||||
|
while (!types.isEmpty()) {
|
||||||
|
Class<?> type = types.removeFirst();
|
||||||
|
types.addAll(List.of(type.getDeclaredClasses()));
|
||||||
|
try (var bytes = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class")) {
|
||||||
|
assertNotNull(bytes);
|
||||||
|
String constants = new String(bytes.readAllBytes(), java.nio.charset.StandardCharsets.ISO_8859_1);
|
||||||
|
assertFalse(constants.contains("io/agentscope/core/hook/"),
|
||||||
|
type.getName() + " must use supported middleware rather than for-removal hooks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final List<ToolSchema> SCHEMAS =
|
private static final List<ToolSchema> SCHEMAS =
|
||||||
List.of(
|
List.of(
|
||||||
ToolSchema.builder()
|
ToolSchema.builder()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user