Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions tests/cli/test_generated_agent_backend_codegen_extended.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ def test_retired_a2ui_option_is_accepted_but_not_generated() -> None:
assert "[a2ui]" not in files["requirements.txt"]


@pytest.mark.parametrize("agent_type", ["llm", "sequential", "parallel", "loop"])
def test_codegen_studio_tools_follow_root_type(agent_type: str) -> None:
draft = AgentDraft.model_validate(
{
"name": "workflow",
"agentType": agent_type,
"subAgents": [{"name": "worker", "agentType": "llm"}],
}
)
files = _file_map(generate_project_from_draft(draft))
expected = agent_type == "llm"
assert f'"enable_studio_tools": {expected!r}' in files["app.py"]


def test_codegen_preserves_agent_display_names_for_topology() -> None:
project = generate_project_from_draft(
AgentDraft(
Expand Down
42 changes: 42 additions & 0 deletions tests/integrations/agentkit/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
from fastapi import FastAPI
from fastapi.testclient import TestClient
from google.adk.agents import Agent as AdkAgent
from google.adk.agents import LoopAgent, ParallelAgent, SequentialAgent
from google.adk.agents.base_agent import BaseAgent
from google.adk.apps.app import App
from google.adk.plugins.base_plugin import BasePlugin

import veadk
Expand Down Expand Up @@ -245,6 +247,46 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
assert bool(studio_toolsets) is enabled


@pytest.mark.parametrize("workflow_type", [SequentialAgent, ParallelAgent, LoopAgent])
@pytest.mark.parametrize("use_app", [False, True])
@pytest.mark.parametrize("enabled", [False, True])
def test_workflow_roots_disable_studio_tools(
monkeypatch: pytest.MonkeyPatch,
workflow_type: type[BaseAgent],
use_app: bool,
enabled: bool,
) -> None:
class SessionAgentServer(_FakeAgentServer):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.session_service = object()

monkeypatch.setattr(agentkit_app, "AgentkitAgentServerApp", SessionAgentServer)

def existing_tool() -> str:
return "ok"

child = AdkAgent(name="worker", tools=[existing_tool])
root = workflow_type(name="workflow", sub_agents=[child])
kwargs = (
{"app": App(name="workflow_app", root_agent=root)}
if use_app
else {"root_agent": root}
)
app = agentkit_app.create_agentkit_app(**kwargs, enable_studio_tools=enabled)
client = TestClient(app)

assert client.get("/harness/studio-channel/v1/capabilities").json() == {
"enabled": False,
"protocol": "studio-tool-channel/1",
"transports": [],
}
paths = {getattr(route, "path", "") for route in app.routes}
assert "/harness/studio-channel/v1/http-runs" not in paths
assert child.tools == [existing_tool]
assert existing_tool() == "ok"


@pytest.mark.parametrize("enabled", [False, True])
def test_create_agentkit_app_uses_runtime_bff_route_opt_in(
monkeypatch: pytest.MonkeyPatch,
Expand Down
4 changes: 3 additions & 1 deletion veadk/cli/generated_agent_codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,7 @@ def _render_app_py(
pkg: str,
feishu_channel_enabled: bool,
harness_sidecar_enabled: bool,
studio_tools_enabled: bool,
) -> str:
lines = [
_PYTHON_LICENSE_HEADER.rstrip(),
Expand All @@ -1155,7 +1156,7 @@ def _render_app_py(
"",
"_app_options = {",
f' "enable_feishu": {feishu_channel_enabled!r},',
' "enable_studio_tools": True,',
f' "enable_studio_tools": {studio_tools_enabled!r},',
"}",
'if "agent_draft" in signature(create_agentkit_app).parameters:',
' _app_options["agent_draft"] = AGENT_DRAFT',
Expand Down Expand Up @@ -2443,6 +2444,7 @@ def generate_project_from_draft(draft: AgentDraft) -> GeneratedProject:
pkg,
feishu_channel_enabled,
harness_sidecar_enabled,
studio_tools_enabled=draft.agentType not in {"sequential", "parallel", "loop"},
)
files = [
GeneratedFile(path="app.py", content=app_py),
Expand Down
14 changes: 13 additions & 1 deletion veadk/integrations/agentkit/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,16 @@
from veadk.agent_search import search_agent_component
from veadk.cli.frontend_invocation import FrontendInvocationPlugin
from veadk.memory.short_term_memory import ShortTermMemory
from veadk.utils.logger import get_logger

if TYPE_CHECKING:
from agentkit.identity import RuntimeIdentity # pyright: ignore[reportMissingImports]

from veadk.runner import Runner


logger = get_logger(__name__)

_MAX_AGENT_GRAPH_DEPTH = 8
_SERVER_STATE_KEY = "_veadk_agentkit_server"
_ADK_SERVER_STATE_KEY = "_veadk_adk_server"
Expand Down Expand Up @@ -915,6 +918,14 @@ def _configure_studio_tool_routes(
mount_studio_channel_routes,
)

if enabled and isinstance(root_agent, (SequentialAgent, ParallelAgent, LoopAgent)):
logger.warning(
"Disabling Studio BFF tools for workflow root agent "
f"{root_agent.name!r} ({type(root_agent).__name__}); "
"workflow roots do not support tool calls."
)
enabled = False

if not enabled:
mount_studio_channel_routes(app=app, enabled=False)
return
Expand Down Expand Up @@ -1001,7 +1012,8 @@ def create_agentkit_app(
enable_studio_tools: Whether to mount the generic Runtime host for
Studio BFF-owned dynamic tools. Tool manifests and executors remain
in the Studio BFF and are exposed only during explicitly selected
Studio-channel runs.
Studio-channel runs. Automatically disabled for SequentialAgent,
ParallelAgent, and LoopAgent roots.
enable_studio_routes: Whether to mount the generic Runtime host for
Studio BFF-owned dynamic HTTP routes. Route handlers remain in the
Studio BFF and are never loaded into the Runtime process. Enabled
Expand Down
Loading