Skip to content

Commit f70e281

Browse files
authored
example(a2a,nacos): For #293, Add example for a2a and nacos a2a registry. (#458)
## AgentScope-Java Version 1.0.7 ## Description For #293 . - example(a2a): add A2A protocol example with tools and Spring Boot app. - chore(deps): Add Nacos extensions dependency into all-in-one and update documents. - example(a2a,nacos): Add Nacos A2A registry and discovery example in a2a example module. ## Checklist Please check the following items before code is ready to be reviewed. - [x] Code has been formatted with `mvn spotless:apply` - [x] All tests are passing (`mvn test`) - [x] Javadoc comments are complete and follow project conventions - [x] Related documentation has been updated (e.g. links, examples, etc.) - [x] Code is ready for review
1 parent c5b6e8a commit f70e281

17 files changed

Lines changed: 697 additions & 54 deletions

File tree

agentscope-distribution/agentscope-all/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
<scope>compile</scope>
5353
<optional>true</optional>
5454
</dependency>
55+
56+
<dependency>
57+
<groupId>io.agentscope</groupId>
58+
<artifactId>agentscope-extensions-a2a-server</artifactId>
59+
<scope>compile</scope>
60+
<optional>true</optional>
61+
</dependency>
5562

5663
<dependency>
5764
<groupId>io.agentscope</groupId>
@@ -157,6 +164,13 @@
157164
<scope>compile</scope>
158165
<optional>true</optional>
159166
</dependency>
167+
168+
<dependency>
169+
<groupId>io.agentscope</groupId>
170+
<artifactId>agentscope-extensions-nacos-a2a</artifactId>
171+
<scope>compile</scope>
172+
<optional>true</optional>
173+
</dependency>
160174

161175
<!-- Model Context Protocol (MCP) SDK -->
162176
<dependency>

