Skip to content

Commit 9dad26c

Browse files
feat: support workflow agents (#85)
* feat: support workflow agents * chore: openai version (#84) * fix: fix deploy bug and add license to toml (#83) * add callbacks to sub agents
1 parent acdb9de commit 9dad26c

6 files changed

Lines changed: 230 additions & 6 deletions

File tree

veadk/agent.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ class Agent(LlmAgent):
6060
instruction: str = DEFAULT_INSTRUCTION
6161
"""The instruction for the agent, such as principles of function calling."""
6262

63-
# factory
6463
model_name: str = getenv("MODEL_AGENT_NAME", DEFAULT_MODEL_AGENT_NAME)
6564
"""The name of the model for agent running."""
6665

@@ -117,7 +116,7 @@ def model_post_init(self, __context: Any) -> None:
117116
for tracer in self.tracers:
118117
tracer.do_hooks(self)
119118

120-
logger.info(f"Agent `{self.name}` init done.")
119+
logger.info(f"{self.__class__.__name__} `{self.name}` init done.")
121120
logger.debug(
122121
f"Agent: {self.model_dump(include={'name', 'model_name', 'model_api_base', 'tools', 'serve_url'})}"
123122
)

veadk/agents/loop_agent.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
from google.adk.agents import LoopAgent as GoogleADKLoopAgent
18+
from google.adk.agents.base_agent import BaseAgent
19+
from pydantic import ConfigDict, Field
20+
from typing_extensions import Any
21+
22+
from veadk.agent import Agent
23+
from veadk.prompts.agent_default_prompt import DEFAULT_DESCRIPTION, DEFAULT_INSTRUCTION
24+
from veadk.tracing.base_tracer import BaseTracer
25+
from veadk.utils.logger import get_logger
26+
from veadk.utils.patches import patch_asyncio
27+
28+
patch_asyncio()
29+
logger = get_logger(__name__)
30+
31+
32+
class LoopAgent(GoogleADKLoopAgent):
33+
"""Loop Agent with Volcengine capabilities."""
34+
35+
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
36+
"""The model config"""
37+
38+
name: str = "veLoopAgent"
39+
"""The name of the agent."""
40+
41+
description: str = DEFAULT_DESCRIPTION
42+
"""The description of the agent. This will be helpful in A2A scenario."""
43+
44+
instruction: str = DEFAULT_INSTRUCTION
45+
"""The instruction for the agent, such as principles of function calling."""
46+
47+
sub_agents: list[BaseAgent] = Field(default_factory=list, exclude=True)
48+
"""The sub agents provided to agent."""
49+
50+
tracers: list[BaseTracer] = []
51+
"""The tracers provided to agent."""
52+
53+
def set_sub_agents_tracer(self, tracer) -> None:
54+
from veadk.agents.parallel_agent import ParallelAgent
55+
from veadk.agents.sequential_agent import SequentialAgent
56+
57+
for sub_agent in self.sub_agents:
58+
if isinstance(sub_agent, Agent):
59+
tracer.do_hooks(sub_agent)
60+
elif isinstance(sub_agent, (SequentialAgent, LoopAgent, ParallelAgent)):
61+
sub_agent.set_sub_agents_tracer(tracer)
62+
63+
def model_post_init(self, __context: Any) -> None:
64+
super().model_post_init(None) # for sub_agents init
65+
66+
if self.tracers:
67+
for tracer in self.tracers:
68+
self.set_sub_agents_tracer(tracer)
69+
70+
logger.info(f"{self.__class__.__name__} `{self.name}` init done.")

veadk/agents/parallel_agent.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
from google.adk.agents import ParallelAgent as GoogleADKParallelAgent
18+
from google.adk.agents.base_agent import BaseAgent
19+
from pydantic import ConfigDict, Field
20+
from typing_extensions import Any
21+
22+
from veadk.agent import Agent
23+
from veadk.prompts.agent_default_prompt import DEFAULT_DESCRIPTION, DEFAULT_INSTRUCTION
24+
from veadk.tracing.base_tracer import BaseTracer
25+
from veadk.utils.logger import get_logger
26+
from veadk.utils.patches import patch_asyncio
27+
28+
patch_asyncio()
29+
logger = get_logger(__name__)
30+
31+
32+
class ParallelAgent(GoogleADKParallelAgent):
33+
"""LLM-based Agent with Volcengine capabilities."""
34+
35+
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
36+
"""The model config"""
37+
38+
name: str = "veParallelAgent"
39+
"""The name of the agent."""
40+
41+
description: str = DEFAULT_DESCRIPTION
42+
"""The description of the agent. This will be helpful in A2A scenario."""
43+
44+
instruction: str = DEFAULT_INSTRUCTION
45+
"""The instruction for the agent, such as principles of function calling."""
46+
47+
sub_agents: list[BaseAgent] = Field(default_factory=list, exclude=True)
48+
"""The sub agents provided to agent."""
49+
50+
tracers: list[BaseTracer] = []
51+
"""The tracers provided to agent."""
52+
53+
def set_sub_agents_tracer(self, tracer) -> None:
54+
from veadk.agents.loop_agent import LoopAgent
55+
from veadk.agents.sequential_agent import SequentialAgent
56+
57+
for sub_agent in self.sub_agents:
58+
if isinstance(sub_agent, Agent):
59+
tracer.do_hooks(sub_agent)
60+
elif isinstance(sub_agent, (SequentialAgent, LoopAgent, ParallelAgent)):
61+
sub_agent.set_sub_agents_tracer(tracer)
62+
63+
def model_post_init(self, __context: Any) -> None:
64+
super().model_post_init(None) # for sub_agents init
65+
66+
if self.tracers:
67+
logger.warning(
68+
"Enable tracing in ParallelAgent may cause OpenTelemetry context error. Issue see https://github.com/google/adk-python/issues/1670"
69+
)
70+
for tracer in self.tracers:
71+
self.set_sub_agents_tracer(tracer)
72+
73+
logger.info(f"{self.__class__.__name__} `{self.name}` init done.")

veadk/agents/sequential_agent.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
from google.adk.agents import SequentialAgent as GoogleADKSequentialAgent
18+
from google.adk.agents.base_agent import BaseAgent
19+
from pydantic import ConfigDict, Field
20+
from typing_extensions import Any
21+
22+
from veadk.agent import Agent
23+
from veadk.prompts.agent_default_prompt import DEFAULT_DESCRIPTION, DEFAULT_INSTRUCTION
24+
from veadk.tracing.base_tracer import BaseTracer
25+
from veadk.utils.logger import get_logger
26+
from veadk.utils.patches import patch_asyncio
27+
28+
patch_asyncio()
29+
logger = get_logger(__name__)
30+
31+
32+
class SequentialAgent(GoogleADKSequentialAgent):
33+
"""Sequential Agent with Volcengine capabilities."""
34+
35+
model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
36+
"""The model config"""
37+
38+
name: str = "veSequentialAgent"
39+
"""The name of the agent."""
40+
41+
description: str = DEFAULT_DESCRIPTION
42+
"""The description of the agent. This will be helpful in A2A scenario."""
43+
44+
instruction: str = DEFAULT_INSTRUCTION
45+
"""The instruction for the agent, such as principles of function calling."""
46+
47+
sub_agents: list[BaseAgent] = Field(default_factory=list, exclude=True)
48+
"""The sub agents provided to agent."""
49+
50+
tracers: list[BaseTracer] = []
51+
"""The tracers provided to agent."""
52+
53+
def set_sub_agents_tracer(self, tracer) -> None:
54+
from veadk.agents.loop_agent import LoopAgent
55+
from veadk.agents.parallel_agent import ParallelAgent
56+
57+
for sub_agent in self.sub_agents:
58+
if isinstance(sub_agent, Agent):
59+
tracer.do_hooks(sub_agent)
60+
elif isinstance(sub_agent, (SequentialAgent, LoopAgent, ParallelAgent)):
61+
sub_agent.set_sub_agents_tracer(tracer)
62+
63+
def model_post_init(self, __context: Any) -> None:
64+
super().model_post_init(None) # for sub_agents init
65+
66+
if self.tracers:
67+
for tracer in self.tracers:
68+
self.set_sub_agents_tracer(tracer)
69+
70+
logger.info(f"{self.__class__.__name__} `{self.name}` init done.")

veadk/runner.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
from veadk.a2a.remote_ve_agent import RemoteVeAgent
2424
from veadk.agent import Agent
25+
from veadk.agents.loop_agent import LoopAgent
26+
from veadk.agents.parallel_agent import ParallelAgent
27+
from veadk.agents.sequential_agent import SequentialAgent
2528
from veadk.evaluation import EvalSetRecorder
2629
from veadk.memory.short_term_memory import ShortTermMemory
2730
from veadk.tracing.base_tracer import UserMessagePlugin
@@ -40,11 +43,13 @@
4043
list[MediaMessage | str], # multiple turn prompt with media and text-based prompt
4144
]
4245

46+
VeAgent = Union[Agent, RemoteVeAgent, SequentialAgent, ParallelAgent, LoopAgent]
47+
4348

4449
class Runner:
4550
def __init__(
4651
self,
47-
agent: Agent | RemoteVeAgent,
52+
agent: VeAgent,
4853
short_term_memory: ShortTermMemory,
4954
plugins: list[BasePlugin] = [],
5055
app_name: str = "veadk_default_app",
@@ -200,10 +205,12 @@ def _print_trace_id(self):
200205
return
201206

202207
def save_tracing_file(self, session_id: str) -> str:
203-
if not isinstance(self.agent, Agent):
208+
if not isinstance(
209+
self.agent, (Agent, SequentialAgent, ParallelAgent, LoopAgent)
210+
):
204211
logger.warning(
205212
(
206-
"The agent is not an instance of VeADK Agent, cannot save tracing file."
213+
"The agent is not an instance of Agent, SequentialAgent, ParallelAgent or LoopAgent, cannot save tracing file."
207214
)
208215
)
209216
return ""

veadk/types.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
from pydantic import BaseModel, Field
1616

1717
from veadk.agent import Agent
18+
from veadk.agents.loop_agent import LoopAgent
19+
from veadk.agents.parallel_agent import ParallelAgent
20+
from veadk.agents.sequential_agent import SequentialAgent
1821
from veadk.memory.short_term_memory import ShortTermMemory
1922

2023

@@ -35,7 +38,9 @@ class AgentRunConfig(BaseModel):
3538
default="veadk_vefaas_app", description="The name of the application"
3639
)
3740

38-
agent: Agent = Field(..., description="The root agent instance")
41+
agent: Agent | SequentialAgent | ParallelAgent | LoopAgent = Field(
42+
..., description="The root agent instance"
43+
)
3944

4045
short_term_memory: ShortTermMemory = Field(
4146
default_factory=ShortTermMemory, description="The short-term memory instance"

0 commit comments

Comments
 (0)