Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fd054eb

Browse files
authored
feat(examples): add HITL chat example with MCP tools and tool confirmation (agentscope-ai#440)
1 parent 0b2c643 commit fd054eb

20 files changed

Lines changed: 2722 additions & 27 deletions

File tree

agentscope-core/src/main/java/io/agentscope/core/ReActAgent.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,16 @@ private Mono<Msg> reasoning(int iter, boolean ignoreMaxIters) {
342342
}
343343
})
344344
.then(Mono.defer(() -> Mono.justOrEmpty(context.buildFinalMessage())))
345+
.onErrorResume(
346+
InterruptedException.class,
347+
error -> {
348+
// Save accumulated message before propagating interrupt
349+
Msg msg = context.buildFinalMessage();
350+
if (msg != null) {
351+
memory.addMessage(msg);
352+
}
353+
return Mono.error(error);
354+
})
345355
.flatMap(this::notifyPostReasoning)
346356
.flatMap(
347357
event -> {

agentscope-core/src/main/java/io/agentscope/core/formatter/dashscope/DashScopeResponseParser.java

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,9 @@
2929
import io.agentscope.core.message.ToolUseBlock;
3030
import io.agentscope.core.model.ChatResponse;
3131
import io.agentscope.core.model.ChatUsage;
32-
import io.agentscope.core.util.JsonUtils;
3332
import java.time.Duration;
3433
import java.time.Instant;
3534
import java.util.ArrayList;
36-
import java.util.HashMap;
3735
import java.util.List;
3836
import java.util.Map;
3937
import org.slf4j.Logger;
@@ -145,24 +143,6 @@ protected void addToolCallsFromMessage(DashScopeMessage message, List<ContentBlo
145143
String name = function.getName();
146144
String argsJson = function.getArguments();
147145

148-
Map<String, Object> argsMap = new HashMap<>();
149-
String rawContent = null;
150-
151-
if (argsJson != null && !argsJson.isEmpty()) {
152-
rawContent = argsJson;
153-
try {
154-
@SuppressWarnings("unchecked")
155-
Map<String, Object> parsed =
156-
JsonUtils.getJsonCodec().fromJson(argsJson, Map.class);
157-
if (parsed != null) {
158-
argsMap.putAll(parsed);
159-
}
160-
} catch (Exception ignored) {
161-
// Keep raw content for later aggregation when JSON parsing fails
162-
// This handles streaming tool calls where arguments are fragmented
163-
}
164-
}
165-
166146
// For DashScope streaming tool calls:
167147
// - First chunk: has name, id, and partial arguments
168148
// - Subsequent chunks: only have argument fragments, no name/id
@@ -174,19 +154,19 @@ protected void addToolCallsFromMessage(DashScopeMessage message, List<ContentBlo
174154
ToolUseBlock.builder()
175155
.id(callId)
176156
.name(name)
177-
.input(argsMap)
178-
.content(rawContent)
157+
.input(Map.of())
158+
.content(argsJson)
179159
.build());
180-
} else if (rawContent != null) {
160+
} else if (argsJson != null) {
181161
// Subsequent chunks with only argument fragments
182162
String callId =
183163
id != null ? id : ("fragment_" + System.currentTimeMillis() + "_" + idx);
184164
blocks.add(
185165
ToolUseBlock.builder()
186166
.id(callId)
187167
.name(FRAGMENT_PLACEHOLDER)
188-
.input(argsMap)
189-
.content(rawContent)
168+
.input(Map.of())
169+
.content(argsJson)
190170
.build());
191171
}
192172
idx++;

agentscope-core/src/test/java/io/agentscope/core/formatter/dashscope/DashScopeResponseParserTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ void testParseResponseWithToolCalls() {
159159
ToolUseBlock toolUse = (ToolUseBlock) chatResponse.getContent().get(1);
160160
assertEquals("call_123", toolUse.getId());
161161
assertEquals("get_weather", toolUse.getName());
162-
assertEquals("Beijing", toolUse.getInput().get("location"));
162+
assertTrue(toolUse.getInput().isEmpty());
163163
}
164164

165165
@Test
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
<relativePath>../pom.xml</relativePath>
27+
</parent>
28+
29+
<groupId>io.agentscope.examples</groupId>
30+
<artifactId>hitl-chat</artifactId>
31+
<packaging>jar</packaging>
32+
33+
<name>AgentScope Java - Examples - HITL Chat</name>
34+
<description>Human-in-the-Loop chat example with MCP tools, interruption and tool confirmation</description>
35+
36+
<properties>
37+
<maven.compiler.source>17</maven.compiler.source>
38+
<maven.compiler.target>17</maven.compiler.target>
39+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
40+
<maven.deploy.skip>true</maven.deploy.skip>
41+
</properties>
42+
43+
<dependencyManagement>
44+
<dependencies>
45+
<!-- Spring Boot BOM -->
46+
<dependency>
47+
<groupId>org.springframework.boot</groupId>
48+
<artifactId>spring-boot-dependencies</artifactId>
49+
<version>${spring.boot.version}</version>
50+
<type>pom</type>
51+
<scope>import</scope>
52+
</dependency>
53+
</dependencies>
54+
</dependencyManagement>
55+
56+
<dependencies>
57+
<dependency>
58+
<groupId>io.agentscope</groupId>
59+
<artifactId>agentscope-core</artifactId>
60+
</dependency>
61+
62+
<dependency>
63+
<groupId>org.springframework.boot</groupId>
64+
<artifactId>spring-boot-starter-webflux</artifactId>
65+
</dependency>
66+
67+
</dependencies>
68+
69+
<build>
70+
<plugins>
71+
<plugin>
72+
<groupId>org.springframework.boot</groupId>
73+
<artifactId>spring-boot-maven-plugin</artifactId>
74+
<version>${spring.boot.version}</version>
75+
<executions>
76+
<execution>
77+
<goals>
78+
<goal>repackage</goal>
79+
</goals>
80+
</execution>
81+
</executions>
82+
</plugin>
83+
</plugins>
84+
</build>
85+
86+
</project>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
package io.agentscope.examples.hitlchat;
17+
18+
import org.springframework.boot.SpringApplication;
19+
import org.springframework.boot.autoconfigure.SpringBootApplication;
20+
21+
/**
22+
* HITL Chat Application - Human-in-the-Loop chat example.
23+
*
24+
* <p>This application demonstrates:
25+
* <ul>
26+
* <li>Dynamic MCP tool configuration</li>
27+
* <li>Agent interruption during conversation</li>
28+
* <li>Dangerous tool confirmation before execution</li>
29+
* <li>Built-in tools (time, file, random number)</li>
30+
* </ul>
31+
*
32+
* <p><b>Usage:</b>
33+
* <ol>
34+
* <li>Set the DASHSCOPE_API_KEY environment variable</li>
35+
* <li>Run this application</li>
36+
* <li>Open http://localhost:8080 in a browser</li>
37+
* </ol>
38+
*/
39+
@SpringBootApplication
40+
public class HitlChatApplication {
41+
42+
public static void main(String[] args) {
43+
SpringApplication.run(HitlChatApplication.class, args);
44+
printStartupInfo();
45+
}
46+
47+
private static void printStartupInfo() {
48+
System.out.println("\n=== HITL Chat Application Started ===");
49+
System.out.println("Open: http://localhost:8080");
50+
System.out.println("\nFeatures:");
51+
System.out.println(" - Dynamic MCP tool configuration");
52+
System.out.println(" - Agent interruption support");
53+
System.out.println(" - Dangerous tool confirmation");
54+
System.out.println(" - Built-in tools: get_time, list_files, random_number");
55+
System.out.println("\nPress Ctrl+C to stop.");
56+
}
57+
}

0 commit comments

Comments
 (0)