Skip to content

[Bug]:agentscope agent as tools模式下流式场景报错:Cannot add messages without tool results when pending tool calls exist. #918

@chestnut-Z

Description

@chestnut-Z

agent as tools模式
1、主agent注册子agent方式 子agent是实例的
@OverRide
protected Toolkit createToolkit() {
Toolkit tk = new Toolkit();

    // 注册所有子 Agent 到 Toolkit(排除自己,避免循环)
    // 使用 Supplier 每次创建新实例,避免并发状态问题
    for (Agent subAgent : subAgents) {
        // 跳过大脑 Agent 自己,只注册真正的子 Agent
        if (subAgent == this || StringUtil.equals(subAgent.getName(), getName())) {
            log.info("Skipping self-registration for CoordinatorAgent");
            continue;
        }
        
        String agentName = subAgent.getName();
        String agentDesc = subAgent.getDescription();
        
        // 为每个子 Agent 创建 Supplier,每次调用时创建新实例
        SubAgentProvider<ReActAgent> agentSupplier = createAgentSupplier(agentName);
        
        tk.registration()
                .subAgent(agentSupplier, SubAgentConfig.builder()
                        .toolName(agentName)
                        .description(agentDesc)
                        .forwardEvents(false)
                        .build())
                .apply();
        log.info("Registered sub-agent: {} (with new instance per call)", agentName);
    }
    
    return tk;
}

/**
 * 创建 Agent Supplier,每次调用时创建新的 Agent 实例
 * 参考 BrainAgent 的实现方式,避免并发状态问题
 */
private SubAgentProvider<ReActAgent> createAgentSupplier(String agentName) {
    return () -> {
        // 根据 Agent 名称创建对应的新实例
        AgentBase newAgent = switch (agentName) {
            case "ChitChat" -> new ChitChatAgent(chitchatModel);
            default -> throw new IllegalArgumentException("Unknown agent: " + agentName);
        };
        
        // 初始化并返回 ReActAgent
        return newAgent.getAgent();
    };
}

2、子agent实例注册工具和skill
/**
* 确保初始化(延迟初始化模式)
* 支持:1. Spring 注入后初始化 2. AgentScope 框架创建新实例时初始化
*/
protected void ensureInitialized() {
if (!initialized) {
synchronized (this) {
if (!initialized) {
this.toolkit = createToolkit();
this.skillBox = createSkillBox(toolkit);
this.hooks = getHooks();
this.agent = buildAgent();
initialized = true;

                log.info("Agent [{}] initialized with skillBox: {}", getName(),
                        skillBox != null ? skillBox.getAllSkillIds() : "none");
            }
        }
    }
}

3、子agentskill:
/**
* 创建并配置 SkillBox,流程:
* 1. 从 classpath 批量加载 skill
* 2. 逐个委托子类绑定 tools
* 3. 注册 skill-load tool
*
* @param toolkit 共享的 Toolkit 实例
* @return 配置好的 SkillBox
*/
public SkillBox createSkillBox(Toolkit toolkit) {
SkillBox skillBox = new SkillBox(toolkit);
this.toolkit = toolkit; // 保存引用

    log.info("[{}] Starting to load skills from path: {}", configName(), getSkillsResourcePath());

    try {
        // 使用 PathMatchingResourcePatternResolver 加载所有 .md 文件
        List<AgentSkill> skills = loadSkillsFromClasspath();
        log.info("[{}] Found {} skills in classpath", configName(), skills.size());
        
        for (AgentSkill skill : skills) {
            log.info("[{}] Loaded skill: {} - {}", configName(), skill.getName(), skill.getDescription());
            bindTools(skillBox, skill);
        }
        
        if (skills.isEmpty()) {
            log.warn("[{}] No skills found, using fallback registration", configName());
            fallbackRegister(skillBox);
        }
    } catch (Exception e) {
        log.error("[{}] Failed to load skills from classpath: {}", configName(), e.getMessage(), e);
        fallbackRegister(skillBox);
    }

    
    int skillCount = skillBox.getAllSkillIds().size();
    log.info("[{}] SkillBox configured with {} skills: {}", configName(), skillCount, skillBox.getAllSkillIds());
    
    if (skillCount == 0) {
        log.error("[{}] WARNING: No skills loaded! Check if skill files exist in classpath: {}", 
                configName(), getSkillsResourcePath());
    }
    
    return skillBox;
}

4\skill绑定工具:
protected void register(SkillBox skillBox, AgentSkill skill, Object toolsBean) {
log.info("[{}] Registering skill: {} - {}", configName(), skill.getName(), toolsBean.getClass().getSimpleName());
skillBox.registration()
.skill(skill)
.tool(toolsBean)
.apply();
}

5、主agent调用子agent成功 决策需要调用子agent 但是子agent在进行工具选择时报错
2026-03-11 02:32:52,706 [ - /// - ] ERROR subagent.SubAgentTool - Error in streaming execution: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]
java.lang.IllegalStateException: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]
at io.agentscope.core.ReActAgent.validateAndAddToolResults(ReActAgent.java:335)
at io.agentscope.core.ReActAgent.doCall(ReActAgent.java:256)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2570)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2366)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117)
at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:193)
at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:63)
at reactor.core.publisher.MonoUsing.subscribe(MonoUsing.java:109)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.Mono.subscribeWith(Mono.java:4641)
at reactor.core.publisher.Mono.subscribe(Mono.java:4542)
at reactor.core.publisher.Mono.subscribe(Mono.java:4478)
at reactor.core.publisher.Mono.subscribe(Mono.java:4450)
at io.agentscope.core.agent.AgentBase.lambda$createEventStream$26(AgentBase.java:707)
at reactor.core.publisher.FluxCreate.subscribe(FluxCreate.java:97)
at reactor.core.publisher.FluxPublishOn.subscribeOrReturn(FluxPublishOn.java:92)
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:55)
at reactor.core.publisher.FluxDeferContextual.subscribe(FluxDeferContextual.java:57)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
2026-03-11 02:32:52,706 [ - /// - ] INFO hook.AgentMonitorHook - [MONITOR] [Coordinator] tool output: [Error: Execution error: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69c82f3264a09a89c9d05]]
2026-03-11 02:32:52,706 [ - /// - ] INFO hook.AgentMonitorHook - [MONITOR] [Coordinator] tool result: TechnicalSupport -> Error: Execution error: Cannot add messages without tool results when pending tool calls exist. Pending IDs: [call_b7b69...

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Status

    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions