Skip to content

Commit a40a1f2

Browse files
author
wayflow-bot
committed
Merge 'Agent inputs default values'
2 parents 87bf38e + 282a62d commit a40a1f2

File tree

4 files changed

+128
-9
lines changed

4 files changed

+128
-9
lines changed

docs/wayflowcore/source/core/changelog.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ Possibly Breaking Changes
3939
Bug fixes
4040
^^^^^^^^^
4141

42+
* **Default values in agents inputs were ignored:**
43+
44+
Fixed a bug where if agents had input descriptors with default values set, these defaults were ignored and not
45+
used when starting a conversation. Now default values of input descriptors are used if they are set, and no
46+
input entry with the descriptor name is passed to the ``start_conversation`` method.
47+
4248
* **Default values in tools outputs were ignored:**
4349

4450
Fixed a bug where if tools had multiple output descriptors with default values set for some of them, these defaults were ignored and not

wayflowcore/src/wayflowcore/agent.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from wayflowcore.idgeneration import IdGenerator
1919
from wayflowcore.messagelist import Message, MessageList
2020
from wayflowcore.models.llmmodel import LlmModel
21-
from wayflowcore.property import Property, _cast_value_into
21+
from wayflowcore.property import Property, _cast_value_into, _empty_default
2222
from wayflowcore.serialization.serializer import SerializableDataclassMixin, SerializableObject
2323
from wayflowcore.templates import PromptTemplate
2424
from wayflowcore.tools import DescribedAgent, DescribedFlow, Tool, ToolBox
@@ -398,19 +398,32 @@ def start_conversation(
398398
if not isinstance(messages, MessageList):
399399
messages = MessageList.from_messages(messages=messages)
400400

401+
required_input_names = [
402+
input_descriptor.name
403+
for input_descriptor in self.input_descriptors
404+
if input_descriptor.default_value is _empty_default
405+
]
406+
401407
if len(self.input_descriptors) > 0:
402408
if inputs is None:
403-
raise ValueError(
404-
f"Agent has inputs (`{self.input_descriptors}`), but you did not pass any."
405-
)
409+
if required_input_names:
410+
raise ValueError(
411+
f"Agent requires inputs (`{required_input_names}`), but you did not pass any."
412+
)
413+
else:
414+
# We don't have inputs, but all the input descriptors have defaults
415+
inputs = {}
406416
for input_value_description in self.input_descriptors:
407-
if input_value_description.name not in inputs:
417+
# We retrieve inputs when available, otherwise get defaults if defined, if not defined, raise
418+
if input_value_description.name in inputs:
419+
input_value = inputs[input_value_description.name]
420+
elif input_value_description.default_value is not _empty_default:
421+
input_value = input_value_description.default_value
422+
else:
408423
raise ValueError(
409-
f"The agent has an input `{input_value_description}`, but it was not passed in the input dictionary: `{inputs}`"
424+
f"The agent requires an input `{input_value_description.name}`, but it was not passed in the input dictionary: `{inputs}`"
410425
)
411426

412-
input_value = inputs[input_value_description.name]
413-
414427
try:
415428
casted_input_value = _cast_value_into(input_value, input_value_description)
416429
inputs[input_value_description.name] = casted_input_value

wayflowcore/tests/integration/steps/test_agentexecution_step.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from wayflowcore.flow import Flow
1515
from wayflowcore.flowhelpers import create_single_step_flow, run_flow_and_return_outputs
1616
from wayflowcore.models.vllmmodel import VllmModel
17-
from wayflowcore.property import IntegerProperty, Property
17+
from wayflowcore.property import IntegerProperty, Property, StringProperty
1818
from wayflowcore.steps.agentexecutionstep import AgentExecutionStep, CallerInputMode
1919
from wayflowcore.steps.outputmessagestep import OutputMessageStep
2020
from wayflowcore.tools import ClientTool, ToolRequest
@@ -495,3 +495,49 @@ def test_agent_step_uses_default_caller_input_mode_of_agent(remotely_hosted_llm)
495495
conv.append_user_message("What is the capital of Switzerland?")
496496
status = conv.execute()
497497
assert isinstance(status, FinishedStatus)
498+
499+
500+
@retry_test(max_attempts=3)
501+
def test_agent_step_that_uses_agent_with_default_input_values_works(big_llama):
502+
"""
503+
Failure rate: 0 out of 20
504+
Observed on: 2025-11-19
505+
Average success time: 2.94 seconds per successful attempt
506+
Average failure time: No time measurement
507+
Max attempt: 3
508+
Justification: (0.05 ** 3) ~= 9.4 / 100'000
509+
"""
510+
agent = Agent(
511+
llm=big_llama,
512+
custom_instruction="You are a helpful agent. Here's what you know: {{context}}. Answer the user `{{username}}`.",
513+
input_descriptors=[
514+
StringProperty(name="context", default_value="Videogames"),
515+
StringProperty(name="username"),
516+
],
517+
)
518+
519+
agent_step = AgentExecutionStep(
520+
agent=agent,
521+
)
522+
523+
flow = Flow.from_steps(steps=[agent_step])
524+
assert len(flow.input_descriptors) == 2
525+
assert {"context", "username"} == set(descriptor.name for descriptor in flow.input_descriptors)
526+
context_input = next(
527+
descriptor for descriptor in flow.input_descriptors if descriptor.name == "context"
528+
)
529+
assert context_input.default_value == "Videogames"
530+
531+
conv = flow.start_conversation({"username": "john"})
532+
status = conv.execute()
533+
assert isinstance(status, UserMessageRequestStatus)
534+
status.submit_user_response("Who is the user?")
535+
status = conv.execute()
536+
assert isinstance(status, UserMessageRequestStatus)
537+
last_message = status.message
538+
assert "john" in last_message.content.lower()
539+
status.submit_user_response("What do you know?")
540+
status = conv.execute()
541+
assert isinstance(status, UserMessageRequestStatus)
542+
last_message = status.message
543+
assert "videogame" in last_message.content.lower()

wayflowcore/tests/integration/test_agent.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2080,3 +2080,57 @@ def test_caller_input_mode_never_with_single_iteration(big_llama):
20802080
status = conv.execute()
20812081
assert isinstance(status, FinishedStatus)
20822082
assert not status.output_values["haiku_submitted"]
2083+
2084+
2085+
@retry_test(max_attempts=3)
2086+
def test_agent_with_default_input_values_works(big_llama):
2087+
"""
2088+
Failure rate: 0 out of 20
2089+
Observed on: 2025-11-19
2090+
Average success time: 2.81 seconds per successful attempt
2091+
Average failure time: No time measurement
2092+
Max attempt: 3
2093+
Justification: (0.05 ** 3) ~= 9.4 / 100'000
2094+
"""
2095+
agent = Agent(
2096+
llm=big_llama,
2097+
custom_instruction="You are a helpful agent. Here's what you know: {{context}}. Answer the user `{{username}}`.",
2098+
input_descriptors=[
2099+
StringProperty(name="context", default_value="Videogames"),
2100+
StringProperty(name="username"),
2101+
],
2102+
)
2103+
conv = agent.start_conversation({"username": "john"})
2104+
status = conv.execute()
2105+
assert isinstance(status, UserMessageRequestStatus)
2106+
status.submit_user_response("Who is the user?")
2107+
status = conv.execute()
2108+
assert isinstance(status, UserMessageRequestStatus)
2109+
last_message = status.message
2110+
assert "john" in last_message.content.lower()
2111+
status.submit_user_response("What do you know?")
2112+
status = conv.execute()
2113+
assert isinstance(status, UserMessageRequestStatus)
2114+
last_message = status.message
2115+
assert "videogame" in last_message.content.lower()
2116+
2117+
2118+
def test_agent_with_missing_input_values_raises(big_llama):
2119+
agent = Agent(
2120+
llm=big_llama,
2121+
custom_instruction="You are a helpful agent. Here's what you know: {{context}}. But also {{additional_context}}. Answer the user.",
2122+
input_descriptors=[
2123+
StringProperty(name="context", default_value="Videogames"),
2124+
StringProperty(name="additional_context"),
2125+
],
2126+
)
2127+
with pytest.raises(
2128+
ValueError,
2129+
match=r"Agent requires inputs \(`\['additional_context'\]`\), but you did not pass any.",
2130+
):
2131+
_ = agent.start_conversation()
2132+
with pytest.raises(
2133+
ValueError,
2134+
match="The agent requires an input `additional_context`, but it was not passed in the input dictionary",
2135+
):
2136+
_ = agent.start_conversation({})

0 commit comments

Comments
 (0)