fix(web): align core profile with RL prompt

This commit is contained in:
Yichen Jiang
2026-08-06 19:52:08 +08:00
parent 6afca00a77
commit 0cf1ba7f87
17 changed files with 118 additions and 40 deletions

View File

@@ -1,6 +1,26 @@
# Opt-in two-tool profile over the shipped Web composition. The default native
# model surface is exactly persistent `bash` plus `str_replace_editor`; the
# Web host, browser shell, workspace, persistence, and permission stack remain.
# Opt-in Web shell for the RL core agent contract. The model receives exactly
# the configured persona plus the native `bash` and `str_replace_editor`
# schemas; the Web host, browser shell, persistence, and permission stack stay.
# Match the Claude SWE-compatible RL core prompt. The launcher-owned Web
# orientation is a separate plugin so disabling it removes both its prompt
# sections without a path-specific launcher branch. Workspace instructions are
# model-visible user context rather than a system section, but RL core disables
# them as part of the same prompt contract.
- id: system-prompt
config:
includeHarnessIdentity: false
persona: !!js process.env.DSH_SYSTEM_PROMPT ?? 'You are a helpful software engineer assistant.'
- id: web-runtime-context
disabled: true
- id: workspace-context
disabled: true
- id: tools
config:
mode: native
# Disable every model-facing consumer in the base/Web tree. plan-mode owns the
# always-registered exit_plan_mode tool even while the session is not planning.

View File

@@ -46,6 +46,12 @@
# `dshClient` rows are the browser roster the modules node half scans into
# window.__DSH_BOOT__; the modules row is simultaneously a host row.
- insert:
# Launcher-provided builtin: owns Web GUI orientation in the model prompt
# and the matching managed Bash variables. Profiles with a complete prompt
# contract disable this row instead of relying on launcher special cases.
- id: web-runtime-context
name: cordis:web-runtime-context
- id: session-projection
name: '@deepseek-ai/dsh-session-projection'

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write apps/cli/reference/README.md
README.md: b37ec9ed61ea4e9899a51316065d4188f30997ad
README.zh.md: ca29808a6c8e670f0d0b82c59b1a2c1fa0e13565
README.md: 0b6c4d0ad854fb6fa0428f6a1cb2db8d91017f27
README.zh.md: ebd055c949827eb58696e90aea94a111a543586e

View File

@@ -55,7 +55,7 @@ Both modes treat the invoking directory as the default workspace root, load appl
New sessions default to the `workspace-write` permission preset. Bash and filesystem mutations are restricted to the session workspace and platform temporary roots; reads, network access, and process visibility are not confined. `DSH_PERMISSION_MODE` changes the process fallback. Stored General-settings permissions affect later Web sessions, not an already-open one.
`DSH_TOOLS_MODE` selects `native`, `code`, or `both` for the Web/headless process; another value fails at boot. [`config/core-web.cordis.yml`](../config/core-web.cordis.yml) is an optional Web overlay that reduces the native model surface to persistent `bash` and `str_replace_editor` while retaining the shipped host, browser, workspace, persistence, and permission composition.
`DSH_TOOLS_MODE` selects `native`, `code`, or `both` for the ordinary Web/headless process; another value fails at boot. [`config/core-web.cordis.yml`](../config/core-web.cordis.yml) is an optional RL-compatible Web overlay that pins native mode, renders only `DSH_SYSTEM_PROMPT` or `You are a helpful software engineer assistant.` as the system prompt, disables Workspace instructions and Web runtime prompt context, and exposes only persistent `bash` and `str_replace_editor` while retaining the shipped host, browser, workspace, persistence, and permission composition.
## Shared deployment behavior

View File

@@ -55,7 +55,7 @@ Web 和无头进程关闭时会给插件树最多 5 秒完成 dispose。第一
新会话默认使用 `workspace-write` 权限预设。Bash 和文件系统修改仅限于会话 workspace 与平台临时根目录;读取、网络访问和进程可见性不受限制。`DSH_PERMISSION_MODE` 更改进程后备值。General settings 中存储的权限影响后续 Web 会话,不改变已打开的会话。
`DSH_TOOLS_MODE` 为 Web无头进程选择 `native``code``both`;其他值会导致启动失败。[`config/core-web.cordis.yml`](../config/core-web.cordis.yml) 是可选 Web overlay它在保留随附宿主、浏览器、workspace、持久化和权限组合的同时把原生模型 surface 缩减为持久 `bash``str_replace_editor`
`DSH_TOOLS_MODE`常规 Web无头进程选择 `native``code``both`;其他值会导致启动失败。[`config/core-web.cordis.yml`](../config/core-web.cordis.yml) 是可选的 RL 兼容 Web overlay固定使用原生模式,仅将 `DSH_SYSTEM_PROMPT``You are a helpful software engineer assistant.` 渲染为系统提示词,禁用 Workspace 指令与 Web 运行时提示词上下文,并且在保留随附宿主、浏览器、workspace、持久化和权限组合的同时仅暴露持久 `bash``str_replace_editor`
## 共享部署行为

