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:
@@ -979,6 +979,15 @@ function projectionValuesOf(log: readonly SessionEvent[]): Record<string, unknow
|
||||
values['contextPressure'] = contextPressureOf(log)
|
||||
// Always present (token-meter composed): heuristic request composition.
|
||||
values['contextBreakdown'] = contextBreakdownOf(log)
|
||||
// Always present (attachment service composed): the deployment image
|
||||
// limits, constant per boot (mirrors the attachment-local defaults).
|
||||
values['imageLimits'] = {
|
||||
maxImageBytes: 10 * 1024 * 1024,
|
||||
maxImagesPerMessage: 20,
|
||||
maxMessageImageBytes: 100 * 1024 * 1024,
|
||||
maxImagePixels: 40_000_000,
|
||||
mediaTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'],
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http'
|
||||
|
||||
/** Default carrier cap for all HTTP RPC bodies: sized for the default
|
||||
* aggregate image limit (100 MiB) after base64 expansion plus envelope
|
||||
* headroom (~134.3 MiB required), rounded up for slack. The bridge buffers
|
||||
* each body in memory, so this cap is also the per-request resident bound. */
|
||||
export const DEFAULT_MAX_REQUEST_BODY_BYTES = 160 * 1024 * 1024
|
||||
|
||||
/** Transport-independent request handler consumed by the Host HTTP bridge. */
|
||||
export interface FetchHandler {
|
||||
/**
|
||||
@@ -27,7 +33,7 @@ export async function bridge(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
apiHandler: FetchHandler,
|
||||
maxRequestBodyBytes = 32 * 1024 * 1024,
|
||||
maxRequestBodyBytes = DEFAULT_MAX_REQUEST_BODY_BYTES,
|
||||
): Promise<void> {
|
||||
const abort = new AbortController()
|
||||
// Client-disconnect detection MUST hang off the response, not the request:
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {} from '@deepseek-ai/dsh-attachment'
|
||||
import type { WebRoute, WebUpgradeRoute } from '@deepseek-ai/dsh-host-webserver'
|
||||
import { toFetchHandler } from '@deepseek-ai/dsh-host-apiproxy'
|
||||
import { API_PATH, HOST_EVENTS_PATH, MUX_EVENTS_PATH } from './api-path.ts'
|
||||
import { bridge } from './http-bridge.ts'
|
||||
import { bridge, DEFAULT_MAX_REQUEST_BODY_BYTES } from './http-bridge.ts'
|
||||
import { assertTrustedAuthority, isTrustedApiRequest } from './api-request-trust.ts'
|
||||
import { HostConnectionService } from './rpc-host.ts'
|
||||
import { rejectWebSocketUpgrade, WebSocketDownlinks } from './websocket-downlink.ts'
|
||||
@@ -42,8 +42,6 @@ function assertImageBodyCapacity(ctx: Context, maxRequestBodyBytes: number): voi
|
||||
)
|
||||
}
|
||||
}
|
||||
/** Default carrier cap for all HTTP RPC bodies. */
|
||||
const DEFAULT_MAX_REQUEST_BODY_BYTES = 32 * 1024 * 1024
|
||||
|
||||
/** Services required before providing Connection; API Proxy is an optional `/api` fallback. */
|
||||
export const inject = ['httpServer']
|
||||
|
||||
Reference in New Issue
Block a user