Files
privateGPT/tests/components/tools/test_code_execution_builders.py
Javier Martinez 21d42fd97a feat: code execution v4 (#2295)
* feat: add bundle to remove

* fix: spaces

* feat: add xml render as skill spec

* feat: add skill volume root to cache

* fix: deduplicate values

* fix: change the mount path to skill_id

* fix: use different paths

* feat: add principal

(cherry picked from commit 5db64fe721d5706440ce9f342b1388ffe742bc16)

# Conflicts:
#	private_gpt/components/code_execution/base.py
#	private_gpt/components/code_execution/code_execution_component.py
#	private_gpt/components/code_execution/local.py
#	private_gpt/components/environment/manager.py
#	private_gpt/components/tools/builders/bash_tool_builder.py
#	private_gpt/components/tools/builders/text_editor_tool_builder.py
#	private_gpt/components/tools/processors/bash_processor.py

* fix: mypy

...

* fix: config

* fix: sandbox config

* feat: add forward cookies

* fix: loop

* feat: add present server

* feat: add feature flag for tools

* refactor: move principal to another better place

* feat: add api key principal

* docs: fix docs

* docs: add present server

* fix: principal

* fix: mypy

* fix: avoid to block the loop

* fix: blocks in expansion

* fix: remove maximum concurrent users

...

* fix: multiplexer

* fix: readers

* fix: more fixes

...

* fix: impl

* feat: tool scheduler

* feat: add adaptative

* feat: add chat worker

* fix: config

* fix: max

* feat: add chat/tools workers

* fix: mypy

* feat: add generic scheduler

* fix: get result

* feat: do serializable the tool executor

* fix: tools

* fix: config

* fix: config

* fix: args

* fix: config

* fix: serializer

* Revert "fix: blocks in expansion"

This reverts commit a2110f94a8.

* fix: unify all logic

* feat: add ingestion scheduler

* fix: settings

* fix: config

* feat: add arq worker to chat

* fix: arq worker

* fix: add nest

* fix: mypy

* fix: await

* fix: script stress

* fix: tokenizer

* fix: chat scheduler

* fix: mypy

* fix: add async tokenizer

* fix: improve condense

* fix: tool scheduler

* feat: add initial real async chat worker

* fix: mypy

* fix: do resumable local executor

...

...

...

fix: revert usleess changes

fix: remove parent chat job

fix: refactor

fix: loop

ref: rename models

fix: chat engine

fix: mypy

...

...

...

fix: fix deps

* fix: tests

* fix: tests

* ...

* fix: stream

* fix: config

* fix: scheduler

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Handle PGPT_WORKER_MODE=celery in health check worker status

* fix: cancel

* fix: arch

* fix: test ingestion

* fix: deserialization of chat messages

* fix: broken results

* fix: mypy

* fix: test

* fix: config

* fix: remove arq tool worker

* fix: output cls

* fix: preserve early resumable tool callbacks

* fix: preserve async tool result order

* refactor: address worker PR review comments

* fix: mypy

* test: colocate ARQ chat enqueue coverage

* fix: remove redis from tests

* fix: mypy

* fix: tests

* test: isolate chat mocks and cancellation timing

* fix: tests

* fix: tests

* fix: test

(cherry picked from commit f8ee460af2)

* fix: worker config

* test: remove flaky chat cancellation assertion

(cherry picked from commit 1115ff2349)

# Conflicts:
#	tests/server/chat/test_chat_routes.py

* fix: emit chat pings from stream listeners

* fix: don't duplciate the output

* fix: rss memory

...

* fix: pass the args

* fix: threads

* fix: websearch

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-15 13:05:23 +02:00

102 lines
3.3 KiB
Python

from types import SimpleNamespace
from unittest.mock import AsyncMock
import pytest
from private_gpt.components.code_execution.results import (
BashExecutionResult,
FileOperationResult,
)
from private_gpt.components.tools.builders.bash_tool_builder import BashToolBuilder
from private_gpt.components.tools.builders.text_editor_tool_builder import (
TextEditorToolBuilder,
)
from private_gpt.settings.settings import unsafe_typed_settings
def _settings():
settings = unsafe_typed_settings.model_copy(deep=True)
settings.code_execution.max_output_bytes = 10_000
return settings
@pytest.mark.asyncio
async def test_bash_tool_builder_executes_session_command() -> None:
session = SimpleNamespace(
execute_bash=AsyncMock(
return_value=BashExecutionResult(
success=True,
stdout="ok",
stderr="",
exit_code=0,
)
)
)
builder = BashToolBuilder(
code_execution_component=SimpleNamespace(
get_or_create_session=AsyncMock(return_value=session)
),
settings=_settings(),
)
tool = await builder.build_tool("corr-1")
result = await tool.async_fn(command="echo ok")
session.execute_bash.assert_awaited_once_with(
"echo ok",
timeout=None,
restart=False,
)
assert result[0].text == "exit_code: 0\n\nstdout:\nok"
@pytest.mark.asyncio
async def test_text_editor_tool_builder_wraps_file_operations() -> None:
session = SimpleNamespace(
view=AsyncMock(
return_value=FileOperationResult(success=True, output="1: line")
),
str_replace=AsyncMock(
return_value=FileOperationResult(success=True, output="Updated file.txt")
),
create=AsyncMock(
return_value=FileOperationResult(success=False, error="exists")
),
insert=AsyncMock(
return_value=FileOperationResult(success=True, output="Updated file.txt")
),
)
builder = TextEditorToolBuilder(
code_execution_component=SimpleNamespace(
get_or_create_session=AsyncMock(return_value=session)
),
settings=_settings(),
)
view_tool = await builder.build_view_tool("corr-2")
replace_tool = await builder.build_str_replace_tool("corr-2")
create_tool = await builder.build_create_tool("corr-2")
insert_tool = await builder.build_insert_tool("corr-2")
view_result = await view_tool.async_fn(path="file.txt", view_range=[1, 1])
replace_result = await replace_tool.async_fn(
path="file.txt",
old_str="old",
new_str="new",
)
create_result = await create_tool.async_fn(path="file.txt", file_text="body")
insert_result = await insert_tool.async_fn(
path="file.txt",
insert_line=1,
new_str="extra",
)
session.view.assert_awaited_once_with("file.txt", view_range=(1, 1))
session.str_replace.assert_awaited_once_with("file.txt", "old", "new")
session.create.assert_awaited_once_with("file.txt", "body")
session.insert.assert_awaited_once_with("file.txt", 1, "extra")
assert view_result[0].text == "1: line"
assert replace_result[0].text == "Updated file.txt"
assert create_result[0].text == "Error: exists"
assert insert_result[0].text == "Updated file.txt"