Fix timer bounds and ACP teardown ownership
This commit is contained in:
@@ -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/fs/tool-fs-search/README.md
|
||||
README.md: 78ffa069e56da5fc987913acf761eb5c6ae15b1a
|
||||
README.zh.md: 42b123d5c47d8f48bc21b6f9bed4905372ca8625
|
||||
README.md: 32fa61e3bb09b2166499003953a5631a93baf73b
|
||||
README.zh.md: 766ac01dadde34ef1f9ef9b9f6abfb719ba3d0a6
|
||||
|
||||
@@ -30,7 +30,7 @@ The binary ships with the package on every supported platform (macOS/Linux/Windo
|
||||
| `grepMaxLineBytes` | `2000` | Byte cap per matched-line preview; the cut preserves UTF-8 boundaries and is marked `(line truncated)`. |
|
||||
| `rawOutputMaxBytes` | `20000000` | Max complete raw `rg` stdout a search will parse (matches Claude Code's ripgrep raw buffer); larger raw output fails with `SEARCH_RAW_OUTPUT_OVERFLOW`. |
|
||||
| `timeoutMs` | `30000` | Cooperative tool-call budget attached to both tool definitions, enforced by `@deepseek-ai/dsh-timeout-policy` through `exec.signal`; the subprocess seam's terminate escalation is the hard kill. |
|
||||
| `graceMs` | `3000` | Terminate-escalation grace period the subprocess seam grants past `timeoutMs` before the search fails as `SEARCH_ABORTED`. |
|
||||
| `graceMs` | `3000` | Positive terminate-escalation grace the subprocess seam grants past `timeoutMs` before the search fails as `SEARCH_ABORTED`; it cannot exceed [`MAX_TIMER_DELAY_MS`](../../util/timeout/README.md). |
|
||||
| `stderrMaxBytes` | `65536` | Diagnostic-tail budget for `rg` stderr, captured through the subprocess seam's collect disposition; a lossy read keeps only the tail (marked `[stderr truncated]`). |
|
||||
|
||||
## Tools
|
||||
|
||||
@@ -30,7 +30,7 @@ await ctx.plugin(LocalSpillStore) // @deepseek-ai/dsh-
|
||||
| `grepMaxLineBytes` | `2000` | 每条匹配行预览的字节上限;截断会保留 UTF-8 边界,并标记为 `(line truncated)`。 |
|
||||
| `rawOutputMaxBytes` | `20000000` | 搜索将解析的完整原始 `rg` stdout 上限(与 Claude Code 的 ripgrep 原始 buffer 相同);更大的原始输出以 `SEARCH_RAW_OUTPUT_OVERFLOW` 失败。 |
|
||||
| `timeoutMs` | `30000` | 附加到两个工具定义上的协作式工具调用预算,由 `@deepseek-ai/dsh-timeout-policy` 通过 `exec.signal` 强制执行;subprocess seam 的终止升级提供硬终止。 |
|
||||
| `graceMs` | `3000` | subprocess seam 在 `timeoutMs` 之外授予的终止升级宽限期;超过后搜索以 `SEARCH_ABORTED` 失败。 |
|
||||
| `graceMs` | `3000` | subprocess seam 在 `timeoutMs` 之外授予的终止升级宽限期须为正值;超过后搜索以 `SEARCH_ABORTED` 失败;该宽限期不得大于 [`MAX_TIMER_DELAY_MS`](../../util/timeout/README.md)。 |
|
||||
| `stderrMaxBytes` | `65536` | `rg` stderr 的诊断尾部预算,经 subprocess seam 的 collect 形态捕获;lossy 读取只保留尾部(标记 `[stderr truncated]`)。 |
|
||||
|
||||
## 工具
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"@deepseek-ai/dsh-spill": "^0.0.1",
|
||||
"@deepseek-ai/dsh-subprocess": "^0.0.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "^0.0.1",
|
||||
"@deepseek-ai/dsh-timeout": "^0.0.1",
|
||||
"@deepseek-ai/dsh-tools": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.6"
|
||||
},
|
||||
@@ -51,6 +52,7 @@
|
||||
"@deepseek-ai/dsh-session": "workspace:^",
|
||||
"@deepseek-ai/dsh-spill": "workspace:^",
|
||||
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
||||
"@deepseek-ai/dsh-timeout": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"cordis": "^4.0.0-rc.6"
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
import type { Context } from 'cordis'
|
||||
import z from 'schemastery'
|
||||
import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
|
||||
import { GLOB_MAX_RESULTS, applyGlobTool } from './glob.ts'
|
||||
import { GREP_MAX_LINE_BYTES, GREP_MAX_MATCHES, applyGrepTool } from './grep.ts'
|
||||
import { RAW_OUTPUT_MAX_BYTES, SEARCH_GRACE_MS, SEARCH_META_MAX_BYTES, SEARCH_STDERR_MAX_BYTES, SEARCH_TIMEOUT_MS } from './search-core.ts'
|
||||
@@ -82,7 +83,7 @@ export interface Config {
|
||||
searchMetaMaxBytes?: number
|
||||
/** Max complete raw `rg` stdout bytes a search will parse; larger raw output fails with `SEARCH_RAW_OUTPUT_OVERFLOW`. */
|
||||
rawOutputMaxBytes?: number
|
||||
/** Terminate-escalation grace period (ms) for one search process, handed to the subprocess seam. */
|
||||
/** Terminate-escalation grace (ms), handed to the subprocess seam and bounded by `MAX_TIMER_DELAY_MS`. */
|
||||
graceMs?: number
|
||||
/** Max bytes retained for one search's stderr tail; the excerpt is embedded in `SEARCH_*` error messages, never shown on success. */
|
||||
stderrMaxBytes?: number
|
||||
@@ -130,6 +131,9 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
|
||||
assertPositiveInteger('searchMetaMaxBytes', resolved.searchMetaMaxBytes)
|
||||
assertPositiveInteger('rawOutputMaxBytes', resolved.rawOutputMaxBytes)
|
||||
assertPositiveInteger('graceMs', resolved.graceMs)
|
||||
if (resolved.graceMs > MAX_TIMER_DELAY_MS) {
|
||||
throw new Error(`tool-fs-search: graceMs must be no greater than ${MAX_TIMER_DELAY_MS}`)
|
||||
}
|
||||
assertPositiveInteger('stderrMaxBytes', resolved.stderrMaxBytes)
|
||||
assertPositiveInteger('timeoutMs', resolved.timeoutMs)
|
||||
applyGlobTool(ctx, {
|
||||
|
||||
@@ -18,6 +18,7 @@ import SystemPrompt, { renderPrompt } from '@deepseek-ai/dsh-system-prompt'
|
||||
import ToolRegistry, { TOOL_ABORTED_BEFORE_DISPATCH, type ToolExecution, type ToolExecutionToken } from '@deepseek-ai/dsh-tools'
|
||||
import { SubprocessService } from '@deepseek-ai/dsh-subprocess'
|
||||
import type { SubprocessCollectedOutputs, SubprocessHandle, SubprocessOutcome, SubprocessOutputRead, SubprocessOutputReader, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess'
|
||||
import { MAX_TIMER_DELAY_MS } from '@deepseek-ai/dsh-timeout'
|
||||
import { rgPath } from '@vscode/ripgrep'
|
||||
import { SpillLocator, SpillStore } from '@deepseek-ai/dsh-spill'
|
||||
import type { SaveTextSpill, SpillRef } from '@deepseek-ai/dsh-spill'
|
||||
@@ -309,6 +310,17 @@ describe('config validation', () => {
|
||||
await ctx.plugin(FakeSubprocess)
|
||||
await expect(ctx.plugin(ToolFsSearch, { ...DEFAULT_CONFIG, ...config })).rejects.toThrow(new RegExp(`tool-fs-search: ${name} must be a positive integer`))
|
||||
})
|
||||
|
||||
it('rejects a grace beyond the Node timer range at load', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
await ctx.plugin(ToolRegistry)
|
||||
await ctx.plugin(FakeSubprocess)
|
||||
await expect(ctx.plugin(ToolFsSearch, {
|
||||
...DEFAULT_CONFIG,
|
||||
graceMs: MAX_TIMER_DELAY_MS + 1,
|
||||
})).rejects.toThrow(`tool-fs-search: graceMs must be no greater than ${MAX_TIMER_DELAY_MS}`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('command construction (plain argv)', () => {
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
{
|
||||
"path": "../../spill/spill"
|
||||
},
|
||||
{
|
||||
"path": "../../util/timeout"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user