Files
deepseek-harness/packages/fs/tool-fs/src/error.ts
T
_Kerman 1ee167aeac feat(fs): append recovery remedy to guarded-mutation errors
write/edit failures with FS_STALE_VERSION or FS_NOT_OBSERVED now reach the
model with the correct recovery instruction appended (re-read / read, then
retry) while preserving the structured code and chaining the cause. The
edit-intent waterfall sits inside the same try, so the policy's
FS_NOT_OBSERVED refusal is remediated too. Re-recorded the fs-policy-reject
keyless snapshot and the bilingual README pairs.
2026-08-03 20:08:41 +08:00

35 lines
1.6 KiB
TypeScript

/**
* Model-facing remediation for guarded-mutation failures. The provider's
* `FS_STALE_VERSION` and `FS_NOT_OBSERVED` messages state the condition but
* not the only correct recovery (re-read / read the file), so this package
* appends the remedy at the model boundary; provider messages stay
* machine-oriented and unchanged.
* @module @deepseek-ai/dsh-tool-fs/src/error
*/
import { FsError } from '@deepseek-ai/dsh-fs'
import type { FsErrorCode } from '@deepseek-ai/dsh-fs'
/** The remedy appended to each remediable failure code's message. */
const REMEDIES: Partial<Record<FsErrorCode, string>> = {
FS_STALE_VERSION: 're-read the file, then retry',
FS_NOT_OBSERVED: 'read the file, then retry',
}
/**
* Append the correct recovery instruction to a guarded-mutation failure's
* message. `FS_STALE_VERSION` (the file changed since this session's last
* observation, including a missing target) recovers only by re-reading;
* `FS_NOT_OBSERVED` (no prior read by this session) by reading. The `FsError`
* code is preserved so retry/permission/UI layers keep routing on it, and the
* original error chains as `cause`. Anything else passes through untouched.
* @param error - the caught value from a write/edit execution.
* @returns a remediated `FsError` for the two guarded-mutation codes, else the original value.
*/
export function remediateFsError(error: unknown): unknown {
if (!(error instanceof FsError)) return error
const remedy = REMEDIES[error.code]
if (!remedy) return error
return new FsError(`${error.message}${remedy}`, error.code, { cause: error })
}