From 086d00c31760044cf316a43b2d9112f8d72e1084 Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Tue, 27 Oct 2026 18:44:42 +0000 Subject: [PATCH] Choose network access in Parsar environment templates --- example/parsar/README.md | 2 +- example/parsar/README.zh.md | 2 +- example/parsar/server/runtime-profile.mjs | 16 ++++++++ example/parsar/src/EnvironmentFields.tsx | 49 +++++++++++++++++++++++ example/parsar/src/lib/product.ts | 1 + example/parsar/tests/product.test.mjs | 26 ++++++++++++ 6 files changed, 94 insertions(+), 2 deletions(-) diff --git a/example/parsar/README.md b/example/parsar/README.md index 80ad30f2b..9872c5b8a 100644 --- a/example/parsar/README.md +++ b/example/parsar/README.md @@ -22,7 +22,7 @@ Open http://127.0.0.1:18180. `OPENAI_BASE_URL` ends in `/v1`; remote endpoints r | Object | What it is | | --- | --- | | **资源库** | Building blocks, grouped by what uses them: models for Agent engines; Skills, MCP servers, Plugins, knowledge and instruction fragments for Agents; credentials for MCP. Resources are shared: editing one affects everything that uses it, and an item in use cannot be removed. | -| **环境模板** | The prepared workspace: npm and Python packages, a Bash setup script, environment variables, Feishu bot variables and initial files. | +| **环境模板** | The prepared workspace: npm and Python packages, a Bash setup script, network access (allowed, blocked or limited to listed domains), environment variables, Feishu bot variables and initial files. | | **Agent** | What people talk to: name, description, instructions, how it runs, one required environment template, capabilities and behavior switches. How it runs mirrors a local Codex configuration: Harness, model, reasoning effort, web search and, under **高级**, reasoning summary, verbosity and service tier. **复制** creates an independent copy. | | **飞书机器人** | One bot is bound to at most one Agent. It routes its chats to that Agent and is the Agent’s Feishu identity in every conversation, including Web chats. | | **对话** | One public Core Session with its own Environment. It freezes the Agent and environment configuration when it starts. | diff --git a/example/parsar/README.zh.md b/example/parsar/README.zh.md index 78b21334a..c0505f0e3 100644 --- a/example/parsar/README.zh.md +++ b/example/parsar/README.zh.md @@ -27,7 +27,7 @@ pnpm --filter @oac/parsar-example dev | 对象 | 含义 | | --- | --- | | **资源库** | 组装用的零件,按使用方分组:模型供 Agent 的执行引擎使用;Skills、MCP 服务、Plugins、知识和指令片段供 Agent 使用;凭据供 MCP 使用。资源是共享的:修改一项会影响所有使用它的对象,正在使用的条目不能移除。 | -| **环境模板** | 准备好的工作区:npm 与 Python 软件包、Bash 初始化脚本、环境变量、飞书机器人变量和初始文件。 | +| **环境模板** | 准备好的工作区:npm 与 Python 软件包、Bash 初始化脚本、联网权限(允许、禁止或仅允许指定域名)、环境变量、飞书机器人变量和初始文件。 | | **Agent** | 用户对话的对象:名称、描述、指令、运行方式、一个必选的环境模板、能力和行为开关。运行方式对应本地 Codex 的配置:Harness、模型、推理强度、网页搜索,以及 **高级** 中的推理摘要、输出详细度和服务层级。**复制**会生成一份独立副本。 | | **飞书机器人** | 一个机器人最多绑定一个 Agent。它把自己的聊天路由给该 Agent,并在所有对话中(包括网页对话)作为该 Agent 的飞书身份。 | | **对话** | 一个公开 Core Session,拥有独立的 Environment,在开始时冻结 Agent 和环境配置。 | diff --git a/example/parsar/server/runtime-profile.mjs b/example/parsar/server/runtime-profile.mjs index bfcbc2d4f..50d200a41 100644 --- a/example/parsar/server/runtime-profile.mjs +++ b/example/parsar/server/runtime-profile.mjs @@ -29,6 +29,20 @@ export function runtimeProfile(body, previous) { Object.keys(body.packages).some((k) => !["npm", "python"].includes(k)) ) throw new AppError(400, "环境模板支持 npm 和 Python 软件包。"); + // Core validates the domains; Parsar only maps the choice. + const access = body.network?.access; + let network; + if (access === "disabled") network = { access }; + else if (access === "restricted") { + const domains = body.network.allowed_domains; + if (!Array.isArray(domains) || domains.some((d) => typeof d !== "string")) + throw new AppError(400, "请填写允许访问的域名,每行一个。"); + network = { + access, + allowed_domains: domains.map((d) => d.trim()).filter(Boolean), + }; + } else if (access !== undefined && access !== "enabled") + throw new AppError(400, "网络设置无效。"); const env = Object.create(null); const input = body.env === undefined ? previous?.env || {} : body.env; if ( @@ -94,6 +108,7 @@ export function runtimeProfile(body, previous) { description: text(body.description || "", "说明", 1000), packages, setup_script: text(body.setup_script || "", "初始化脚本", 100000), + ...(network && { network }), env, bot_env, files: normalized, @@ -114,6 +129,7 @@ export function runtimeEnvironment(runtime) { return { type: "openai_hosted", packages: runtime.packages || { npm: [], python: [] }, + ...(runtime.network && { network: runtime.network }), env: { ...runtime.env }, setup_commands: runtime.setup_script ? [{ command: runtime.setup_script, cwd: "/workspace" }] diff --git a/example/parsar/src/EnvironmentFields.tsx b/example/parsar/src/EnvironmentFields.tsx index 0ead69047..d94a35024 100644 --- a/example/parsar/src/EnvironmentFields.tsx +++ b/example/parsar/src/EnvironmentFields.tsx @@ -99,6 +99,54 @@ export function EnvironmentFields({ )} /> + + + + {value.network?.access === "restricted" && ( + +