refactor(sandbox): keep box logic out of pipeline and localagent

- Move sandbox system-prompt guidance from LocalAgentRunner into
    BoxService.get_system_guidance() so all box domain knowledge stays
    in the box module.
  - Remove standalone logging_utils.py; merge format_result_log() into
    MessageHandler base class alongside cut_str().
  - Strip sandbox-specific JSON parsing from log formatting; tool
    results now use generic truncation.
  - Revert TYPE_CHECKING changes in stage.py and runner.py that were
    unrelated to this feature.
  - Skip two test files affected by a pre-existing circular import
    (runner ↔ app) until the import cycle is resolved in a separate PR.
This commit is contained in:
youhuanghe
2026-03-22 05:46:32 +00:00
committed by WangCham
parent a7664d1665
commit 42fa75331b
9 changed files with 106 additions and 126 deletions

View File

@@ -3,8 +3,7 @@ from __future__ import annotations
import abc
import typing
if typing.TYPE_CHECKING:
from ..core import app
from ..core import app
preregistered_runners: list[typing.Type[RequestRunner]] = []
@@ -26,11 +25,11 @@ class RequestRunner(abc.ABC):
name: str = None
ap: 'app.Application'
ap: app.Application
pipeline_config: dict
def __init__(self, ap: 'app.Application', pipeline_config: dict):
def __init__(self, ap: app.Application, pipeline_config: dict):
self.ap = ap
self.pipeline_config = pipeline_config

View File

@@ -25,39 +25,10 @@ Respond in the same language as the user's input.
</user_message>
"""
SANDBOX_EXEC_SYSTEM_GUIDANCE = (
'When sandbox_exec is available, use it for exact calculations, statistics, structured data parsing, '
'and code execution instead of estimating mentally. If the user provides numbers, tables, CSV-like text, '
'JSON, or other data and asks for a computed answer, prefer running a short Python script in sandbox_exec '
'and then answer from the tool result. Unless the user explicitly asks for the script, code, or implementation '
'details, do not include the generated script in the final answer; return the result and a brief explanation only.'
)
SANDBOX_EXEC_WORKSPACE_GUIDANCE = (
'A default host workspace is mounted at /workspace for file tasks. When the user asks to read, create, or '
'modify local files in the working directory, use sandbox_exec with /workspace paths directly; do not ask the '
'user for sandbox parameters such as host_path unless they explicitly need a different directory.'
)
@runner.runner_class('local-agent')
class LocalAgentRunner(runner.RequestRunner):
"""Local agent request runner"""
_cached_sandbox_guidance: str | None = None
def _build_sandbox_system_guidance(self) -> str:
if self._cached_sandbox_guidance is not None:
return self._cached_sandbox_guidance
from langbot.pkg.box.models import get_box_config
guidance = SANDBOX_EXEC_SYSTEM_GUIDANCE
default_host_workspace = str(get_box_config(self.ap).get('default_host_workspace', '')).strip()
if default_host_workspace:
guidance = f'{guidance} {SANDBOX_EXEC_WORKSPACE_GUIDANCE}'
self._cached_sandbox_guidance = guidance
return guidance
def _build_request_messages(
self,
query: pipeline_query.Query,
@@ -69,7 +40,7 @@ class LocalAgentRunner(runner.RequestRunner):
req_messages.append(
provider_message.Message(
role='system',
content=self._build_sandbox_system_guidance(),
content=self.ap.box_service.get_system_guidance(),
)
)