Skip to content

feat(adk): support returning directly based on tool result - #1237

Open
wqdqwqdqwdqwq wants to merge 2 commits into
cloudwego:alpha/10from
wqdqwqdqwdqwq:feat/adk-runtime-return-directly
Open

feat(adk): support returning directly based on tool result#1237
wqdqwqdqwdqwq wants to merge 2 commits into
cloudwego:alpha/10from
wqdqwqdqwdqwq:feat/adk-runtime-return-directly

Conversation

@wqdqwqdqwdqwq

Copy link
Copy Markdown

What

Add SetReturnDirectly, letting a tool decide from its own execution result whether the agent should stop and return that result.

func SetReturnDirectly(ctx context.Context) error

Enabled by a new ToolsConfig field:

AllowRuntimeReturnDirectly bool

Closes #1187.

Why

Until now a tool could only influence the ReAct loop statically, by being listed in ToolsConfig.ReturnDirectly. That cannot express "return directly for some arguments, keep the loop running for others" — a retriever whose recall is good enough this time, a query tool that hit a cache.

The old flow/agent/react package already exposes exactly this as react.SetReturnDirectly, so ADK was the one losing capability. Its doc comment even states the intended priority: "This setting has a higher priority than the AgentConfig.ToolReturnDirectly."

There is also a gap that makes the naive version of this feature silently fail: the direct-return branch was only compiled when len(ReturnDirectly) > 0, so an agent with no static configuration has no path to reach the end node, and a runtime request could never take effect.

How

  • The direct-return branch is now compiled when either a tool is statically listed in ReturnDirectly or AllowRuntimeReturnDirectly is set. Agents using neither keep their previous topology, so they pay nothing for this feature — no extra branch, no extra state read per tool iteration.
  • Priority: runtime > ToolsConfig.ReturnDirectly / ChatModelAgentContext.ReturnDirectly. With parallel tool calls, the last request in an iteration wins.
  • When the agent has no direct-return path at all, SetReturnDirectly returns an error rather than silently continuing the loop.
  • Both the *schema.Message and *schema.AgenticMessage graphs are covered; a tool cannot know which it runs under, so both concrete states are attempted.
  • The returnDirectlyAllowed state flag is deliberately unexported so gob skips it and the checkpoint wire format is unchanged. It is therefore lost across a resume, and is refreshed from live config on every tool iteration.

Test plan

  • go test -race ./adk/... -count=1
  • golangci-lint run ./adk/... (v2.8.0, as pinned in CI) — 0 issues
  • Checkpoint interrupt/resume cases still pass, including TestChatModelParallelToolInterruptAndResume and TestReturnDirectlyEventSentAfterResume
  • New cases: runtime-only enablement; runtime decision overriding the configured tool; the not-allowed guard; StreamableRun tool; AgenticMessage path; topology predicate

What(中文)

新增 SetReturnDirectly,让 tool 根据自己的执行结果决定是否终止循环并把该结果作为最终输出,由新的 ToolsConfig.AllowRuntimeReturnDirectly 开启。

Why(中文)

原先只能通过 ToolsConfig.ReturnDirectly 静态指定,无法表达“这次参数下直接返回、其他情况继续循环”。老的 flow/agent/react 包本来就有 react.SetReturnDirectly,ADK 反而缺失。

另外 direct-return 分支此前仅在 len(ReturnDirectly) > 0 时编入图,未做静态配置的 agent 根本没有通往结束节点的路径,运行时请求会静默失效。

How(中文)

  • 静态配置与新开关任一满足时才编入分支;两者都未设置的 agent 拓扑保持不变,不引入额外开销。
  • 优先级:运行时 > 静态配置;并行调用时同一轮内最后一次请求生效。
  • agent 完全没有 direct-return 路径时返回错误,而不是静默继续循环。
  • returnDirectlyAllowed 特意使用非导出字段,gob 会跳过它,checkpoint 线上格式零变化;因此 resume 后会丢失,改为每轮从配置刷新。

Add SetReturnDirectly, which lets a tool decide from its own execution
result whether to stop the ReAct loop and return that result as the
agent's final output. This is the runtime counterpart of the static
ToolsConfig.ReturnDirectly.

Previously the direct-return graph branch was only compiled when at least
one tool was statically listed in ReturnDirectly, so a runtime decision
could never take effect for an agent with no static configuration. The
branch is now also compiled when the new ToolsConfig.AllowRuntimeReturnDirectly
is set, which keeps agents using neither mechanism on their original
topology.

SetReturnDirectly reports an error when the agent has no direct-return
path at all, instead of silently continuing the loop.
…tions

The adk package plain errors with no package prefix; the three new errors
carried an 'adk:' prefix unique in the package. Rework them to match, move
the sentinel error next to ErrExceedMaxIterations, and use closure capture
instead of a sentinel error through ProcessState for control flow.
@CLAassistant

CLAassistant commented Sep 2, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants