2026-07-12 05:13:17 +08:00
# System Prompt Assembly
2026-07-15 23:11:25 -07:00
English | [中文 ](system-prompt.zh.md )
2026-08-09 15:27:21 +08:00
The [system-prompt package ](../../packages/core/system-prompt ) owns the data exchanged between prompt contributors and one assembly call. The package [README ](../../packages/core/system-prompt/README.md ) documents registration, ordering, scoping, and rendering behavior; this page records the exact cross-package types that plugins implement or pass.
2026-07-12 05:13:17 +08:00
Source: [`packages/core/system-prompt/src/index.ts` ](../../packages/core/system-prompt/src/index.ts ).
## Assembly context
2026-07-16 18:12:34 +08:00
`AssembleContext` identifies the scope layer one assembly resolves and may carry the explicit control signal for that request. It is merge-extensible: `dsh-agent` adds the optional live `agent` field, and `assembleContextFor(agent, signal)` sets the explicit fields together. A bare assembly has neither scope nor signal.
2026-07-12 05:13:17 +08:00
```ts type-equiv
2026-07-19 12:25:40 +08:00
/** Merge-extensible context for one prompt assembly. */
2026-07-12 05:13:17 +08:00
interface AssembleContext {
2026-07-19 12:25:40 +08:00
/**
* Scope whose providers and waterfall listeners participate. When absent,
* only global providers and subject-less listeners participate.
*/
2026-07-12 05:13:17 +08:00
scope?: ScopeKey
2026-07-20 21:38:49 +08:00
/** Explicit control signal for the turn that requested this assembly, when any. */
2026-07-16 18:12:34 +08:00
signal?: AbortSignal
2026-07-12 05:13:17 +08:00
}
```
## Tool-provider result
2026-07-13 13:09:41 +08:00
`ToolProviderResult.schemas` is the model-visible set for the current assembly. `knownNames` is the provider's pre-restriction name universe used to distinguish a configured-name typo from a known tool that is deliberately hidden in this scope.
2026-07-12 05:13:17 +08:00
```ts type-equiv
2026-07-19 12:25:40 +08:00
/** Tool schemas visible in one assembly and their pre-restriction name set. */
2026-07-12 05:13:17 +08:00
interface ToolProviderResult {
2026-07-19 12:25:40 +08:00
/** The schemas this provider contributes to THIS assembly. */
2026-07-12 22:49:46 +08:00
readonly schemas: readonly ToolSchema[]
2026-07-19 12:25:40 +08:00
/** The pre-restriction name universe for config validation (defaults to `schemas` ' names). */
2026-07-12 22:49:46 +08:00
readonly knownNames?: readonly string[]
2026-07-12 05:13:17 +08:00
}
```
2026-07-13 13:09:41 +08:00
## Prompt sections
2026-07-12 05:13:17 +08:00
2026-08-10 18:02:11 +08:00
`PromptSection` is a readonly same-process registration contract. Its text may be static or resolved from the current assembly context. One effective `complete` section becomes the sole prompt section after cooperative assembly.
2026-07-12 05:13:17 +08:00
```ts type-equiv
2026-07-19 12:25:40 +08:00
/** One contributed section of the system prompt (registry input). */
2026-07-12 22:49:46 +08:00
interface PromptSection {
2026-07-19 12:25:40 +08:00
/** Unique name — a duplicate registration throws (see {@link SystemPrompt.section}). */
2026-07-12 22:49:46 +08:00
readonly name: string
2026-07-19 12:25:40 +08:00
/**
* Sections are concatenated in ascending order. Convention: `-100` is the
* harness identity, `0` the deployment persona, tool guidance uses 100– 199;
* other negative orders also render before the persona.
*/
2026-07-12 22:49:46 +08:00
readonly order: number
2026-07-19 12:25:40 +08:00
/**
* Static text or a provider evaluated at each assembly with that assembly's
* {@link AssembleContext}. The text may reference `{{variable}}` s — they are
* interpolated later, by {@link renderPrompt}.
*/
2026-07-12 22:49:46 +08:00
readonly text: string | ((context: AssembleContext) => string)
2026-08-10 18:02:11 +08:00
/**
* Treat this contribution as the complete system prompt. Assembly still
* runs the cooperative waterfall so tools, contexts, and variables can be
* resolved, then restores this exact section as the sole prompt section.
* More than one effective complete section makes assembly fail.
*/
readonly complete?: boolean
2026-07-12 05:13:17 +08:00
}
```
2026-07-30 22:09:15 +08:00
## Dynamic prompt context
`PromptContext` is the cache-safe counterpart to `PromptSection` . The assembly resolves and orders these contributions, while agent-loop logs their complete current snapshot after retained model history only when it changed or compaction removed it.
```ts type-equiv
2026-08-03 12:25:33 +08:00
/** Dynamic model context materialized as a durable user-role snapshot. */
2026-07-30 22:09:15 +08:00
interface PromptContext {
/** Unique name — a duplicate registration throws (see {@link SystemPrompt.context}). */
readonly name: string
2026-08-03 12:25:33 +08:00
/** Contexts are joined in ascending order. */
2026-07-30 22:09:15 +08:00
readonly order: number
/** Static text or a provider evaluated for each assembly. Empty text contributes nothing. */
readonly text: string | ((context: AssembleContext) => string)
}
```
2026-07-30 21:40:58 +08:00
<!-- BEGIN GENERATED cordis - surface (gen - cordis - catalog.ts) — do not edit between markers -->
< a id = "cordis-surface" > < / a >
2026-07-24 19:54:25 +08:00
## Cordis API
2026-07-30 21:40:58 +08:00
2026-08-18 21:02:50 +08:00
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog` ) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer ](../cordis-primer.md#dispatch-modes ), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md ](../cordis-api/inherited.md ).
2026-07-30 21:40:58 +08:00
< a id = "ctxsystemprompt--systemprompt" > < / a >
### `ctx.systemPrompt` — `SystemPrompt`
Registry service for the prompt inputs assembled before each model step.
```ts cordis-catalog
/**
* Register an ordered prompt section in the calling context's scope. A scoped
* section shadows a global section with the same name; duplicates within one
* layer and non-finite orders throw. Registration and disposal emit
* `system-prompt/change` .
* @param section - the section to register.
* @returns the exact Cordis effect disposer.
*/
section(section: PromptSection): () => void
/**
* Register ordered dynamic context in the calling context's scope. Scoped
* entries shadow global entries with the same name.
* @param context - the context contribution to register.
* @returns the exact Cordis effect disposer.
*/
context(context: PromptContext): () => void
2026-08-12 23:28:15 +08:00
/**
* Suppress every dynamic runtime-context contribution in the calling
* context's scope without changing the services that own or enforce those
* facts. Multiple suppressors remain independently disposable.
* @returns the exact Cordis effect disposer.
*/
suppressRuntimeContext(): () => void
2026-07-30 21:40:58 +08:00
/**
* Register a tool-schema provider in the calling context's scope. Global and
* matching scoped providers both contribute; returning the reserved
* {@link TOOL_ORDER_REST} name makes assembly fail.
* @param provider - evaluated for each assembly with its context.
* @returns the exact Cordis effect disposer.
*/
tools(provider: (context: AssembleContext) => ToolProviderResult): () => void
/**
* Register a prompt variable in the calling context's scope. Scoped values
* shadow globals; invalid or duplicate names throw. A provider may return
* `undefined` , but rendering a section that references that value then fails.
* @param name - the `[a-z][a-z0-9_]*` reference name.
* @param provider - evaluated for each assembly.
* @returns the exact Cordis effect disposer.
*/
variable(name: string, provider: (context: AssembleContext) => string | undefined): () => void
/**
* Assemble global and scoped providers, detach tool parameters, apply
* canonical ordering, then run the assembly waterfall. Scoped sections and
2026-08-10 18:02:11 +08:00
* variables shadow globals. The returned waterfall value is authoritative
* except that an effective complete section is restored afterwards as the
* sole prompt section.
2026-07-30 21:40:58 +08:00
* @param context - the optional scope and plugin-defined assembly fields.
2026-08-10 18:02:11 +08:00
* @returns the post-waterfall assembly with any complete prompt enforced.
2026-07-30 21:40:58 +08:00
*/
async assemble(context: AssembleContext = {}): Promise< PromptAssembly >
```
2026-08-04 11:38:42 +08:00
Source: [`packages/core/system-prompt/src/index.ts` ](../../packages/core/system-prompt/src/index.ts )
2026-07-30 21:40:58 +08:00
< a id = "system-prompt-events" > < / a >
### `system-prompt/*` events
< a id = "system-promptassemble--waterfall" > < / a >
#### `system-prompt/assemble` — waterfall
2026-08-10 18:02:11 +08:00
Expert waterfall over the assembled sections, contexts, tools, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope` ): scoped listeners receive only that scope's assemblies. The returned value is authoritative. A supplied signal controls only this explicit assembly request and must not be retained to control later turns. A registered complete section is restored after this waterfall, so listeners cannot add to or replace that scope's system prompt.
2026-07-30 21:40:58 +08:00
```ts cordis-catalog
/**
* Expert waterfall over the assembled sections, contexts, tools, and variables.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope` ): scoped listeners
* receive only that scope's assemblies. The returned value is authoritative.
* A supplied signal controls only this explicit assembly request and must not
2026-08-10 18:02:11 +08:00
* be retained to control later turns. A registered complete section is
* restored after this waterfall, so listeners cannot add to or replace
* that scope's system prompt.
2026-07-30 21:40:58 +08:00
* @param assembly - the mutable assembly built from registered providers.
* @param context - the caller's per-assembly context.
* @mode waterfall
*/
'system-prompt/assemble'(this: Scoped< SystemPrompt > , assembly: PromptAssembly, context: AssembleContext, next: () => Promise< PromptAssembly > ): Promise< PromptAssembly >
```
Types: [Scoped ](scope.md )
2026-08-04 11:38:42 +08:00
Source: [`packages/core/system-prompt/src/index.ts` ](../../packages/core/system-prompt/src/index.ts )
2026-07-30 21:40:58 +08:00
< a id = "system-promptchange--emit" > < / a >
#### `system-prompt/change` — emit
Emitted when any prompt provider changes. This registry notification is unfiltered because a global change affects every scope.
```ts cordis-catalog
/**
* Emitted when any prompt provider changes. This registry notification is
* unfiltered because a global change affects every scope.
* @mode emit
*/
'system-prompt/change'(): void
```
2026-08-04 11:38:42 +08:00
Source: [`packages/core/system-prompt/src/index.ts` ](../../packages/core/system-prompt/src/index.ts )
2026-07-30 21:40:58 +08:00
<!-- END GENERATED cordis - surface -->