fix(workspace-context): require explicit byte budgets
This commit is contained in:
@@ -56,8 +56,8 @@ export interface Config {
|
||||
tools?: ToolsConfig
|
||||
/** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
|
||||
persistenceRoot?: string
|
||||
/** Controls automatic AGENTS.md/CLAUDE.md loading; set `false` for hermetic prompts. */
|
||||
workspaceContext?: agentCore.Config['workspaceContext']
|
||||
/** Controls automatic AGENTS.md/CLAUDE.md loading; configure a byte budget or set `false`. */
|
||||
workspaceContext: agentCore.Config['workspaceContext']
|
||||
/** Skill registry, local-provider, and model-facing consumer config forwarded to agent-core. */
|
||||
skills?: agentCore.SkillConfig
|
||||
}
|
||||
@@ -77,10 +77,11 @@ Source: [`packages/ui/acp-agent/src/index.ts:53`](../packages/ui/acp-agent/src/i
|
||||
* plugin (the deployment's persona section and the explicit model-facing tool
|
||||
* order), the `tools` object to the tool registry (its presentation `mode`),
|
||||
* `skills` to the skill registry/local provider/tool consumer, and
|
||||
* `workspaceContext` to the workspace-context plugin. Every field is optional
|
||||
* INPUT here because each owner's schema supplies the default; the schema is
|
||||
* the INTERSECTION of the owners' own schemas (with child schemas nested under
|
||||
* their bundle keys), so validation and defaulting can never drift from them.
|
||||
* `workspaceContext` to the workspace-context plugin. Workspace context must
|
||||
* be configured explicitly with a byte budget or disabled with `false`; the
|
||||
* other fields remain optional inputs whose owner schemas supply defaults. The
|
||||
* schema is the INTERSECTION of the owners' own schemas (with child schemas
|
||||
* nested under their bundle keys), so validation and defaulting cannot drift.
|
||||
*/
|
||||
export interface Config {
|
||||
/** The agent-loop `agents` list (see dsh-agent-loop's `Config`). */
|
||||
@@ -91,8 +92,8 @@ export interface Config {
|
||||
toolOrder?: SystemPromptConfig['toolOrder']
|
||||
/** The tool registry's config — its presentation `mode` (see dsh-tools' `Config`). */
|
||||
tools?: ToolsConfig
|
||||
/** Workspace-context loader controls; set `false` for hermetic prompts. */
|
||||
workspaceContext?: workspaceContext.Config | false
|
||||
/** Workspace-context loader controls with an explicit byte budget; set `false` for hermetic prompts. */
|
||||
workspaceContext: workspaceContext.Config | false
|
||||
/** Skill registry, local provider, and model-facing consumer config. */
|
||||
skills?: SkillConfig
|
||||
}
|
||||
@@ -110,7 +111,7 @@ export interface SkillConfig {
|
||||
|
||||
Depends on: [`AgentLoopConfig`](#deepseek-aidsh-agent-loop) · [`SkillLocal`](../packages/skill/skill-local/src/index.ts) · [`SkillRegistryConfig`](#deepseek-aidsh-skill) · [`SystemPromptConfig`](#deepseek-aidsh-system-prompt) · [`ToolsConfig`](#deepseek-aidsh-tools) · [`toolSkill`](../packages/skill/tool-skill/src/index.ts) · [`workspaceContext`](../packages/prompt/workspace-context/src/index.ts)
|
||||
|
||||
Source: [`packages/core/agent-core/src/index.ts:88`](../packages/core/agent-core/src/index.ts)
|
||||
Source: [`packages/core/agent-core/src/index.ts:89`](../packages/core/agent-core/src/index.ts)
|
||||
|
||||
## `@deepseek-ai/dsh-agent-loop`
|
||||
|
||||
@@ -641,8 +642,8 @@ export interface Config {
|
||||
* (`resumeSessionId: !!js process.env.RESUME_SESSION_ID`).
|
||||
*/
|
||||
resumeSessionId?: string
|
||||
/** Controls automatic AGENTS.md/CLAUDE.md loading; set `false` for hermetic prompts. */
|
||||
workspaceContext?: agentCore.Config['workspaceContext']
|
||||
/** Controls automatic AGENTS.md/CLAUDE.md loading; configure a byte budget or set `false`. */
|
||||
workspaceContext: agentCore.Config['workspaceContext']
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1145,14 +1146,14 @@ export interface Config {
|
||||
dshHome?: string
|
||||
/** Directory entries that identify the project root while walking upward from the session cwd. */
|
||||
projectRootMarkers?: string[]
|
||||
/** Maximum UTF-8 bytes in one rendered baseline or dynamic instruction batch; non-positive disables loading. */
|
||||
maxBytes?: number
|
||||
/** UTF-8 byte cap for one rendered baseline or dynamic batch; non-positive or non-finite disables loading. */
|
||||
maxBytes: number
|
||||
/** Ordered same-directory project candidates; the first existing regular file wins in each scope. */
|
||||
instructionFileCandidates?: string[]
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/prompt/workspace-context/src/config.ts:10`](../packages/prompt/workspace-context/src/config.ts)
|
||||
Source: [`packages/prompt/workspace-context/src/config.ts:15`](../packages/prompt/workspace-context/src/config.ts)
|
||||
|
||||
## Loadable plugins with no config
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ Shell commands are not discovery triggers. Local bash calls start fresh shells,
|
||||
|
||||
### Duplicate Suppression And Change Detection
|
||||
|
||||
Every dynamic workspace context event stores versioned metadata with `{ action, scope, path, previousPath?, digest? }`, where `digest` is SHA-256 over the loaded content. The model-facing prompt has no HTML comments, hidden markers, or headings that are parsed back into state.
|
||||
Every dynamic workspace context event stores versioned metadata with `{ action, scope, path, previousPath?, digest? }`, where `digest` is SHA-1 over the loaded content. The model-facing prompt has no HTML comments, hidden markers, or headings that are parsed back into state.
|
||||
|
||||
At reconciliation time the plugin scans plugin-owned `context/message` events and derives the latest state for each visible scope. A short per-session pending map covers the interval after `tools/post-execute` returns `additionalContext` but before the loop appends that context to the log. Once an equal event appears at or after the pending sequence boundary, the pending entry is removed.
|
||||
|
||||
@@ -58,9 +58,9 @@ There is intentionally no watcher. Detection occurs at the next successful struc
|
||||
|
||||
### Byte Budget And Cache
|
||||
|
||||
`maxBytes` defaults to 64 KiB and applies separately to a rendered baseline or one dynamic reconciliation batch. Non-positive and non-finite values disable loading. When content exceeds the budget, broader files are omitted before the most-specific file is truncated. A visible `Workspace instruction budget ...` notice names omitted and truncated paths and byte counts, and output never exceeds the configured bytes.
|
||||
`maxBytes` is required and applies separately to a rendered baseline or one dynamic reconciliation batch; there is no implicit or unbounded budget. Non-positive and non-finite values disable loading. When content exceeds the budget, broader files are omitted before the most-specific file is truncated. A visible `Workspace instruction budget ...` notice names omitted and truncated paths and byte counts, and output never exceeds the configured bytes.
|
||||
|
||||
File content is cached by normalized absolute path plus the provider's opaque version and optional size. A signature change causes a re-read. Discovery carries the signature into the read pass so one pass does not stat the same instruction twice. The cache is an I/O optimization only; visible structured metadata is the source of duplicate-suppression state.
|
||||
Each discovered candidate is read and identified by normalized absolute path, the provider's opaque version, and a SHA-1 content digest. Hashing the read content prevents same-version, same-size rewrites from staying stale. Discovery carries the provider version into the read pass so one pass does not stat the same instruction twice. Visible structured metadata remains the source of duplicate-suppression state.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
Reference in New Issue
Block a user