Skip to content

Commit 4f88055

Browse files
authored
Raise an exception on duplicated subagent names (#41)
1 parent 9e969e2 commit 4f88055

2 files changed

Lines changed: 82 additions & 4 deletions

File tree

splunklib/ai/engines/langchain.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,21 @@ async def create_agent(
155155
tools = [_create_langchain_tool(t) for t in agent.tools]
156156

157157
if agent.agents:
158-
tools.extend([_agent_as_tool(a) for a in agent.agents])
159-
system_prompt = AGENT_AS_TOOLS_PROMPT + "\n" + system_prompt
158+
seen_names: set[str] = set()
159+
for subagent in agent.agents:
160+
# Call _agent_as_tool first, such that the empty name exception is
161+
# checked and raised first, before the duplicated name exception.
162+
tool = _agent_as_tool(subagent)
163+
164+
if subagent.name in seen_names:
165+
raise AssertionError(
166+
f"Subagents share the same name: {subagent.name}"
167+
)
168+
169+
seen_names.add(subagent.name)
170+
tools.append(tool)
171+
172+
system_prompt = AGENT_AS_TOOLS_PROMPT + "\n" + system_prompt
160173

161174
middleware = []
162175
if agent.loop_stop_conditions:
@@ -219,8 +232,6 @@ def _agent_as_tool(agent: BaseAgent[OutputT]):
219232
if not agent.name:
220233
raise AssertionError("Agent must have a name to be used by other Agents")
221234

222-
# TODO: we should enforce uniqueness of subagent names.
223-
224235
if agent.input_schema is None:
225236

226237
async def _run(content: str) -> str:

tests/integration/ai/test_agent.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,70 @@ async def test_agent_loop_stop_conditions_timeout(self):
402402
)
403403
]
404404
)
405+
406+
@pytest.mark.asyncio
407+
async def test_duplicated_subagent_name(self) -> None:
408+
pytest.importorskip("langchain_openai")
409+
410+
async with (
411+
Agent(
412+
model=(await self.model()),
413+
system_prompt="",
414+
service=self.service,
415+
name="subagent_name",
416+
) as subagent1,
417+
Agent(
418+
model=(await self.model()),
419+
system_prompt="",
420+
service=self.service,
421+
name="subagent_name",
422+
) as subagent2,
423+
Agent(
424+
model=(await self.model()),
425+
system_prompt="",
426+
service=self.service,
427+
name="",
428+
) as subagent1_empty_name,
429+
Agent(
430+
model=(await self.model()),
431+
system_prompt="",
432+
service=self.service,
433+
name="",
434+
) as subagent2_empty_name,
435+
):
436+
with pytest.raises(
437+
AssertionError, match="Subagents share the same name: subagent_name"
438+
):
439+
async with Agent(
440+
model=(await self.model()),
441+
system_prompt="",
442+
service=self.service,
443+
agents=[subagent1, subagent2],
444+
):
445+
pass
446+
447+
# Also make sure, that because of this check we have, we will not
448+
# mistakenely accept same subagent (since they also share the same name).
449+
with pytest.raises(
450+
AssertionError, match="Subagents share the same name: subagent_name"
451+
):
452+
async with Agent(
453+
model=(await self.model()),
454+
system_prompt="",
455+
service=self.service,
456+
agents=[subagent1, subagent1],
457+
):
458+
pass
459+
460+
# Make sure that the subagent is validated before the name uniqueness check.
461+
with pytest.raises(
462+
AssertionError,
463+
match="Agent must have a name to be used by other Agents",
464+
):
465+
async with Agent(
466+
model=(await self.model()),
467+
system_prompt="",
468+
service=self.service,
469+
agents=[subagent1_empty_name, subagent2_empty_name],
470+
):
471+
pass

0 commit comments

Comments
 (0)