View File

@@ -22,6 +22,7 @@ const SOURCE_ROOT = fileURLToPath(new URL('../../..', import.meta.url))
const DSH_WEB_URL = 'DSH_WEB_URL' as const
const DSH_WEB_MODE = 'DSH_WEB_MODE' as const
const WEB_RUNTIME_CONTEXT_BUILTIN = 'web-runtime-context' as const
type WebMode = 'production' | 'development'
@@ -53,16 +54,8 @@ function localWebUrl(ctx: Context): string {
return `http://${LOOPBACK_HOST}:${String(port)}`
}
/**
* Register the launcher-owned prompt and shell runtime context before the
* shared config tree mounts. The earlier injections install the prompt
* sections and managed Bash contributor when their owning services activate;
* dynamic values read the bound server only when consumed.
* @param ctx - Web root context with Loader installed but no config tree mounted.
* @param sourceRoot - absolute checkout root resolved from the launcher module.
* @param mode - whether this process mounted the client-plugin HMR receiver.
*/
export function prepareWebRuntimeContext(ctx: Context, sourceRoot: string, mode: WebMode): void {
/** Register the model-facing Web orientation and its matching shell variables. */
function applyWebRuntimeContext(ctx: Context, sourceRoot: string, mode: WebMode): void {
ctx.inject(['systemPrompt'], (promptCtx) => {
addHarnessSourceSection(promptCtx, sourceRoot)
promptCtx.systemPrompt.section({
@@ -83,6 +76,31 @@ export function prepareWebRuntimeContext(ctx: Context, sourceRoot: string, mode:
})
}
/**
* Register the launcher-owned runtime-context builtin before the config tree
* mounts. The Web overlay decides whether to mount it, so profiles that own
* their complete model prompt can disable the contribution without changing
* launcher control flow. Dynamic values read the bound server only when used.
* @param ctx - Web root context with Loader installed but no config tree mounted.
* @param sourceRoot - absolute checkout root resolved from the launcher module.
* @param mode - whether this process mounted the client-plugin HMR receiver.
*/
export function prepareWebRuntimeContext(ctx: Context, sourceRoot: string, mode: WebMode): void {
const { builtins } = ctx.loader
if (builtins[WEB_RUNTIME_CONTEXT_BUILTIN] !== undefined) {
throw new Error(`dsh web: Loader builtin "${WEB_RUNTIME_CONTEXT_BUILTIN}" is already registered`)
}
const plugin = (runtimeCtx: Context): void => {
applyWebRuntimeContext(runtimeCtx, sourceRoot, mode)
}
builtins[WEB_RUNTIME_CONTEXT_BUILTIN] = plugin
ctx.effect(() => () => {
if (builtins[WEB_RUNTIME_CONTEXT_BUILTIN] === plugin) {
Reflect.deleteProperty(builtins, WEB_RUNTIME_CONTEXT_BUILTIN)
}
}, 'dsh web runtime-context builtin')
}
/**
* Serve the browser UI from the shipped config tree. `host`/`port` are passed
* through only when the flag was given; absent, the shipped Web overlay value stands.

View File

@@ -1,18 +1,26 @@
import { sep } from 'node:path'
import { Context } from 'cordis'
import { describe, expect, it } from 'vitest'
import Loader from '@cordisjs/plugin-loader'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import { HARNESS_SOURCE_SECTION } from '@deepseek-ai/dsh-app-boot'
import type {} from '@deepseek-ai/dsh-host-webserver'
import { prepareWebRuntimeContext } from '../src/web.ts'
describe('prepareWebRuntimeContext', () => {
it('installs both sections before a later systemPrompt consumer activates', async () => {
it('registers the config-tree builtin that installs both prompt sections', async () => {
const ctx = new Context()
const sourceRoot = `${sep}opt${sep}harness-src`
let observedSections: { name: string; text: string }[] | undefined
try {
await ctx.plugin(Loader)
prepareWebRuntimeContext(ctx, sourceRoot, 'production')
expect(() => {
prepareWebRuntimeContext(ctx, sourceRoot, 'production')
}).toThrow(
'Loader builtin "web-runtime-context" is already registered',
)
await ctx.loader.create({ name: 'cordis:web-runtime-context' })
ctx.provide('httpServer', { port: 3080 } as Context['httpServer'])
const consumer = ctx.inject(['systemPrompt'], async (promptCtx) => {
const assembly = await promptCtx.systemPrompt.assemble()