fix: suppress runtime context in minimal profiles

This commit is contained in:
Yichen Jiang
2026-08-12 23:28:15 +08:00
parent c4e24071d6
commit ece8645080
41 changed files with 400 additions and 233 deletions

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 packages/preset/persona/README.md
README.md: 742141e65fa8d50b89e6b74e6d21aa8c5bfe98cd
README.zh.md: 61112d1091e428d8c92aa056b7aaa272d3bbbc1d
README.md: 978d01ddbd52095bc2486d27d08fde2d4a8fa79b
README.zh.md: d36af6c028f1258d044608535c6da4eaf2fb92e8

View File

@@ -16,8 +16,9 @@ Mounting this row outside an agent scope collides with the registry's own `deplo
|---|---|---|
| `text` | required | Persona prose rendered as the `deployment:persona` section |
| `complete` | `false` | Restore this persona after assembly as the only system-prompt section |
| `includeRuntimeContext` | `true` | Include dynamic runtime-context snapshots for this agent scope; false suppresses every context contribution without disabling its owning services |
`text` is a template, like any prompt section: complete `{{…}}` groups resolve strictly against registered prompt variables when the prompt renders, not when it assembles. Empty text still occupies the slot, so it shadows the deployment persona away entirely and then disappears at render. With `complete: true`, assembly still resolves contexts, tools, variables, and cooperative listeners, then the prompt registry restores this exact persona as the sole section; no identity, tool guidance, or listener can append prompt text.
`text` is a template, like any prompt section: complete `{{…}}` groups resolve strictly against registered prompt variables when the prompt renders, not when it assembles. Empty text still occupies the slot, so it shadows the deployment persona away entirely and then disappears at render. With `complete: true`, assembly still resolves contexts, tools, variables, and cooperative listeners, then the prompt registry restores this exact persona as the sole section; no identity, tool guidance, or listener can append prompt text. With `includeRuntimeContext: false`, context providers are not evaluated for this scope and contexts added by assembly listeners are discarded.
## Model Experience
@@ -25,7 +26,7 @@ Mounting this row outside an agent scope collides with the registry's own `deplo
#### What the model sees
The `deployment:persona` section at order 0, immediately after the harness identity opener, carrying exactly this row's configured `text` with prompt variables resolved. For an agent whose preset mounts this row, it replaces whatever persona the deployment configured. In complete mode, the model sees only this rendered section as its system prompt.
The `deployment:persona` section at order 0, immediately after the harness identity opener, carrying exactly this row's configured `text` with prompt variables resolved. For an agent whose preset mounts this row, it replaces whatever persona the deployment configured. In complete mode, the model sees only this rendered section as its system prompt. Runtime context remains enabled by default. When disabled, a fresh agent receives no runtime-context snapshot from sandbox policy, approval policy, delegation, or another system-prompt context provider.
#### Token effect

View File

