Merge remote-tracking branch 'origin/worktree/web-multimodal-image-input' into worktree/web-multimodal-image-input

# Conflicts:
#	.agents/notes/implemented/feature/2026-07-22-web-multimodal-image-input-and-durable-attachments.i18n.yaml
#	apps/web/tests/code-mode-fixture.snapshot.ts
#	apps/web/tests/image-display.snapshot.ts
#	docs/architecture.i18n.yaml
#	docs/module-graph.md
#	packages/client/test-runtime/tests/runtime.spec.tsx
#	packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx
#	packages/client/ui-conversation/tests/terminal-card.spec.tsx
#	packages/client/ui-trajectory/src/client/layout.ts
This commit is contained in:
creatixchu
2026-07-30 10:46:50 +08:00
38 changed files with 75 additions and 444 deletions
@@ -1,4 +1,4 @@
import type { HostDescription, IApiClient, HostFrame, MuxFrame, RpcRequest } from './api.ts'
import type { IApiClient, HostFrame, MuxFrame, RpcRequest } from './api.ts'
/** Reconnect/backoff tunables (deployment-varying — no hardcoded tunables; web-cordis §B.1 lists
* these as the future `ctx.connection` plugin Config). All fields optional; defaults below. */
@@ -44,8 +44,6 @@ export type ConnectionState = 'connected' | 'reconnecting'
export interface ConnectionSinks {
onMuxEnvelope?: (envelope: RpcRequest<MuxFrame>) => void
onHostEnvelope?: (envelope: RpcRequest<HostFrame>) => void
/** Latest successful host capability snapshot for this connection generation. */
onDescription?: (description: HostDescription) => void
/** After each connection generation is established (both streams open + describe succeeded), first connect included. */
onConnected?: () => void
/** Coarse state transitions (deduplicated: fires only on change). The initial pre-connect
@@ -144,7 +142,6 @@ export class ConnectionController {
}
if (ac.signal.aborted) throw new Error('generation aborted during readiness handshake')
this.attempt = 0
this.callSink(() => { this.sinks.onDescription?.(descriptionResult.value) })
this.emitState('connected')
this.callSink(this.sinks.onConnected)
} catch {
@@ -1260,20 +1260,6 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
cwd: '/tmp/fixture',
provider: 'fixture',
model: 'fx-vision',
activeModel: {
provider: 'fixture',
id: 'fx-vision',
name: 'Fixture Vision',
inputModalities: ['text', 'image'],
outputModalities: ['text', 'image'],
},
imageLimits: {
maxImageBytes: 5 * 1024 * 1024,
maxImagesPerMessage: 10,
maxMessageImageBytes: 20 * 1024 * 1024,
maxImagePixels: 40_000_000,
mediaTypes: ['image/png', 'image/jpeg', 'image/webp', 'image/gif'],
},
attachedSessions,
}),
// Deterministic native pick: the keyless lanes drive the full