Skip to content

Commit 42fe9f8

Browse files
luohq-bytedancemeguminnnnnnnnnhi-pendershentongmartin
authored
feat(adk): adk implementation (#262)
* feat: adk implementation Change-Id: I2d9dcbb15735c348f666e41959e6bbaeb7038821 * fix: Runner run with new runctx Change-Id: If0ae01e3a7d396d2c3080b359eff656a3ed43d0f * feat: agent as tool (#293) * feat: the input will not be passed when calling subagent because the … (#305) feat: the input will not be passed when calling subagent because the subagent will retrieve the input from the run ctx * feat: add Agent CallOption for adk (#312) * feat: prebuilt/supervisor (#329) Change-Id: Ia5c7a4562fb609f932c8b91c0b8d6eb79b5e948d * fix: disallow to parrent for sub agents (#336) * St/adk1 (#339) * feat: include max steps in adk.ChatModelConfig * fix: AgentEvent * revert(adk): check tool_call until stream end (#346) * fix: only set automatic close on events added to session and emitted … (#343) fix: only set automatic close on events added to session and emitted by flow agent Change-Id: I48c12915b0f2ee5606262bbf0857eb1a571faf10 * Feat/wdz/adk interrupt (#311) feat: support adk interrupt * fix(adk): reserve stream event (#378) * feat(adk): optimize pass event (#379) * fix(adk): use uuid as mock transfer tool call id (#388) * feat: adk -- implement plan_execute_replan (#386) Change-Id: Icf07c6b7408e2c0eb7568874b77d14b5a07a0a35 * feat: support skip transfer messages (#399) * feat(adk): history entry support user input (#404) * fix: resume chatmodel agent panic (#414) * fix: encode agent event wrapper & input message in history rewrite (#416) * fix: history rewrite user input correctly (#419) * fix: gob will discord tool call index(*int), so concat message stream… (#422) fix: gob will discord tool call index(*int), so concat message stream before encoding * fix: plan_execute: improve plan instruction (#427) Change-Id: I2f7dd579e1ac82c329a487997768af8f5a763678 * refactor: change run path from string to RunStep (#423) * feat(adk): support WithSessionValues agent run option (#428) * feat: enable history rewriter in root agent & report run ctx nil in resume (#430) * fix(adk_deterministic_transfer): support deterministic transfer interrupt&resume (#433) * feat(adk): add GenInputFn for planner/executor/replanner (#420) * Feat/workflow inherit (#439) * feat: sequential inherits previous agent * refactor: add sub directory for prebuilt agent and add comments (#443) * feat: use MaxIterations instead of MaxSteps for ChatModelAgent (#447) --------- Co-authored-by: Megumin <[email protected]> Co-authored-by: IPender <[email protected]> Co-authored-by: shentongmartin <[email protected]>
1 parent 106ff40 commit 42fe9f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+8995
-71
lines changed

_typos.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ invokable = "invokable"
77
InvokableLambda = "InvokableLambda"
88
InvokableRun = "InvokableRun"
99
typ = "typ"
10+
byted = "byted"
1011

1112
[files]
1213
extend-exclude = ["go.mod", "go.sum", "check_branch_name.sh"]

adk/agent_tool.go

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/*
2+
* Copyright 2025 CloudWeGo 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 adk
18+
19+
import (
20+
"context"
21+
"errors"
22+
"fmt"
23+
24+
"github.com/bytedance/sonic"
25+
26+
"github.com/cloudwego/eino/components/tool"
27+
"github.com/cloudwego/eino/compose"
28+
"github.com/cloudwego/eino/schema"
29+
)
30+
31+
var (
32+
defaultAgentToolParam = schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{
33+
"request": {
34+
Desc: "request to be processed",
35+
Required: true,
36+
Type: schema.String,
37+
},
38+
})
39+
)
40+
41+
type agentToolOptions struct {
42+
agentName string
43+
opts []AgentRunOption
44+
}
45+
46+
func withAgentToolOptions(agentName string, opts []AgentRunOption) tool.Option {
47+
return tool.WrapImplSpecificOptFn(func(opt *agentToolOptions) {
48+
opt.agentName = agentName
49+
opt.opts = opts
50+
})
51+
}
52+
53+
func getOptionsByAgentName(agentName string, opts []tool.Option) []AgentRunOption {
54+
var ret []AgentRunOption
55+
for _, opt := range opts {
56+
o := tool.GetImplSpecificOptions[agentToolOptions](nil, opt)
57+
if o != nil && o.agentName == agentName {
58+
ret = append(ret, o.opts...)
59+
}
60+
}
61+
return ret
62+
}
63+
64+
type agentTool struct {
65+
agent Agent
66+
67+
fullChatHistoryAsInput bool
68+
}
69+
70+
func (at *agentTool) Info(ctx context.Context) (*schema.ToolInfo, error) {
71+
var param *schema.ParamsOneOf
72+
if !at.fullChatHistoryAsInput {
73+
param = defaultAgentToolParam
74+
}
75+
76+
return &schema.ToolInfo{
77+
Name: at.agent.Name(ctx),
78+
Desc: at.agent.Description(ctx),
79+
ParamsOneOf: param,
80+
}, nil
81+
}
82+
83+
func (at *agentTool) InvokableRun(ctx context.Context, argumentsInJSON string, opts ...tool.Option) (string, error) {
84+
var intData *agentToolInterruptInfo
85+
var bResume bool
86+
err := compose.ProcessState(ctx, func(ctx context.Context, s *State) error {
87+
toolCallID := compose.GetToolCallID(ctx)
88+
intData, bResume = s.AgentToolInterruptData[toolCallID]
89+
if bResume {
90+
delete(s.AgentToolInterruptData, toolCallID)
91+
}
92+
return nil
93+
})
94+
if err != nil {
95+
// cannot resume
96+
bResume = false
97+
}
98+
99+
var ms *mockStore
100+
var iter *AsyncIterator[*AgentEvent]
101+
if bResume {
102+
ms = newResumeStore(intData.Data)
103+
104+
iter, err = newInvokableAgentToolRunner(at.agent, ms).Resume(ctx, mockCheckPointID, getOptionsByAgentName(at.agent.Name(ctx), opts)...)
105+
if err != nil {
106+
return "", err
107+
}
108+
} else {
109+
ms = newEmptyStore()
110+
var input []Message
111+
if at.fullChatHistoryAsInput {
112+
history, err := getReactChatHistory(ctx, at.agent.Name(ctx))
113+
if err != nil {
114+
return "", err
115+
}
116+
117+
input = history
118+
} else {
119+
type request struct {
120+
Request string `json:"request"`
121+
}
122+
123+
req := &request{}
124+
err := sonic.UnmarshalString(argumentsInJSON, req)
125+
if err != nil {
126+
return "", err
127+
}
128+
input = []Message{
129+
schema.UserMessage(req.Request),
130+
}
131+
}
132+
133+
iter = newInvokableAgentToolRunner(at.agent, ms).Run(ctx, input, append(getOptionsByAgentName(at.agent.Name(ctx), opts), WithCheckPointID(mockCheckPointID))...)
134+
}
135+
136+
var lastEvent *AgentEvent
137+
for {
138+
event, ok := iter.Next()
139+
if !ok {
140+
break
141+
}
142+
143+
if event.Err != nil {
144+
return "", event.Err
145+
}
146+
147+
lastEvent = event
148+
}
149+
150+
if lastEvent != nil && lastEvent.Action != nil && lastEvent.Action.Interrupted != nil {
151+
data, existed, err_ := ms.Get(ctx, mockCheckPointID)
152+
if err_ != nil {
153+
return "", fmt.Errorf("failed to get interrupt info: %w", err_)
154+
}
155+
if !existed {
156+
return "", fmt.Errorf("interrupt has happened, but cannot find interrupt info")
157+
}
158+
err = compose.ProcessState(ctx, func(ctx context.Context, st *State) error {
159+
st.AgentToolInterruptData[compose.GetToolCallID(ctx)] = &agentToolInterruptInfo{
160+
LastEvent: lastEvent,
161+
Data: data,
162+
}
163+
return nil
164+
})
165+
if err != nil {
166+
return "", fmt.Errorf("failed to save agent tool checkpoint to state: %w", err)
167+
}
168+
return "", compose.InterruptAndRerun
169+
}
170+
171+
if lastEvent == nil {
172+
return "", errors.New("no event returned")
173+
}
174+
175+
var ret string
176+
if lastEvent.Output != nil {
177+
if output := lastEvent.Output.MessageOutput; output != nil {
178+
if !output.IsStreaming {
179+
ret = output.Message.Content
180+
} else {
181+
msg, err := schema.ConcatMessageStream(output.MessageStream)
182+
if err != nil {
183+
return "", err
184+
}
185+
ret = msg.Content
186+
}
187+
}
188+
}
189+
190+
return ret, nil
191+
}
192+
193+
type AgentToolOptions struct {
194+
fullChatHistoryAsInput bool
195+
}
196+
197+
type AgentToolOption func(*AgentToolOptions)
198+
199+
func WithFullChatHistoryAsInput() AgentToolOption {
200+
return func(options *AgentToolOptions) {
201+
options.fullChatHistoryAsInput = true
202+
}
203+
}
204+
205+
func getReactChatHistory(ctx context.Context, destAgentName string) ([]Message, error) {
206+
var messages []Message
207+
var agentName string
208+
err := compose.ProcessState(ctx, func(ctx context.Context, st *State) error {
209+
messages = st.Messages
210+
agentName = st.AgentName
211+
return nil
212+
})
213+
214+
messages = messages[:len(messages)-1] // remove the last assistant message, which is the tool call message
215+
history := make([]Message, 0, len(messages))
216+
history = append(history, messages...)
217+
a, t := GenTransferMessages(ctx, destAgentName)
218+
history = append(history, a, t)
219+
for _, msg := range messages {
220+
if msg.Role == schema.System {
221+
continue
222+
}
223+
224+
if msg.Role == schema.Assistant || msg.Role == schema.Tool {
225+
msg = rewriteMessage(msg, agentName)
226+
}
227+
228+
history = append(history, msg)
229+
}
230+
231+
return history, err
232+
}
233+
234+
func NewAgentTool(_ context.Context, agent Agent, options ...AgentToolOption) tool.BaseTool {
235+
opts := &AgentToolOptions{}
236+
for _, opt := range options {
237+
opt(opts)
238+
}
239+
240+
return &agentTool{agent: agent, fullChatHistoryAsInput: opts.fullChatHistoryAsInput}
241+
}
242+
243+
func newInvokableAgentToolRunner(agent Agent, store compose.CheckPointStore) *Runner {
244+
return &Runner{
245+
a: agent,
246+
enableStreaming: false,
247+
store: store,
248+
}
249+
}

0 commit comments

Comments
 (0)