Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions agentscope-dependencies-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,7 @@
<opentelemetry-reactor.version>2.27.0-alpha</opentelemetry-reactor.version>
<opentelemetry-semconv-incubating.version>1.41.0-alpha</opentelemetry-semconv-incubating.version>
<redisson.version>4.2.0</redisson.version>
<a2a-client.version>0.3.3.Final</a2a-client.version>
<a2a-server-common.version>0.3.3.Final</a2a-server-common.version>
<a2a-transport-jsonrpc.version>0.3.3.Final</a2a-transport-jsonrpc.version>
<a2a-java-sdk.version>1.4.0.Final</a2a-java-sdk.version>
<jedis.version>7.4.1</jedis.version>
<lettuce.version>6.4.2.RELEASE</lettuce.version>
<mongodb-driver.version>5.3.1</mongodb-driver.version>
Expand All @@ -117,7 +115,7 @@
<kotlin.coroutines.version>1.10.2</kotlin.coroutines.version>
<jgit.version>7.6.0.202603022253-r</jgit.version>
<fabric8.kubernetes-client.version>7.8.0</fabric8.kubernetes-client.version>
<protobuf.java.version>4.29.3</protobuf.java.version>
<protobuf.java.version>4.35.0</protobuf.java.version>

<spotless.version>3.4.0</spotless.version>
<maven-gpg-plugin.version>3.2.8</maven-gpg-plugin.version>
Expand Down Expand Up @@ -381,14 +379,14 @@

