mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-12 00:36:03 +00:00
feat(box): add host workspace mounting and sandbox_exec guidance
This commit is contained in:
@@ -29,7 +29,13 @@ 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.'
|
||||
'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.'
|
||||
)
|
||||
|
||||
|
||||
@@ -37,6 +43,15 @@ SANDBOX_EXEC_SYSTEM_GUIDANCE = (
|
||||
class LocalAgentRunner(runner.RequestRunner):
|
||||
"""Local agent request runner"""
|
||||
|
||||
def _build_sandbox_system_guidance(self) -> str:
|
||||
guidance = SANDBOX_EXEC_SYSTEM_GUIDANCE
|
||||
default_host_workspace = str(
|
||||
getattr(getattr(self.ap, 'instance_config', None), 'data', {}).get('box', {}).get('default_host_workspace', '')
|
||||
).strip()
|
||||
if default_host_workspace:
|
||||
guidance = f'{guidance} {SANDBOX_EXEC_WORKSPACE_GUIDANCE}'
|
||||
return guidance
|
||||
|
||||
def _build_request_messages(
|
||||
self,
|
||||
query: pipeline_query.Query,
|
||||
@@ -48,7 +63,7 @@ class LocalAgentRunner(runner.RequestRunner):
|
||||
req_messages.append(
|
||||
provider_message.Message(
|
||||
role='system',
|
||||
content=SANDBOX_EXEC_SYSTEM_GUIDANCE,
|
||||
content=self._build_sandbox_system_guidance(),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
import langbot_plugin.api.entities.builtin.resource.tool as resource_tool
|
||||
from langbot_plugin.api.entities.events import pipeline_query
|
||||
|
||||
@@ -18,6 +20,11 @@ class NativeToolLoader(loader.ToolLoader):
|
||||
async def invoke_tool(self, name: str, parameters: dict, query: pipeline_query.Query):
|
||||
if name != self.SANDBOX_EXEC_TOOL_NAME:
|
||||
raise ValueError(f'未找到工具: {name}')
|
||||
self.ap.logger.info(
|
||||
'sandbox_exec tool invoked: '
|
||||
f'query_id={query.query_id} '
|
||||
f'parameters={json.dumps(self._summarize_parameters(parameters), ensure_ascii=False)}'
|
||||
)
|
||||
return await self.ap.box_service.execute_sandbox_tool(parameters, query)
|
||||
|
||||
async def shutdown(self):
|
||||
@@ -61,6 +68,19 @@ class NativeToolLoader(loader.ToolLoader):
|
||||
'type': 'string',
|
||||
'description': 'Optional sandbox session id. Defaults to the current request id for reuse.',
|
||||
},
|
||||
'host_path': {
|
||||
'type': 'string',
|
||||
'description': (
|
||||
'Optional absolute host directory path to mount into the sandbox as /workspace. '
|
||||
'The path must be under an allowed host mount root.'
|
||||
),
|
||||
},
|
||||
'host_path_mode': {
|
||||
'type': 'string',
|
||||
'description': 'Mount mode for host_path. Use rw to create or modify host files.',
|
||||
'enum': ['ro', 'rw'],
|
||||
'default': 'rw',
|
||||
},
|
||||
'env': {
|
||||
'type': 'object',
|
||||
'description': 'Optional environment variables to expose inside the sandbox.',
|
||||
@@ -73,3 +93,17 @@ class NativeToolLoader(loader.ToolLoader):
|
||||
},
|
||||
func=lambda parameters: parameters,
|
||||
)
|
||||
|
||||
def _summarize_parameters(self, parameters: dict) -> dict:
|
||||
summary = dict(parameters)
|
||||
cmd = str(summary.get('cmd', '')).strip()
|
||||
if len(cmd) > 400:
|
||||
cmd = f'{cmd[:397]}...'
|
||||
summary['cmd'] = cmd
|
||||
|
||||
env = summary.get('env')
|
||||
if isinstance(env, dict):
|
||||
summary['env_keys'] = sorted(str(key) for key in env.keys())
|
||||
del summary['env']
|
||||
|
||||
return summary
|
||||
|
||||
Reference in New Issue
Block a user