feat(web): whole-page image drop, projected intake limits, and thumbnail tiling
Second alignment step for #2248: document-level drag intake behind the new DropOverlay atom, lightbox close icon and shared dialog mask, DeepSeek Chat thumbnail rules (single 240px long edge with ratio clamp, 64px tiles, merged consecutive assistant images), image limits raised to 20/10MiB/100MiB and published to clients as the imageLimits projection, whole-batch intake pre-check with product-copy banners, and attachment-error reasons mapped to localized copy.
This commit is contained in:
@@ -15,7 +15,7 @@ import type {
|
||||
ModelReasoningEffort, ModelSelection, SessionProjectionsBlock, SessionSearchItem, SessionSummary,
|
||||
} from './sessions.ts'
|
||||
import type { ToolEventView } from './events.ts'
|
||||
import type { AttachmentIdType, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
|
||||
import type { AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
|
||||
import type { WorkspaceId } from './workspace.ts'
|
||||
import {
|
||||
SESSION_SEARCH_RESULT_LIMIT,
|
||||
@@ -213,7 +213,20 @@ export const sessionProjectionsBlockSchema = z.object({
|
||||
// -1 = empty log (the lastSeq convention of session/subscribed).
|
||||
asOfSeq: z.number().int().min(-1),
|
||||
values: z.record(z.string(), z.unknown()),
|
||||
}) as unknown as z.ZodType<SessionProjectionsBlock>
|
||||
}) as unknown as z.ZodType<Wire<SessionProjectionsBlock>>
|
||||
|
||||
/**
|
||||
* imageLimits projection unit schema (host-side view validation). zod widens
|
||||
* `readonly ImageMediaType[]` to `string[]`; on the JSON wire the two
|
||||
* serialize identically, so the cast records exactly that widening.
|
||||
*/
|
||||
export const imageLimitsProjectionSchema = z.object({
|
||||
maxImageBytes: z.number().int().positive(),
|
||||
maxImagesPerMessage: z.number().int().positive(),
|
||||
maxMessageImageBytes: z.number().int().positive(),
|
||||
maxImagePixels: z.number().int().positive(),
|
||||
mediaTypes: z.array(z.string()),
|
||||
}) as unknown as z.ZodType<ImageAttachmentLimits>
|
||||
|
||||
/** session.history response value (projections rides the tail page only). */
|
||||
export const sessionHistoryValueSchema: z.ZodType<Wire<ResponseValue<'session.history'>>> = z.object({
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import type { MessageId } from '@deepseek-ai/dsh-llm/brand'
|
||||
import type { AttachmentIdType, ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment'
|
||||
import type { AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType } from '@deepseek-ai/dsh-attachment'
|
||||
import type { ContentBlock } from '@deepseek-ai/dsh-llm/types'
|
||||
import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session/types'
|
||||
// The pure-type outlet: api/ is browser-importable, and the package root's
|
||||
@@ -15,6 +15,19 @@ import type { RpcId, RpcRequest, RpcResponse } from './rpc.ts'
|
||||
import type { ToolEventView } from './events.ts'
|
||||
import type { WorkspaceId } from './workspace.ts'
|
||||
|
||||
declare module '@deepseek-ai/dsh-session-projection/types' {
|
||||
interface SessionProjectionMap {
|
||||
/**
|
||||
* The deployment's image-intake limits: the attachments service's config
|
||||
* as this proxy enforces it at prompt admission, constant per host boot.
|
||||
* Clients pre-check count and bytes at intake and show the limits in
|
||||
* upload affordances. Key absence means no attachment service is
|
||||
* composed — clients skip the pre-check and let the host answer.
|
||||
*/
|
||||
imageLimits: ImageAttachmentLimits
|
||||
}
|
||||
}
|
||||
|
||||
declare module '@deepseek-ai/dsh-llm' {
|
||||
interface MessageSourceMap {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user