<!-- A2A dependencies -->
<dependency>
<groupId>io.github.a2asdk</groupId>
<groupId>org.a2aproject.sdk</groupId>
<artifactId>a2a-java-sdk-client</artifactId>
<version>${a2a-client.version}</version>
<version>${a2a-java-sdk.version}</version>
</dependency>
<dependency>
<groupId>io.github.a2asdk</groupId>
<groupId>org.a2aproject.sdk</groupId>
<artifactId>a2a-java-sdk-server-common</artifactId>
<version>${a2a-server-common.version}</version>
<version>${a2a-java-sdk.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.microprofile.config</groupId>
Expand All @@ -397,9 +395,9 @@
</exclusions>
</dependency>
<dependency>
<groupId>io.github.a2asdk</groupId>
<groupId>org.a2aproject.sdk</groupId>
<artifactId>a2a-java-sdk-transport-jsonrpc</artifactId>
<version>${a2a-transport-jsonrpc.version}</version>
<version>${a2a-java-sdk.version}</version>
</dependency>

<!-- Jedis client for Redis-based session implementation -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,36 +291,74 @@ void failureBudgetStopsOnlyObservationAndWorkerRunsToCompletion() {
}

@Test
void eventBurstsAreCoalescedAndRequestsNeverOverlapOrExceedLimit() {
void eventBurstsAreCoalescedAndRequestsNeverOverlapOrExceedLimit() throws Exception {
AtomicInteger active = new AtomicInteger(),
maxActive = new AtomicInteger(),
calls = new AtomicInteger();
var observations = new CopyOnWriteArrayList<JevSupervisionMiddleware.Observation>();
var firstResponse = Sinks.<Boolean>one();
var secondResponse = Sinks.<Boolean>one();
CountDownLatch firstRequested = new CountDownLatch(1),
secondRequested = new CountDownLatch(1),
limitReported = new CountDownLatch(1);
Function<SystemOneRequest, Mono<SystemOneResult>> caller =
r ->
Mono.defer(
() -> {
int call = calls.incrementAndGet();
maxActive.accumulateAndGet(active.incrementAndGet(), Math::max);
var response = call == 1 ? firstResponse : secondResponse;
(call == 1 ? firstRequested : secondRequested).countDown();
return response.asMono()
.then(JevSupervisionExample.syntheticAnswers(r))
.doOnNext(ignored -> active.decrementAndGet());
});
var m =
middleware(
r ->
Mono.defer(
() -> {
calls.incrementAndGet();
maxActive.accumulateAndGet(
active.incrementAndGet(), Math::max);
return JevSupervisionExample.syntheticAnswers(r)
.delayElement(Duration.ofMillis(25))
.doOnNext(ignored -> active.decrementAndGet());
}),
observations,
2,
3);
var worker =
Flux.interval(Duration.ofMillis(1))
.take(160)
.map(i -> (AgentEvent) new TextBlockDeltaEvent("r", "b", "x"));
assertEquals(160, invoke(m, context("s"), worker).count().block());
assertEquals(2, calls.get());
assertEquals(1, maxActive.get());
assertTrue(
observations.stream()
.anyMatch(o -> o.decision().reason().equals("ASSESSMENT_LIMIT")));
new JevSupervisionMiddleware(
new JevTaskSupervisor(
caller,
new JevTaskSupervisor.Thresholds(.2, .8),
JevTaskSupervisor.Limits.defaults(),
// Response gates, rather than a request timeout, control this test.
new JevExecution.Options(
JevExecution.Mode.SHADOW,
Duration.ofDays(1),
"gated-test",
(c, r) -> {})),
new JevSupervisionMiddleware.Schedule(
Duration.ofMillis(10), Duration.ofMillis(30), 2, 3),
(ctx, o) -> {
observations.add(o);
if (o.decision().reason().equals("ASSESSMENT_LIMIT")) {
limitReported.countDown();
}
});
var worker = Sinks.many().unicast().<AgentEvent>onBackpressureBuffer();
var completion = invoke(m, context("s"), worker.asFlux()).count().toFuture();
try {
assertTrue(firstRequested.await(5, TimeUnit.SECONDS));
for (int i = 0; i < 160; i++) {
assertEquals(
Sinks.EmitResult.OK,
worker.tryEmitNext(new TextBlockDeltaEvent("r", "b", "x")));
}
assertEquals(1, calls.get());
firstResponse.tryEmitValue(true);
assertTrue(secondRequested.await(5, TimeUnit.SECONDS));
secondResponse.tryEmitValue(true);
// Keep the worker active until the limit is observed: a terminal assessment is
// allowed to consume the last slot without producing an ASSESSMENT_LIMIT notice.
assertTrue(limitReported.await(5, TimeUnit.SECONDS));
assertEquals(Sinks.EmitResult.OK, worker.tryEmitComplete());
assertEquals(160, completion.get(5, TimeUnit.SECONDS));
assertEquals(2, calls.get());
assertEquals(1, maxActive.get());
assertTrue(
observations.stream()
.anyMatch(o -> o.decision().reason().equals("ASSESSMENT_LIMIT")));
} finally {
completion.cancel(true);
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<grpc.version>1.75.0</grpc.version>
<!-- Kept in sync with agentscope-dependencies-bom; an imported BOM's properties are not
inherited, so protoc needs its own declaration to match the protobuf-java runtime. -->
<protoc.version>4.29.3</protoc.version>
<protoc.version>4.35.0</protoc.version>
<!-- Canonical ASDP contract, shared with the Go control plane and the Python SDK. -->
<asdp.proto.dir>${project.basedir}/../../agentscope-service/service-controlplane/internal/asdp</asdp.proto.dir>
<os-maven-plugin.version>1.7.1</os-maven-plugin.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
import com.alibaba.nacos.api.ai.model.a2a.AgentCardDetailInfo;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import io.a2a.spec.AgentCard;
import io.agentscope.core.a2a.agent.A2aAgent;
import io.agentscope.core.a2a.agent.card.AgentCardResolver;
import io.agentscope.core.nacos.a2a.utils.AgentCardConverterUtil;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import org.a2aproject.sdk.spec.AgentCard;

/**
* Agent Card Producer from Nacos A2A Registry.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
import com.alibaba.nacos.api.ai.model.a2a.AgentEndpoint;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import io.a2a.spec.AgentCard;
import io.agentscope.core.nacos.a2a.utils.AgentCardConverterUtil;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import org.a2aproject.sdk.spec.AgentCard;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import com.alibaba.nacos.api.ai.constant.AiConstants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import io.a2a.spec.AgentCard;
import io.a2a.spec.AgentInterface;
import io.agentscope.core.a2a.agent.utils.LoggerUtil;
import io.agentscope.core.a2a.server.registry.AgentRegistry;
import io.agentscope.core.a2a.server.transport.TransportProperties;
Expand All @@ -33,6 +31,8 @@
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.a2aproject.sdk.spec.AgentCard;
import org.a2aproject.sdk.spec.AgentInterface;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -176,7 +176,7 @@ private AgentCard tryOverwritePreferredTransport(
LoggerUtil.info(
log,
"Try to overwrite preferred transport from {} to {}",
agentCard.preferredTransport(),
preferredInterface(agentCard).protocolBinding(),
preferredTransport);
if (properties.transportProperties().containsKey(preferredTransport)) {
return doOverwrite(agentCard, properties.transportProperties().get(preferredTransport));
Expand All @@ -186,26 +186,35 @@ private AgentCard tryOverwritePreferredTransport(
"Preferred transport {} is not found, will use original preferred transport {} with"
+ " url {}",
preferredTransport,
agentCard.preferredTransport(),
agentCard.url());
preferredInterface(agentCard).protocolBinding(),
preferredInterface(agentCard).url());
return agentCard;
}

/** The first supported interface is the preferred one. */
private static AgentInterface preferredInterface(AgentCard agentCard) {
return agentCard.supportedInterfaces().isEmpty()
? new AgentInterface("", "")
: agentCard.supportedInterfaces().get(0);
}

private AgentCard doOverwrite(
AgentCard agentCard, NacosA2aRegistryTransportProperties transportProperties) {
String newUrl = generateNewUrl(transportProperties);
String transport = transportProperties.transport();
AgentInterface agentInterface = new AgentInterface(transport, newUrl);
List<AgentInterface> agentInterfaces = new LinkedList<>(agentCard.additionalInterfaces());
agentInterfaces.add(agentInterface);
AgentCard.Builder builder = new AgentCard.Builder(agentCard);
builder.url(newUrl).preferredTransport(transport).additionalInterfaces(agentInterfaces);
List<AgentInterface> agentInterfaces = new LinkedList<>(agentCard.supportedInterfaces());
// The first interface is the preferred one; it is listed once.
agentInterfaces.removeIf(agentInterface::equals);
agentInterfaces.add(0, agentInterface);
AgentCard.Builder builder = AgentCard.builder(agentCard);
builder.supportedInterfaces(agentInterfaces);
LoggerUtil.info(
log,
"Overwrite preferred transport from {} to {} with url from {} to {}",
agentCard.preferredTransport(),
preferredInterface(agentCard).protocolBinding(),
transport,
agentCard.url(),
preferredInterface(agentCard).url(),
newUrl);
return builder.build();
}
Expand Down
Loading
Loading