fix: address ds-review-bot v7 findings on the merged image-input head

- gate model selection on steering-placement image carriers from enqueue
  until their steering/message event publishes; release the gate when an
  admission ends idle without publication (both behaviorally asserted)
- reject session.updateQueue edits carrying non-text blocks at the RPC
  boundary (queue edits cannot bypass image admission)
- extend the durable-directory walk past a first-created DSH_HOME to the
  deepest pre-existing ancestor
- strip Windows-style separators from attachment display names on POSIX
- verify attachment reads with a header-only probe (digest already proves
  the bytes decoded fully at admission); document the read path
- make SessionInputShell.addImages refusal observable and keep workspace
  transfers/composer intake from leaking refused drafts
- own ONE recursive image walk (dsh-llm contentHasImage) across apiproxy,
  pi-ai, compact-basic, and the DeepSeek text-only assertion
- drop the redundant canonical-base64 regex and the no-op role read
- move AttachmentId/AttachmentError out of types.ts (brand.ts/error.ts);
  document why AttachmentError does not extend HarnessError
- document the hard attachments inject in both consumer READMEs
This commit is contained in:
creatixchu
2026-07-30 14:34:08 +08:00
parent 97cf33b7e0
commit 0d1250f743
37 changed files with 335 additions and 140 deletions

View File

@@ -0,0 +1,15 @@
/** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */
import type { Branded } from '@deepseek-ai/dsh-brand'
/** Opaque content-addressed identifier for one immutable attachment object. */
export type AttachmentId = Branded<'AttachmentId'>
/**
* Brand a validated storage identifier.
* @param value - backend-produced opaque identifier.
* @returns the branded identifier.
*/
export function AttachmentId(value: string): AttachmentId {
return value as AttachmentId
}

View File

@@ -0,0 +1,26 @@
/** Attachment failure class. @module @deepseek-ai/dsh-attachment/error */
/**
* Stable failures suitable for host RPC error mapping.
*
* Deliberately re-implements the `HarnessError` shape instead of extending it:
* the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this
* package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base
* would create a dependency cycle. Consumers route on `code`, never on the
* prototype chain, so the shapes stay interchangeable at the wire boundary.
*/
export class AttachmentError extends Error {
/** Stable machine-routing failure code. */
readonly code: string
/**
* @param message - human-readable failure description without raw bytes or host paths.
* @param code - stable machine-routing code.
* @param options - optional chained cause.
*/
constructor(message: string, code: string, options?: ErrorOptions) {
super(message, options)
this.name = 'AttachmentError'
this.code = code
}
}

View File

@@ -8,7 +8,8 @@ import type {
StoredImageAttachment,
} from './types.ts'
export { AttachmentError, AttachmentId } from './types.ts'
export { AttachmentId } from './brand.ts'
export { AttachmentError } from './error.ts'
export type {
AttachmentId as AttachmentIdType,
ImageAttachmentLimits,

View File

@@ -1,18 +1,8 @@
/** Durable attachment vocabulary. @module @deepseek-ai/dsh-attachment/types */
import type { Branded } from '@deepseek-ai/dsh-brand'
import type { AttachmentId } from './brand.ts'
/** Opaque content-addressed identifier for one immutable attachment object. */
export type AttachmentId = Branded<'AttachmentId'>
/**
* Brand a validated storage identifier.
* @param value - backend-produced opaque identifier.
* @returns the branded identifier.
*/
export function AttachmentId(value: string): AttachmentId {
return value as AttachmentId
}
export type { AttachmentId } from './brand.ts'
/** Raster image formats accepted by the version-one attachment path. */
export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'
@@ -56,20 +46,3 @@ export interface StoredImageAttachment {
ref: ImageAttachmentRef
data: Uint8Array
}
/** Stable failures suitable for host RPC error mapping. */
export class AttachmentError extends Error {
/** Stable machine-routing failure code. */
readonly code: string
/**
* @param message - human-readable failure description without raw bytes or host paths.
* @param code - stable machine-routing code.
* @param options - optional chained cause.
*/
constructor(message: string, code: string, options?: ErrorOptions) {
super(message, options)
this.name = 'AttachmentError'
this.code = code
}
}