Merge origin/master into codex/truncated-design
This commit is contained in:
@@ -44,3 +44,47 @@ Raw `rg` stdout is an internal transport detail. Each search requests `stdoutMax
|
||||
## Errors
|
||||
|
||||
Search failures carry the package-owned `SearchError` (a `HarnessError` subclass), surfaced as `{ name, code }` on `isError` results: `SEARCH_INVALID_PATTERN` (ripgrep rejected the regex/glob), `SEARCH_FAILED` (missing `rg`, inaccessible target, signal kill, malformed `--json` output), `SEARCH_RAW_OUTPUT_OVERFLOW` (raw output over `rawOutputMaxBytes`, or still truncated after the requested stdout capture budget), and `SEARCH_ABORTED` (tool timeout, caller cancellation, or the bash executor's own timeout). ripgrep exit semantics are tool-owned: exit 0 is success with results, exit 1 is a successful empty search (`No files found` / `No matches found`), and only other exits are failures. Model argument mistakes (blank pattern, a list-valued `include`) stay ordinary tool argument errors.
|
||||
|
||||
## Model Experience
|
||||
|
||||
### System prompt
|
||||
|
||||
**What the model sees**: Every request in this plugin's registration scope contains the independently registered glob and grep guidance below. Agent-scoped tool restrictions can hide either schema without removing its prompt section.
|
||||
|
||||
**Token effect**: Fixed guidance cost per request while the plugin is active.
|
||||
|
||||
#### Glob guidance
|
||||
|
||||
```markdown
|
||||
Use the glob tool — not shell find or ls — to discover files by path pattern. Results are sorted by modification time and include hidden and ignored files.
|
||||
```
|
||||
|
||||
#### Grep guidance
|
||||
|
||||
```markdown
|
||||
Use the grep tool — not shell grep or rg — to search file contents. Use read on a matched file when you need surrounding context.
|
||||
```
|
||||
|
||||
### Tool schemas
|
||||
|
||||
**What the model sees**: The generated [`glob` and `grep` schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-fs-search) while this surface is visible.
|
||||
|
||||
**Token effect**: Fixed schema cost on every request where the tools are visible.
|
||||
|
||||
### Results and spill notices
|
||||
|
||||
**What the model sees**: `glob` returns one path per line; `grep` groups `Line <line>: <preview>` matches beneath each path. Empty searches return `No files found` or `No matches found`. A capped result ends with its omission count plus the spill locator and backend retrieval hint, or says the complete result could not be saved.
|
||||
|
||||
**Token effect**: Inline paths and matches are bounded by `globMaxResults`, `grepMaxMatches`, and `grepMaxLineBytes`; the call and retained result remain in history until compaction.
|
||||
|
||||
### Tool errors
|
||||
|
||||
**What the model sees**: Failures are normalized as `Error: <message>` with structured `SEARCH_INVALID_PATTERN`, `SEARCH_FAILED`, `SEARCH_RAW_OUTPUT_OVERFLOW`, or `SEARCH_ABORTED` metadata for callers.
|
||||
|
||||
**Token effect**: Only a failing call adds these retained tokens.
|
||||
|
||||
## Known Limitations and Deferred Work
|
||||
|
||||
- **Search and file access have no shared-workspace proof** — returned paths are follow-up-readable only when the bash workdir and filesystem root denote the same workspace; the package performs no runtime cross-service validation.
|
||||
- **Ripgrep is a deployment dependency** — a missing or incompatible `rg` executable fails calls with `SEARCH_FAILED`; remote or virtual filesystems need a co-located executor or another search consumer.
|
||||
- **The schemas expose one bounded page** — offset pagination, case-mode switches, alternate output modes, and provider-backed discovery remain outside this package; capped complete output requires a spill backend.
|
||||
|
||||
@@ -16,7 +16,7 @@ import { CallId } from '@deepseek-ai/dsh-llm'
|
||||
import SystemPrompt, { renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry from '@deepseek-ai/dsh-tools'
|
||||
import { BashExecutor } from '@deepseek-ai/dsh-bash'
|
||||
import type { BashExecRequest, BashExecSpec, BashRunResult, BashTask, BashTaskId, BashTaskRead, OwnerToken } from '@deepseek-ai/dsh-bash'
|
||||
import type { BashExecRequest, BashExecSpec, BashProcess, BashRunResult } from '@deepseek-ai/dsh-bash'
|
||||
import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill'
|
||||
import type { SaveTextSpill, SpillRef } from '@deepseek-ai/dsh-spill'
|
||||
import * as ToolFsSearch from '@deepseek-ai/dsh-tool-fs-search'
|
||||
@@ -65,7 +65,6 @@ class FakeBash extends BashExecutor {
|
||||
timeoutMs: request.timeoutMs ?? 60_000,
|
||||
stdoutMaxBytes: request.stdoutMaxBytes ?? 64_000,
|
||||
signal: request.signal,
|
||||
owner: request.owner,
|
||||
sandboxMode: request.sandboxMode,
|
||||
}
|
||||
}
|
||||
@@ -73,25 +72,10 @@ class FakeBash extends BashExecutor {
|
||||
this.specs.push(spec)
|
||||
return Promise.resolve(this.handler(spec))
|
||||
}
|
||||
override start(): BashTask {
|
||||
override start(): BashProcess {
|
||||
this.startCalls++
|
||||
throw new Error('search tools must never start a background task')
|
||||
}
|
||||
override get(): BashTask | undefined {
|
||||
return undefined
|
||||
}
|
||||
override ownerOf(): OwnerToken | undefined {
|
||||
return undefined
|
||||
}
|
||||
override list(): BashTask[] {
|
||||
return []
|
||||
}
|
||||
override readOutput(id: BashTaskId): BashTaskRead {
|
||||
throw new Error(`unknown bash task ${id}`)
|
||||
}
|
||||
override kill(id: BashTaskId): boolean {
|
||||
throw new Error(`unknown bash task ${id}`)
|
||||
}
|
||||
}
|
||||
|
||||
/** A recording spill backend; arm `failWith` to script a storage failure. */
|
||||
|
||||
Reference in New Issue
Block a user