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.
35 lines
1.6 KiB
TypeScript
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 })
|
|
}
|