agentscope-examples/a2a/pom.xml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2024-2026 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<project xmlns="http://maven.apache.org/POM/4.0.0"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21+
<modelVersion>4.0.0</modelVersion>
22+
<parent>
23+
<groupId>io.agentscope</groupId>
24+
<artifactId>agentscope-examples</artifactId>
25+
<version>${revision}</version>
26+
</parent>
27+
28+
<groupId>io.agentscope.examples</groupId>
29+
<artifactId>a2a</artifactId>
30+
<packaging>jar</packaging>
31+
32+
<name>AgentScope Examples - A2A</name>
33+
<description>A2A(Agent2Agent) Protocol example for AgentScope Java SDK</description>
34+
35+
<dependencyManagement>
36+
<dependencies>
37+
<!-- Spring Boot BOM -->
38+
<dependency>
39+
<groupId>org.springframework.boot</groupId>
40+
<artifactId>spring-boot-dependencies</artifactId>
41+
<version>${spring.boot.version}</version>
42+
<type>pom</type>
43+
<scope>import</scope>
44+
</dependency>
45+
</dependencies>
46+
</dependencyManagement>
47+
48+
<dependencies>
49+
<dependency>
50+
<groupId>io.agentscope</groupId>
51+
<artifactId>agentscope-core</artifactId>
52+
</dependency>
53+
<dependency>
54+
<groupId>io.agentscope</groupId>
55+
<artifactId>agentscope-a2a-spring-boot-starter</artifactId>
56+
</dependency>
57+
<dependency>
58+
<groupId>io.agentscope</groupId>
59+
<artifactId>agentscope-nacos-spring-boot-starter</artifactId>
60+
</dependency>
61+
<dependency>
62+
<groupId>org.springframework.boot</groupId>
63+
<artifactId>spring-boot-starter-web</artifactId>
64+
</dependency>
65+
</dependencies>
66+
67+
</project>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2024-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.agentscope.examples.a2a;
18+
19+
import io.agentscope.core.a2a.agent.A2aAgent;
20+
import io.agentscope.core.message.Msg;
21+
import io.agentscope.core.message.MsgRole;
22+
import io.agentscope.core.message.TextBlock;
23+
import java.io.BufferedReader;
24+
import java.io.IOException;
25+
import java.io.InputStreamReader;
26+
import reactor.core.publisher.Flux;
27+
28+
/**
29+
* Example runner for A2aAgent usage.
30+
*
31+
* <p>This example demonstrates how to request remote agent via the A2A protocol
32+
* using AgentScope A2aAgent.
33+
*/
34+
public class A2aAgentExampleRunner {
35+
36+
private static final String USER_INPUT_PREFIX = "\u001B[34mYou>\u001B[0m ";
37+
38+
private static final String AGENT_RESPONSE_PREFIX = "\u001B[32mAgent>\u001B[0m ";
39+
40+
private final A2aAgent agent;
41+
42+
public A2aAgentExampleRunner(A2aAgent agent) {
43+
this.agent = agent;
44+
}
45+
46+
/**
47+
* Start to run the example for A2aAgent.
48+
*/
49+
public void startExample() {
50+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
51+
while (true) {
52+
// User Input Hint.
53+
System.out.print(USER_INPUT_PREFIX);
54+
String input = reader.readLine();
55+
56+
// Exit example.
57+
if (input == null
58+
|| input.trim().equalsIgnoreCase("exit")
59+
|| input.trim().equalsIgnoreCase("quit")) {
60+
System.out.println(AGENT_RESPONSE_PREFIX + "Bye!");
61+
break;
62+
}
63+
64+
System.out.println(
65+
AGENT_RESPONSE_PREFIX + "I have received your question: " + input);
66+
System.out.print(AGENT_RESPONSE_PREFIX);
67+
68+
// Handle user input and get response.
69+
processInput(agent, input).doOnNext(System.out::print).then().block();
70+
71+
System.out.println();
72+
}
73+
} catch (IOException e) {
74+
System.err.println("input error: " + e.getMessage());
75+
}
76+
}
77+
78+
private Flux<String> processInput(A2aAgent agent, String input) {
79+
Msg msg =
80+
Msg.builder()
81+
.role(MsgRole.USER)
82+
.content(TextBlock.builder().text(input).build())
83+
.build();
84+
return agent.stream(msg)
85+
.map(
86+
event -> {
87+
if (event.isLast()) {
88+
// The last message is whole artifact message result, which has been
89+
// processed and printed in the previous event handling.
90+
return "";
91+
}
92+
Msg message = event.getMessage();
93+
StringBuilder partText = new StringBuilder();
94+
message.getContent().stream()
95+
.filter(block -> block instanceof TextBlock)
96+
.map(block -> (TextBlock) block)
97+
.forEach(block -> partText.append(block.getText()));
98+
return partText.toString();
99+
});
100+
}
101+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2024-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.agentscope.examples.a2a;
18+
19+
import io.agentscope.core.tool.Toolkit;
20+
import io.agentscope.examples.a2a.tools.ExampleTools;
21+
import org.springframework.boot.SpringApplication;
22+
import org.springframework.boot.autoconfigure.SpringBootApplication;
23+
import org.springframework.context.annotation.Bean;
24+
25+
/**
26+
* A2A(Agent2Agent) Protocol Example Application.
27+
*
28+
* <p>This application demonstrates how to expose AgentScope agents via the A2A protocol
29+
* using Spring Web.
30+
*
31+
* <p><b>Usage:</b>
32+
* <ol>
33+
* <li>Set the DASHSCOPE_API_KEY environment variable</li>
34+
* <li>Run this application</li>
35+
* <li>Use curl: {@code curl -X GET http://localhost:8888/.well-known/agent-card.json} to get AgentCard.</li>
36+
* <li>Use curl: {@code curl --location --request POST 'http://localhost:8888' \
37+
* --header 'Content-Type: application/json' \
38+
* --data-raw '{
39+
* "method": "message/stream",
40+
* "id": "2d2b4dc8-8ea2-437b-888d-3aaf3a8239dc",
41+
* "jsonrpc": "2.0",
42+
* "params": {
43+
* "message": {
44+
* "role": "user",
45+
* "kind": "message",
46+
* "contextId": "aa9c67d2-c6fc-42d4-9c9e-b67d69f77cfa",
47+
* "metadata": {
48+
* "userId": "me",
49+
* "sessionId": "test12"
50+
* },
51+
* "parts": [
52+
* {
53+
* "kind": "text",
54+
* "text": "Hello, please calculate the 346 * 47"
55+
* }
56+
* ],
57+
* "messageId": "c4911b64c8404b7a8bf7200dd225b152"
58+
* }
59+
* }
60+
* }'}</li>
61+
* <li>Or run {@link SimpleA2aAgentExample#main(String[])} and input question like: {@code Hello, please calculate the 346 * 47}</li>
62+
* </ol>
63+
*
64+
* <p>This example application also demonstrates how to register agents to Nacos A2A registry.
65+
*
66+
* <p><b>Usage: </b>
67+
* <ol>
68+
* <li>Set the DASHSCOPE_API_KEY environment variable.</li>
69+
* <li>Enabled Nacos Registry by set Nacos environment variable: {@code NACOS_ENABLED=true}.</li>
70+
* <li>Start Nacos Server according to <a href="https://nacos.io/en/docs/latest/quickstart/quick-start-docker">documents</a>.</li>
71+
* <li>Set more Nacos environment variables: NACOS_SERVER_ADDR, NACOS_USERNAME and NACOS_PASSWORD if Nacos Server is not in local and enabled authentication.</li>
72+
* <li>Run this application</li>
73+
* <li>Run Example {@link NacosA2aAgentExample#main(String[])} and input question like: {@code Hello, please calculate the 346 * 47}</li>
74+
* </ol>
75+
*/
76+
@SpringBootApplication
77+
public class A2aExampleApplication {
78+
79+
public static void main(String[] args) {
80+
SpringApplication.run(A2aExampleApplication.class, args);
81+
}
82+
83+
/**
84+
* Optional, if you want to register tools for the agent.
85+
*/
86+
@Bean
87+
public Toolkit toolkit() {
88+
Toolkit toolkit = new Toolkit();
89+
toolkit.registerTool(new ExampleTools());
90+
return toolkit;
91+
}
92+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2024-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.agentscope.examples.a2a;
18+
19+
import com.alibaba.nacos.api.PropertyKeyConst;
20+
import com.alibaba.nacos.api.ai.AiFactory;
21+
import com.alibaba.nacos.api.ai.AiService;
22+
import com.alibaba.nacos.api.exception.NacosException;
23+
import io.agentscope.core.a2a.agent.A2aAgent;
24+
import io.agentscope.core.a2a.agent.card.AgentCardResolver;
25+
import io.agentscope.core.nacos.a2a.discovery.NacosAgentCardResolver;
26+
import java.util.Properties;
27+
28+
/**
29+
* Example for A2aAgent with Nacos Registry.
30+
*
31+
* <p>This example demonstrates how to request remote agent via the A2A protocol
32+
* using AgentScope A2aAgent which discovers AgentCard by Nacos Registry.
33+
*
34+
* <p>If your Nacos Server is not deployed locally, you should set environment variable NACOS_SERVER_ADDR.
35+
*
36+
* <p>If your Nacos Server has authentication enabled, you should set environment variable NACOS_USERNAME and NACOS_PASSWORD.
37+
*/
38+
public class NacosA2aAgentExample {
39+
40+
public static void main(String[] args) throws NacosException {
41+
// Create agent card resolver by Nacos.
42+
AgentCardResolver agentCardResolver = new NacosAgentCardResolver(buildNacosClient());
43+
// Create A2aAgent
44+
A2aAgent agent =
45+
A2aAgent.builder()
46+
.name("agentscope-a2a-example-agent")
47+
.agentCardResolver(agentCardResolver)
48+
.build();
49+
A2aAgentExampleRunner exampleRunner = new A2aAgentExampleRunner(agent);
50+
exampleRunner.startExample();
51+
}
52+
53+
private static AiService buildNacosClient() throws NacosException {
54+
String nacosServerAddr = System.getenv("NACOS_SERVER_ADDR");
55+
if (nacosServerAddr == null) {
56+
nacosServerAddr = "localhost:8848";
57+
}
58+
String nacosUsername = System.getenv("NACOS_USERNAME");
59+
String nacosPassword = System.getenv("NACOS_PASSWORD");
60+
Properties properties = new Properties();
61+
properties.put(PropertyKeyConst.SERVER_ADDR, nacosServerAddr);
62+
if (nacosUsername != null && nacosPassword != null) {
63+
properties.put(PropertyKeyConst.USERNAME, nacosUsername);
64+
properties.put(PropertyKeyConst.PASSWORD, nacosPassword);
65+
}
66+
return AiFactory.createAiService(properties);
67+
}
68+
}

0 commit comments

Comments
 (0)