wren leaves unnamed areas to the assistant; assistant targets take a closed set of values
wren drops a call on an area the command does not name (other than the
user's or, with none named, the living room): "switch on the appliances"
turned on the bathroom light at 0.97. The assistant's `values` setting gives
a str target its only values, explains them in the tool and confirms in the
word set for each ("Canopy open.").
This commit is contained in:
@@ -138,3 +138,39 @@ def test_no_provider_or_one_that_does_not_answer_is_said(
|
||||
_ask(node, "what is the weather tomorrow")
|
||||
assert said.pop() == {"reply": UNAVAILABLE}
|
||||
assert node._health == "degraded"
|
||||
|
||||
|
||||
def test_a_target_with_values_takes_only_those_and_is_confirmed_in_words(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
):
|
||||
seen: list[dict[str, Any]] = []
|
||||
log: list[Any] = []
|
||||
|
||||
async def completion(**kwargs: Any) -> AsyncIterator[str | dict[str, Any]]:
|
||||
seen.append(kwargs)
|
||||
calls = [_call("canopy", "OPEN"), _call("canopy", "UP")]
|
||||
yield {"role": "assistant", "content": None, "tool_calls": calls}
|
||||
|
||||
monkeypatch.setattr(ai_config, "load", lambda: PROVIDER)
|
||||
monkeypatch.setattr(client, "stream_completion", completion)
|
||||
monkeypatch.setattr(AssistantNode, "emit", lambda self, values: log.append(values))
|
||||
node = AssistantNode(
|
||||
requires=[MessageSpec(name="unhandled", port="prompt", dtype=DType.STR)],
|
||||
provides=[
|
||||
MessageSpec(name="canopy_manual", port="canopy", dtype=DType.STR),
|
||||
MessageSpec(name="reply", dtype=DType.STR),
|
||||
],
|
||||
params={"values": {"canopy": {"UP": "open", "DOWN": "closed"}}},
|
||||
)
|
||||
node.assign_flow("voice", "assistant")
|
||||
Pipeline([node])
|
||||
|
||||
_ask(node, "open the canopy")
|
||||
|
||||
[tool] = seen[0]["tools"]
|
||||
assert tool["function"]["parameters"]["properties"]["value"]["enum"] == [
|
||||
"UP",
|
||||
"DOWN",
|
||||
]
|
||||
assert '"UP" means canopy open' in tool["function"]["description"]
|
||||
assert log == [{"canopy": "UP"}, {"reply": "Canopy open."}]
|
||||
|
||||
@@ -204,3 +204,15 @@ def test_a_reply_says_what_was_applied_and_the_rest_is_unhandled(fake_wren):
|
||||
unhandled = MessageSpec(name="house.unhandled", port="unhandled", dtype=DType.STR)
|
||||
Pipeline([node, Node(lambda params, unhandled: None, requires=[unhandled])])
|
||||
assert node.execute({"house.command": asked}) == {"house.unhandled": asked}
|
||||
|
||||
|
||||
def test_a_call_on_an_area_the_command_does_not_name_is_not_applied(fake_wren):
|
||||
"""A word the model never learned lands on a neighbour it was shown."""
|
||||
node = _node(("bathroom_light", DType.BOOL), apply=True)
|
||||
fake_wren.answer = ([FakeCall("lights.on", {"id": "bathroom:light"})], 0.97)
|
||||
|
||||
out = node.execute({"house.command": "switch on the appliances"})
|
||||
|
||||
assert out is not None
|
||||
assert "house.bathroom_light" not in out
|
||||
assert [a["applied"] for a in out["house.actions"]] == [False]
|
||||
|
||||
Reference in New Issue
Block a user