Conversation
* cloud doc * doc refactor * doc move * seo * remove doc * yml * doc * fix: tsconfig * fix: tsconfig
* sandbox version * add sandbox log * update lock * fix * fix: sandbox * doc * add console * i18n
Preview sandbox Image: |
Preview mcp_server Image: |
There was a problem hiding this comment.
Pull request overview
This PR introduces an “Agent sandbox” (per-chat Linux sandbox) integration across service, API, and web UI, enabling sandbox-backed tool execution (sandbox_shell) and user-facing sandbox file management (list/read/write/download), plus lifecycle cleanup and cron-based suspension.
Changes:
- Add service-side sandbox persistence + lifecycle management (Mongo schema, controller, cron suspend, deletion hooks on chat/app delete).
- Inject sandbox tool + prompts into ToolCall/Agent dispatch paths and propagate
useComputerthrough workflow/app forms. - Add web UI entry points + APIs for sandbox file browsing/editing/downloading, plus new icons and i18n strings.
Reviewed changes
Copilot reviewed 79 out of 102 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| test/setup.ts | Adjusts test DB cleanup behavior for Mongo connections. |
| test/cases/service/core/ai/sandbox/sandbox.integration.test.ts | Adds env-gated integration tests for sandbox exec/FS/state/concurrency. |
| test/cases/service/core/ai/sandbox/controller.test.ts | Adds unit tests for sandbox deletion helpers and inactivity query logic (mocked adapter). |
| test/cases/service/core/ai/sandbox/constants.test.ts | Adds tests for deterministic sandbox ID generation. |
| test/cases/global/core/chat/utils.test.ts | Updates expectations to match new chat statistical fields behavior. |
| projects/app/src/web/core/workflow/utils.ts | Updates workflow validation to account for useComputer when tools aren’t connected. |
| projects/app/src/service/common/system/index.ts | Exposes show_agent_sandbox flag in system config based on env. |
| projects/app/src/service/common/system/cron.ts | Registers sandbox cron job in app cron startup. |
| projects/app/src/pages/api/core/chat/history/batchDelete.ts | Deletes sandboxes when chats are batch-deleted. |
| projects/app/src/pages/api/core/ai/sandbox/file.ts | Adds sandbox file list/read/write API endpoint. |
| projects/app/src/pages/api/core/ai/sandbox/download.ts | Adds sandbox file/directory download endpoint (zip for directories). |
| projects/app/src/pages/api/core/ai/sandbox/checkExist.ts | Adds API to check if a sandbox exists for a chat. |
| projects/app/src/pageComponents/chat/ToolMenu.tsx | Adds sandbox entry icon/menu integration for chat UI. |
| projects/app/src/pageComponents/chat/SandboxEditor/utils.tsx | Adds helpers for file icons + language detection by extension. |
| projects/app/src/pageComponents/chat/SandboxEditor/modal.tsx | Adds modal wrapper for sandbox editor UI. |
| projects/app/src/pageComponents/chat/SandboxEditor/hook.tsx | Adds hook handling sandbox existence polling + modal state. |
| projects/app/src/pageComponents/chat/SandboxEditor/api.ts | Adds client API helpers for sandbox file ops/download/checkExist. |
| projects/app/src/pageComponents/chat/ChatHeader.tsx | Removes unused usePathname import. |
| projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/ChatTest.tsx | Adds sandbox entry + modal in workflow test chat UI. |
| projects/app/src/pageComponents/app/detail/Logs/DetailLogsModal.tsx | Adds sandbox entry + modal in logs detail modal UI, updates close button. |
| projects/app/src/pageComponents/app/detail/Edit/SimpleApp/utils.ts | Persists useComputer into workflow and uses tool template when enabled. |
| projects/app/src/pageComponents/app/detail/Edit/SimpleApp/EditForm.tsx | Adds “Use Computer” (sandbox) switch to SimpleApp edit form. |
| projects/app/src/pageComponents/app/detail/Edit/SimpleApp/ChatTest.tsx | Adds sandbox entry + modal to SimpleApp test chat. |
| projects/app/src/pageComponents/app/detail/Edit/ChatAgent/utils.ts | Persists useComputer into agent workflow inputs. |
| projects/app/src/pageComponents/app/detail/Edit/ChatAgent/EditForm.tsx | Adds “Use Computer” (sandbox) switch to ChatAgent edit form. |
| projects/app/src/pageComponents/app/detail/Edit/ChatAgent/ChatTest.tsx | Adds sandbox entry + modal to ChatAgent test chat. |
| projects/app/src/global/core/chat/utils.ts | Adds useComputer response tagging derived from sandbox tool usage; deprecates old fields. |
| projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ResponseTags.tsx | Replaces contextual preview tags with sandbox files tag + modal integration. |
| projects/app/src/components/core/chat/ChatContainer/ChatBox/components/ContextModal.tsx | Removes contextual preview modal implementation. |
| projects/app/package.json | Increases dev memory limit; adds archiver and Monaco dependency. |
| projects/app/.env.template | Adds sandbox-related env vars. |
| packages/web/package.json | Bumps @monaco-editor/react version. |
| packages/web/i18n/zh-Hant/chat.json | Updates/extends chat translations for sandbox UI. |
| packages/web/i18n/zh-Hant/app.json | Adds app translations for sandbox UI and use_computer. |
| packages/web/i18n/zh-CN/chat.json | Updates/extends chat translations for sandbox UI. |
| packages/web/i18n/zh-CN/app.json | Adds app translations for sandbox UI and editor strings. |
| packages/web/i18n/en/chat.json | Updates/extends chat translations for sandbox UI. |
| packages/web/i18n/en/app.json | Adds app translations for sandbox UI and use_computer. |
| packages/web/components/v2/common/MyModal/index.tsx | Adds a v2 modal implementation used by sandbox editor modal. |
| packages/web/components/common/Icon/icons/core/app/sandbox/zip.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/yml.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/xlsx.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/video.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/txt.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/svg.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/scss.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/sandbox.svg | Adds sandbox main icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/py.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/pptx.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/pdf.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/md.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/js.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/java.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/image.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/html.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/go.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/file.svg | Adds sandbox file icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/docx.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/default.svg | Adds sandbox default file icon. |
| packages/web/components/common/Icon/icons/core/app/sandbox/css.svg | Adds sandbox file-type icon. |
| packages/web/components/common/Icon/icons/common/downloadLine.svg | Updates download icon asset. |
| packages/web/components/common/Icon/constants.ts | Registers new sandbox icon paths. |
| packages/service/package.json | Adds sandbox adapter dependency; reorganizes json-schema-ref-parser entry. |
| packages/service/env.ts | Adds sandbox env schema fields. |
| packages/service/core/workflow/dispatch/ai/tool/type.ts | Adds useComputer to tool dispatch props and introduces ChildResponseItemType. |
| packages/service/core/workflow/dispatch/ai/tool/toolCall.ts | Injects sandbox tool/prompt and handles sandbox tool calls in ToolCall flow. |
| packages/service/core/workflow/dispatch/ai/tool/index.ts | Plumbs useComputer into tool-call execution path. |
| packages/service/core/workflow/dispatch/ai/tool/constants.ts | Adds helper to format sandbox tool workflow responses. |
| packages/service/core/workflow/dispatch/ai/agent/utils.ts | Injects sandbox tools for agent mode when useComputer is enabled. |
| packages/service/core/workflow/dispatch/ai/agent/sub/sandbox/index.ts | Adds agent sub-dispatcher for sandbox shell execution. |
| packages/service/core/workflow/dispatch/ai/agent/master/prompt.ts | Adds sandbox environment prompt injection for master agent. |
| packages/service/core/workflow/dispatch/ai/agent/master/call.ts | Handles sandbox tool calls in master agent dispatch flow. |
| packages/service/core/workflow/dispatch/ai/agent/index.ts | Plumbs useComputer into agent dispatch and tool injection. |
| packages/service/core/app/controller.ts | Deletes sandboxes when an app is deleted. |
| packages/service/core/ai/sandbox/type.ts | Adds Zod schema/type for sandbox instance records. |
| packages/service/core/ai/sandbox/schema.ts | Adds Mongo model + indexes for sandbox instances. |
| packages/service/core/ai/sandbox/index.ts | Re-exports sandbox adapter interface type. |
| packages/service/core/ai/sandbox/controller.ts | Implements sandbox instance wrapper + deletion helpers + cron job. |
| packages/service/core/ai/llm/compress/index.ts | Downgrades tool-response compression log to debug level. |
| packages/service/common/logger/categories.ts | Adds sandbox logging category. |
| packages/global/openapi/tag.ts | Adds OpenAPI tag for sandbox. |
| packages/global/openapi/index.ts | Adds sandbox tag into AI group. |
| packages/global/openapi/core/ai/sandbox/index.ts | Adds OpenAPI paths for sandbox file/check/download. |
| packages/global/openapi/core/ai/sandbox/api.ts | Adds request/response schemas for sandbox APIs. |
| packages/global/openapi/core/ai/index.ts | Includes sandbox paths under AI OpenAPI. |
| packages/global/core/workflow/template/system/toolCall.ts | Adds useComputer switch input to ToolCall node template. |
| packages/global/core/workflow/runtime/type.ts | Adds toolId field to dispatch node response type. |
| packages/global/core/workflow/node/agent/constants.ts | Registers sandbox as a system sub-app/tool. |
| packages/global/core/workflow/constants.ts | Adds useComputer to workflow node input keys. |
| packages/global/core/chat/type.ts | Adds useComputer to response tag type; marks old fields deprecated. |
| packages/global/core/app/formEdit/type.ts | Adds useComputer to AI settings schema. |
| packages/global/core/ai/type.ts | Adjusts OpenAI re-exports ordering/types. |
| packages/global/core/ai/sandbox/constants.ts | Adds sandbox constants, tool schema, and prompt text. |
| packages/global/common/system/types/index.ts | Adds show_agent_sandbox to FE config type. |
| document/data/doc-last-modified.json | Updates doc modification map (currently contains conflict markers). |
| document/content/docs/openapi/chat.mdx | Updates docs to match response tag field changes. |
| document/content/docs/openapi/chat.en.mdx | Updates docs to match response tag field changes. |
| .claude/skills/design/core/ai/sandbox/technical-design.md | Adds internal technical design doc for sandbox integration. |
| .claude/skills/design/core/ai/sandbox/prd.md | Adds internal PRD doc for sandbox integration. |
| .claude/plan/phase5-agent-computer-use-todo.md | Adds internal TODO plan for agent computer-use support. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (2)
projects/app/src/pages/api/core/chat/history/batchDelete.ts:67
deleteSandboxesByChatIdsis awaited inside themongoSessionRuntransaction. This holds the Mongo transaction open while performing external sandbox deletion (network I/O) and S3 deletions, increasing the risk of transaction timeouts/locks. Additionally,deleteSandboxesByChatIdscan throw synchronously (e.g., sandbox env not configured, constructor throws), which would abort the chat deletion transaction. Move sandbox cleanup (and ideally S3 cleanup) outside the transaction and make it best-effort (catch/log) so history deletion isn't blocked.
test/setup.ts:61- Test Mongo connections are no longer closed:
afterAlldrops the DB but does notclose()the connections, which can leave open handles and cause Vitest to hang. Also, dropping the DB in bothafterAllandonTestFinishedduplicates work and increases test runtime. Consider restoring connection close inafterAll(and pick a single cleanup strategy: drop DB per-test or once per-suite).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| await Promise.allSettled( | ||
| instances.map((doc) => | ||
| new SandboxInstance({ | ||
| appId: doc.appId, | ||
| userId: doc.userId, | ||
| chatId: doc.chatId | ||
| }).delete() | ||
| ) | ||
| ); | ||
| }; | ||
| export const deleteSandboxesByAppId = async (appId: string) => { | ||
| const instances = await MongoSandboxInstance.find({ appId }).lean(); | ||
| if (!instances.length) return; | ||
|
|
||
| await Promise.allSettled( | ||
| instances.map((doc) => | ||
| new SandboxInstance({ | ||
| appId: doc.appId, | ||
| userId: doc.userId, | ||
| chatId: doc.chatId | ||
| }).delete() | ||
| ) | ||
| ); |
There was a problem hiding this comment.
deleteSandboxesByChatIds/deleteSandboxesByAppId constructs SandboxInstance for each record. If sandbox env vars are not configured, the SandboxInstance constructor throws synchronously, which will cause these cleanup functions to reject before reaching Promise.allSettled. Wrap per-instance construction in a try/catch (or early-return when sandbox is disabled) so cleanup is always best-effort and doesn't break chat/app deletion flows.
| async delete() { | ||
| await mongoSessionRun(async (session) => { | ||
| await MongoSandboxInstance.deleteOne({ sandboxId: this.sandboxId }, { session }); | ||
| await super.delete(); | ||
| }); | ||
| } | ||
|
|
||
| async stop() { | ||
| await mongoSessionRun(async (session) => { | ||
| await MongoSandboxInstance.updateOne( | ||
| { sandboxId: this.sandboxId }, | ||
| { $set: { status: SandboxStatusEnum.stoped } }, | ||
| { session } | ||
| ); | ||
| await super.stop(); | ||
| }); | ||
| } |
There was a problem hiding this comment.
delete()/stop() wrap external adapter calls (super.delete()/super.stop()) inside mongoSessionRun. Mongo transactions can't include the external sandbox service call, so this keeps the DB transaction open across network I/O and can hit maxCommitTimeMS / increase lock time. Prefer updating the DB in a short transaction (or without one), and run the external call outside; if you need consistency, handle partial failures explicitly (e.g., retry queue).
| }; | ||
| }, [historyItem, isShowCite]); | ||
|
|
||
| console.log(useComputer, historyItem); |
There was a problem hiding this comment.
console.log(useComputer, historyItem) was left in the component, which will spam logs in production and may leak chat content to the browser console. Please remove this debug statement.
| icon: 'core/app/sandbox/file' as const, | ||
| label: t('chat:sandox.files'), | ||
| onClick: () => onOpenSandboxModal() |
There was a problem hiding this comment.
The i18n key chat:sandox.files appears to have a typo (sandox) and is inconsistent with other new keys like chat:sandbox_files. This makes translations harder to maintain and increases the chance of missing translations. Please rename to a consistently spelled key (and update the locale JSON accordingly).
| archive.on('error', (err) => { | ||
| throw err; | ||
| }); |
There was a problem hiding this comment.
Throwing inside archive.on('error', ...) won't be caught by the surrounding try/catch/await flow and can crash the Next.js server process. Handle the error by rejecting the request (set an HTTP error status, res.end()), and make sure the archive/response stream is properly terminated/aborted.
| if (result.error) { | ||
| return Promise.reject('Failed to read file'); | ||
| } | ||
|
|
||
| // 尝试将 Uint8Array 转换为 UTF-8 字符串 | ||
| try { | ||
| const decoder = new TextDecoder('utf-8', { fatal: true }); | ||
| const content = decoder.decode(result.content); | ||
| return { action: 'read', content }; | ||
| } catch (error) { | ||
| // 非 UTF-8 内容,返回特殊标记 | ||
| return { action: 'read', content: '[Binary File - Cannot Display]' }; | ||
| } | ||
| } | ||
|
|
||
| case 'write': { | ||
| const results = await sandbox.writeFiles([ | ||
| { | ||
| path: body.path, | ||
| data: body.content | ||
| } | ||
| ]); | ||
| const result = results[0]; | ||
|
|
||
| if (result.error) { | ||
| return Promise.reject('Failed to write file'); | ||
| } | ||
|
|
||
| return { action: 'write', success: true }; | ||
| } | ||
|
|
||
| default: | ||
| return Promise.reject('Invalid action'); | ||
| } |
There was a problem hiding this comment.
These branches use Promise.reject('...') with a string. The API layer will return a 500 with an unstructured error payload, and callers lose useful context. Prefer throwing an Error (or returning a typed error response) so error handling/logging is consistent and includes a message/stack.
|
|
||
| // 2. 删除聊天记录和S3文件 | ||
| // 删除沙盒实例 | ||
| await deleteSandboxesByAppId(appId); | ||
| await getS3ChatSource().deleteChatFilesByPrefix({ appId }); |
There was a problem hiding this comment.
deleteAppDataProcessor now awaits deleteSandboxesByAppId(appId). If sandbox is not configured or the downstream delete fails, this will throw and can prevent the rest of the app deletion cleanup from running. Sandbox cleanup should generally be best-effort here (catch/log and continue) so core deletion isn’t blocked by an optional integration.
| <<<<<<< HEAD | ||
| "document/content/docs/self-host/upgrading/4-14/4148.en.mdx": "2026-03-06T19:32:23+08:00", | ||
| "document/content/docs/self-host/upgrading/4-14/4148.mdx": "2026-03-09T12:04:22+08:00", | ||
| "document/content/docs/self-host/upgrading/4-14/41481.en.mdx": "2026-03-09T12:02:02+08:00", | ||
| "document/content/docs/self-host/upgrading/4-14/41481.mdx": "2026-03-09T14:24:27+08:00", | ||
| ======= | ||
| "document/content/docs/self-host/upgrading/4-14/4148.en.mdx": "2026-03-03T17:39:47+08:00", | ||
| <<<<<<< HEAD | ||
| "document/content/docs/self-host/upgrading/4-14/4148.mdx": "2026-03-04T18:18:14+08:00", | ||
| >>>>>>> b7d57cb9d (sandbox in chat window) | ||
| ======= | ||
| "document/content/docs/self-host/upgrading/4-14/4148.mdx": "2026-03-05T13:59:50+08:00", | ||
| >>>>>>> b9d4f061f (sandbox entry) |
There was a problem hiding this comment.
doc-last-modified.json still contains unresolved Git merge conflict markers (<<<<<<<, =======, >>>>>>>), which makes the JSON invalid and will break any tooling that reads this file. Resolve the conflict and ensure the final file is valid JSON.
| const { onOpenSandboxModal, SandboxEditorModal } = useSandboxEditor({ | ||
| appId, | ||
| chatId, | ||
| outLinkAuthData | ||
| }); |
There was a problem hiding this comment.
useSandboxEditor sets up a 10s polling interval (useInterval) to call /core/ai/sandbox/checkExist. ResponseTags is rendered per message, so this will create one interval per history item and can cause a large number of repeated network calls and timers. Consider only instantiating the hook when useComputer is true (and ideally at a higher level so it runs once per chat), or add an option to disable polling for this usage.
Preview fastgpt Image: |
No description provided.