v1.2.2
Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai> Co-Authored-By: Michel Thomazo <michel.thomazo@mistral.ai>
This commit is contained in:
parent
402e898f39
commit
2e1e15120d
32 changed files with 391 additions and 549 deletions
|
|
@ -44,10 +44,12 @@ def make_config(todo_permission: ToolPermission = ToolPermission.ALWAYS) -> Vibe
|
|||
)
|
||||
|
||||
|
||||
def make_todo_tool_call(call_id: str, action: str = "read") -> ToolCall:
|
||||
def make_todo_tool_call(
|
||||
call_id: str, index: int = 0, arguments: str | None = None
|
||||
) -> ToolCall:
|
||||
args = arguments if arguments is not None else '{"action": "read"}'
|
||||
return ToolCall(
|
||||
id=call_id,
|
||||
function=FunctionCall(name="todo", arguments=f'{{"action": "{action}"}}'),
|
||||
id=call_id, index=index, function=FunctionCall(name="todo", arguments=args)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -72,8 +74,8 @@ async def test_single_tool_call_executes_under_auto_approve() -> None:
|
|||
mocked_tool_call_id = "call_1"
|
||||
tool_call = make_todo_tool_call(mocked_tool_call_id)
|
||||
backend = FakeBackend([
|
||||
mock_llm_chunk(content="Let me check your todos.", tool_calls=[tool_call]),
|
||||
mock_llm_chunk(content="I retrieved 0 todos.", finish_reason="stop"),
|
||||
[mock_llm_chunk(content="Let me check your todos.", tool_calls=[tool_call])],
|
||||
[mock_llm_chunk(content="I retrieved 0 todos.")],
|
||||
])
|
||||
agent = make_agent(auto_approve=True, backend=backend)
|
||||
|
||||
|
|
@ -108,14 +110,13 @@ async def test_tool_call_requires_approval_if_not_auto_approved() -> None:
|
|||
auto_approve=False,
|
||||
todo_permission=ToolPermission.ASK,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_2")],
|
||||
),
|
||||
mock_llm_chunk(
|
||||
content="I cannot execute the tool without approval.",
|
||||
finish_reason="stop",
|
||||
),
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_2")],
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="I cannot execute the tool without approval.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -148,11 +149,13 @@ async def test_tool_call_approved_by_callback() -> None:
|
|||
todo_permission=ToolPermission.ASK,
|
||||
approval_callback=approval_callback,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_3")],
|
||||
),
|
||||
mock_llm_chunk(content="I retrieved 0 todos.", finish_reason="stop"),
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_3")],
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="I retrieved 0 todos.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -183,13 +186,13 @@ async def test_tool_call_rejected_when_auto_approve_disabled_and_rejected_by_cal
|
|||
todo_permission=ToolPermission.ASK,
|
||||
approval_callback=approval_callback,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_4")],
|
||||
),
|
||||
mock_llm_chunk(
|
||||
content="Understood, I won't check the todos.", finish_reason="stop"
|
||||
),
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_4")],
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="Understood, I won't check the todos.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -211,11 +214,13 @@ async def test_tool_call_skipped_when_permission_is_never() -> None:
|
|||
auto_approve=False,
|
||||
todo_permission=ToolPermission.NEVER,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_never")],
|
||||
),
|
||||
mock_llm_chunk(content="Tool is disabled.", finish_reason="stop"),
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.",
|
||||
tool_calls=[make_todo_tool_call("call_never")],
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="Tool is disabled.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -257,14 +262,20 @@ async def test_approval_always_sets_tool_permission_for_subsequent_calls() -> No
|
|||
todo_permission=ToolPermission.ASK,
|
||||
approval_callback=approval_callback,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(
|
||||
content="First check.", tool_calls=[make_todo_tool_call("call_first")]
|
||||
),
|
||||
mock_llm_chunk(content="First done.", finish_reason="stop"),
|
||||
mock_llm_chunk(
|
||||
content="Second check.", tool_calls=[make_todo_tool_call("call_second")]
|
||||
),
|
||||
mock_llm_chunk(content="Second done.", finish_reason="stop"),
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="First check.",
|
||||
tool_calls=[make_todo_tool_call("call_first")],
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="First done.")],
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="Second check.",
|
||||
tool_calls=[make_todo_tool_call("call_second")],
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="Second done.")],
|
||||
]),
|
||||
)
|
||||
agent_ref = agent
|
||||
|
|
@ -291,17 +302,16 @@ async def test_approval_always_sets_tool_permission_for_subsequent_calls() -> No
|
|||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tool_call_with_invalid_action() -> None:
|
||||
tool_call = ToolCall(
|
||||
id="call_5",
|
||||
function=FunctionCall(name="todo", arguments='{"action": "invalid_action"}'),
|
||||
)
|
||||
tool_call = make_todo_tool_call("call_5", arguments='{"action": "invalid_action"}')
|
||||
agent = make_agent(
|
||||
auto_approve=True,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(content="Let me check your todos.", tool_calls=[tool_call]),
|
||||
mock_llm_chunk(
|
||||
content="I encountered an error with the action.", finish_reason="stop"
|
||||
),
|
||||
[
|
||||
mock_llm_chunk(
|
||||
content="Let me check your todos.", tool_calls=[tool_call]
|
||||
)
|
||||
],
|
||||
[mock_llm_chunk(content="I encountered an error with the action.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -320,24 +330,18 @@ async def test_tool_call_with_duplicate_todo_ids() -> None:
|
|||
TodoItem(id="duplicate", content="Task 1"),
|
||||
TodoItem(id="duplicate", content="Task 2"),
|
||||
]
|
||||
tool_call = ToolCall(
|
||||
id="call_6",
|
||||
function=FunctionCall(
|
||||
name="todo",
|
||||
arguments=json.dumps({
|
||||
"action": "write",
|
||||
"todos": [t.model_dump() for t in duplicate_todos],
|
||||
}),
|
||||
),
|
||||
tool_call = make_todo_tool_call(
|
||||
"call_6",
|
||||
arguments=json.dumps({
|
||||
"action": "write",
|
||||
"todos": [t.model_dump() for t in duplicate_todos],
|
||||
}),
|
||||
)
|
||||
agent = make_agent(
|
||||
auto_approve=True,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(content="Let me write todos.", tool_calls=[tool_call]),
|
||||
mock_llm_chunk(
|
||||
content="I couldn't write todos with duplicate IDs.",
|
||||
finish_reason="stop",
|
||||
),
|
||||
[mock_llm_chunk(content="Let me write todos.", tool_calls=[tool_call])],
|
||||
[mock_llm_chunk(content="I couldn't write todos with duplicate IDs.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -353,23 +357,18 @@ async def test_tool_call_with_duplicate_todo_ids() -> None:
|
|||
@pytest.mark.asyncio
|
||||
async def test_tool_call_with_exceeding_max_todos() -> None:
|
||||
many_todos = [TodoItem(id=f"todo_{i}", content=f"Task {i}") for i in range(150)]
|
||||
tool_call = ToolCall(
|
||||
id="call_7",
|
||||
function=FunctionCall(
|
||||
name="todo",
|
||||
arguments=json.dumps({
|
||||
"action": "write",
|
||||
"todos": [t.model_dump() for t in many_todos],
|
||||
}),
|
||||
),
|
||||
tool_call = make_todo_tool_call(
|
||||
"call_7",
|
||||
arguments=json.dumps({
|
||||
"action": "write",
|
||||
"todos": [t.model_dump() for t in many_todos],
|
||||
}),
|
||||
)
|
||||
agent = make_agent(
|
||||
auto_approve=True,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(content="Let me write todos.", tool_calls=[tool_call]),
|
||||
mock_llm_chunk(
|
||||
content="I couldn't write that many todos.", finish_reason="stop"
|
||||
),
|
||||
[mock_llm_chunk(content="Let me write todos.", tool_calls=[tool_call])],
|
||||
[mock_llm_chunk(content="I couldn't write that many todos.")],
|
||||
]),
|
||||
)
|
||||
|
||||
|
|
@ -394,7 +393,7 @@ async def test_tool_call_can_be_interrupted(
|
|||
exception_class: type[BaseException],
|
||||
) -> None:
|
||||
tool_call = ToolCall(
|
||||
id="call_8", function=FunctionCall(name="stub_tool", arguments="{}")
|
||||
id="call_8", index=0, function=FunctionCall(name="stub_tool", arguments="{}")
|
||||
)
|
||||
config = VibeConfig(
|
||||
session_logging=SessionLoggingConfig(enabled=False),
|
||||
|
|
@ -405,8 +404,8 @@ async def test_tool_call_can_be_interrupted(
|
|||
config,
|
||||
mode=AgentMode.AUTO_APPROVE,
|
||||
backend=FakeBackend([
|
||||
mock_llm_chunk(content="Let me use the tool.", tool_calls=[tool_call]),
|
||||
mock_llm_chunk(content="Tool execution completed.", finish_reason="stop"),
|
||||
[mock_llm_chunk(content="Let me use the tool.", tool_calls=[tool_call])],
|
||||
[mock_llm_chunk(content="Tool execution completed.")],
|
||||
]),
|
||||
)
|
||||
# no dependency injection available => monkey patch
|
||||
|
|
@ -433,15 +432,11 @@ async def test_fill_missing_tool_responses_inserts_placeholders() -> None:
|
|||
agent = Agent(
|
||||
make_config(),
|
||||
mode=AgentMode.AUTO_APPROVE,
|
||||
backend=FakeBackend([mock_llm_chunk(content="ok", finish_reason="stop")]),
|
||||
backend=FakeBackend(mock_llm_chunk(content="ok")),
|
||||
)
|
||||
tool_calls_messages = [
|
||||
ToolCall(
|
||||
id="tc1", function=FunctionCall(name="todo", arguments='{"action": "read"}')
|
||||
),
|
||||
ToolCall(
|
||||
id="tc2", function=FunctionCall(name="todo", arguments='{"action": "read"}')
|
||||
),
|
||||
make_todo_tool_call("tc1", index=0),
|
||||
make_todo_tool_call("tc2", index=1),
|
||||
]
|
||||
assistant_msg = LLMMessage(
|
||||
role=Role.assistant, content="Calling tools...", tool_calls=tool_calls_messages
|
||||
|
|
@ -473,7 +468,7 @@ async def test_ensure_assistant_after_tool_appends_understood() -> None:
|
|||
agent = Agent(
|
||||
make_config(),
|
||||
mode=AgentMode.AUTO_APPROVE,
|
||||
backend=FakeBackend([mock_llm_chunk(content="ok", finish_reason="stop")]),
|
||||
backend=FakeBackend(mock_llm_chunk(content="ok")),
|
||||
)
|
||||
tool_msg = LLMMessage(
|
||||
role=Role.tool, tool_call_id="tc_z", name="todo", content="Done"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue