Files
deepseek-harness/packages/api/session-controller/src/client/contract/session.ts
T
creatixchu 7c38fd8102 fix: deliver images reliably with steer and follow-up messages
A steer or follow-up accepted while a turn is closing is now claimed by a
fresh turn at the driver's clean exit instead of stranding in the inbox;
cancellation and pre-step rejection still park accepted work. Continuable
subagent follow-ups accept image parts: the wire is upload-shaped, the Host
admits and persists each batch before inbox acceptance, and delivery is
refused when the child model declines image input. The queue dock renders
durable image thumbnails instead of an [image] text marker.

Fixes #3186
2026-08-27 15:30:35 +08:00

95 lines
4.2 KiB
TypeScript

/**
* The outward session face. Feature packages never see the concrete Session
* class: components read lifecycle state through `useSession` (the
* ObservableSnapshot half), and orchestration code calls the behavior verbs
* below — nothing else. Widening this interface is the explicit act of
* widening what features may do to a session (and what every test fixture
* must stub); implementation-internal entry points (history staging, wire-frame
* dispatch) stay on the class, invisible out here.
*/
import type { AttachmentIdType, ImageAttachmentRef, PromptContentPart } from '@deepseek-ai/dsh-attachment'
import type { MessageId } from '@deepseek-ai/dsh-llm/brand'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'
import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'
import type { QueueAction } from '../../types.ts'
import type { ClientResult } from './result.ts'
import type { SessionSnapshot } from './snapshot.ts'
/** Key-addressed projection read face (the useProjection resolution path; see ProjectionValueStore). */
export interface ProjectionsFace {
/**
* The identity-stable bare observable for one projection key (absence is
* an `undefined` snapshot, never a missing face).
* @param key - projection key.
* @returns the key's value face.
*/
faceOf(key: string): ObservableSnapshot<unknown>
}
/** Identity plus the behavior verbs features may invoke on a session. */
export interface ISession {
/** The session's host identity (agent id — same axis). */
readonly sessionId: SessionId
/** Host-computed projection values by key (the useProjection seat). */
readonly projections: ProjectionsFace
/**
* Send a prompt into the session.
* @param content - text plus browser-owned temporary image uploads.
* @param mode - 'queue' appends a turn; 'steer' interrupts the running one.
* @returns acceptance, or the business error (also mirrored into snapshot.promptError).
*/
prompt(
content: PromptContentPart[],
mode: 'queue' | 'steer',
signal?: AbortSignal,
): Promise<ClientResult<{ accepted: true }>>
/**
* Resolve one durable image referenced by this session.
* @param attachmentId - opaque id found in the folded session log.
* @returns the authenticated reference and decoded bytes.
*/
readAttachment(
attachmentId: AttachmentIdType,
): Promise<ClientResult<{ attachment: ImageAttachmentRef; data: Uint8Array }>>
/**
* Apply one edit, remove, or strict steer action to a still-pending queue occurrence.
* @param itemId - agent-owned inbox occurrence identity.
* @param action - requested queue operation.
* @returns acceptance, or a business/transport error.
*/
updateQueue(itemId: MessageId, action: QueueAction): Promise<ClientResult<{ accepted: true }>>
/**
* Cancel the running turn. Pending queued work remains and resumes in FIFO
* order after the Host reaches cancellation quiescence.
* @returns acceptance, or the business error.
*/
cancel(): Promise<ClientResult<{ accepted: true }>>
/**
* Rename this session (explicit user title; pins it against automatic
* regeneration).
* @param title - raw title text (the host normalizes acceptance).
* @returns the normalized accepted title and its event seq, or the business error.
*/
rename(title: string): Promise<ClientResult<{ title: string; seq: number }>>
/**
* Extend the history window backwards (older messages pagination).
* @returns completion; failures land in snapshot.openState/loadingOlder.
*/
loadOlder(): Promise<void>
/**
* Execute one slash-command line against this session's agent — pure
* admission semantics (the host executor durably logs the lifecycle).
* @param line - the full command line, leading slash included.
* @returns the admission result, or the Remote face's error branch.
*/
command(line: string): Promise<RemoteResult<{ matched: boolean }>>
}
/**
* The full outward face: behavior verbs plus the Session lifecycle read side
* (the `useSession` hook source). This is the type carried by
* `SessionBinding.session` and the provide channel.
*/
export type SessionFace = ISession & ObservableSnapshot<SessionSnapshot>