@@ -16,8 +16,9 @@
|---|---|---|
| `text` | 必填 | 作为 `deployment:persona` 段落渲染的人设文本 |
| `complete` | `false` | 组装后将此人设恢复为唯一的系统提示词段落 |
| `includeRuntimeContext` | `true` | 是否为此 agent 作用域包含动态 runtime-context 快照;false 会抑制所有上下文贡献,但不禁用拥有它们的服务 |
`text` 与任何提示词段落一样是模板:完整的 `{{…}}` 组在提示词**渲染**时(而非组装时)严格解析为已注册的提示词变量。空文本同样占据该槽位,因此会把部署级人设整个遮蔽掉,然后在渲染时消失。启用 `complete: true` 时,组装仍会解析上下文、工具、变量和协作式监听器,之后提示词注册表将这份确切人设恢复为唯一段落;身份、工具引导或监听器都无法追加提示词文本。
`text` 与任何提示词段落一样是模板:完整的 `{{…}}` 组在提示词**渲染**时(而非组装时)严格解析为已注册的提示词变量。空文本同样占据该槽位,因此会把部署级人设整个遮蔽掉,然后在渲染时消失。启用 `complete: true` 时,组装仍会解析上下文、工具、变量和协作式监听器,之后提示词注册表将这份确切人设恢复为唯一段落;身份、工具引导或监听器都无法追加提示词文本。启用 `includeRuntimeContext: false` 时,此作用域的上下文提供方不会被求值,组装监听器添加的上下文也会被丢弃。
## 模型体验
@@ -25,7 +26,7 @@
#### What the model sees
位于 order 0 的 `deployment:persona` 段落,紧随 harness 身份开场白之后,携带本行配置的 `text`,其中的提示词变量已解析。对于其 preset 挂载了本行的 agent,它会替换部署所配置的任何人设。在完整模式下,模型只会看到这个渲染后的段落作为系统提示词。
位于 order 0 的 `deployment:persona` 段落,紧随 harness 身份开场白之后,携带本行配置的 `text`,其中的提示词变量已解析。对于其 preset 挂载了本行的 agent,它会替换部署所配置的任何人设。在完整模式下,模型只会看到这个渲染后的段落作为系统提示词。Runtime context 默认保持启用。禁用后,新建 agent 不会收到来自沙箱策略、批准策略、委派或其他 system-prompt 上下文提供方的 runtime-context 快照。
#### Token effect

View File

@@ -40,12 +40,15 @@ export interface Config {
text: string
/** Make this persona the complete system prompt, suppressing every other section. */
complete?: boolean
/** Suppress dynamic runtime-context snapshots for this persona's agent scope. */
includeRuntimeContext?: boolean
}
/** Runtime schema for the persona row. */
export const Config: z<Config> = z.object({
text: z.string().required(),
complete: z.boolean().default(false),
includeRuntimeContext: z.boolean().default(true),
})
/**
@@ -61,4 +64,5 @@ export function apply(ctx: Context, config: Config): void {
text: config.text,
...(config.complete ? { complete: true } : {}),
}), 'persona.section()')
if (!(config.includeRuntimeContext ?? true)) ctx.systemPrompt.suppressRuntimeContext()
}

View File

@@ -102,4 +102,41 @@ describe('the persona row', () => {
expect(assembly.sections).toEqual([{ name: PERSONA_SECTION, text: 'Only this.' }])
expect(renderPrompt(assembly)).toBe('Only this.')
})
it('can suppress runtime context for its scope without changing the global assembly', async () => {
const ctx = await harness('deployment identity')
const key: ScopeKey = { agent: 'a1' }
const scope = createScope(ctx, key)
ctx.systemPrompt.context({ name: 'policy', order: 1, text: 'global policy' })
const fiber = await scope.ctx.plugin(Persona, {
text: 'Only this.',
includeRuntimeContext: false,
})
const suppressed = await ctx.systemPrompt.assemble({ scope: key })
expect(suppressed.contexts).toEqual([])
const global = await ctx.systemPrompt.assemble()
expect(global.contexts).toEqual([
{ name: 'policy', text: 'global policy' },
])
await fiber.dispose()
expect((await ctx.systemPrompt.assemble({ scope: key })).contexts).toEqual([
{ name: 'policy', text: 'global policy' },
])
})
it('keeps runtime context by default when apply bypasses schema defaults', async () => {
const ctx = await harness('deployment identity')
const key: ScopeKey = { agent: 'a1' }
ctx.systemPrompt.context({ name: 'policy', order: 1, text: 'global policy' })
await ctx.plugin(Object.assign((inner: Context) => {
Persona.apply(createScope(inner, key).ctx, { text: 'Scoped identity.' })
}, { inject: ['systemPrompt'] }))
expect((await ctx.systemPrompt.assemble({ scope: key })).contexts).toEqual([
{ name: 'policy', text: 'global policy' },
])
})
})