@deepseek-ai/dsh-api-session-controller 0.1.2-alpha.2 → 0.1.2-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -132,11 +132,11 @@ const _deepseek_ai_dsh_api_session_controller_session_control_result$schema = z.
132
132
  'subagent': z.union([z.literal(null), z.object({
133
133
  'mode': z.literal("one-shot"),
134
134
  'label': z.string().optional(),
135
- 'seq': z.number(),
135
+ 'seq': z.intersection(z.number(), z.unknown()),
136
136
  }), z.object({
137
137
  'mode': z.literal("continuable"),
138
138
  'label': z.string(),
139
- 'seq': z.number(),
139
+ 'seq': z.intersection(z.number(), z.unknown()),
140
140
  })]).optional(),
141
141
  'goal': z.union([z.literal(null), z.object({
142
142
  'goal': z.object({
@@ -221,9 +221,9 @@ const _deepseek_ai_dsh_api_session_controller_session_follow_result$schema = z.u
221
221
  'ignorable': z.literal(true).readonly().optional(),
222
222
  'sourceEventSeqs': z.array(z.number()).readonly().optional(),
223
223
  'surfaceOp': z.union([z.literal("append"), z.object({
224
- 'op': z.literal("replace"),
225
- 'start': z.number(),
226
- 'end': z.number(),
224
+ 'op': z.literal("replace").readonly(),
225
+ 'start': z.number().readonly(),
226
+ 'end': z.number().readonly(),
227
227
  })]).readonly().optional(),
228
228
  }).readonly(),
229
229
  }), z.object({
@@ -250,9 +250,9 @@ const _deepseek_ai_dsh_api_session_controller_session_follow_result$schema = z.u
250
250
  'ignorable': z.literal(true).readonly().optional(),
251
251
  'sourceEventSeqs': z.array(z.number()).readonly().optional(),
252
252
  'surfaceOp': z.union([z.literal("append"), z.object({
253
- 'op': z.literal("replace"),
254
- 'start': z.number(),
255
- 'end': z.number(),
253
+ 'op': z.literal("replace").readonly(),
254
+ 'start': z.number().readonly(),
255
+ 'end': z.number().readonly(),
256
256
  })]).readonly().optional(),
257
257
  }).readonly(),
258
258
  }), z.object({
@@ -338,11 +338,11 @@ const _deepseek_ai_dsh_api_session_controller_session_follow_result$schema = z.u
338
338
  'subagent': z.union([z.literal(null), z.object({
339
339
  'mode': z.literal("one-shot"),
340
340
  'label': z.string().optional(),
341
- 'seq': z.number(),
341
+ 'seq': z.intersection(z.number(), z.unknown()),
342
342
  }), z.object({
343
343
  'mode': z.literal("continuable"),
344
344
  'label': z.string(),
345
- 'seq': z.number(),
345
+ 'seq': z.intersection(z.number(), z.unknown()),
346
346
  })]).optional(),
347
347
  'goal': z.union([z.literal(null), z.object({
348
348
  'goal': z.object({
@@ -425,11 +425,11 @@ const _deepseek_ai_dsh_api_session_controller_session_list_result$schema = z.obj
425
425
  'subagent': z.union([z.literal(null), z.object({
426
426
  'mode': z.literal("one-shot"),
427
427
  'label': z.string().optional(),
428
- 'seq': z.number(),
428
+ 'seq': z.intersection(z.number(), z.unknown()),
429
429
  }), z.object({
430
430
  'mode': z.literal("continuable"),
431
431
  'label': z.string(),
432
- 'seq': z.number(),
432
+ 'seq': z.intersection(z.number(), z.unknown()),
433
433
  })]).optional(),
434
434
  'goal': z.union([z.literal(null), z.object({
435
435
  'goal': z.object({
@@ -512,9 +512,9 @@ const _deepseek_ai_dsh_api_session_controller_session_page_result$schema = z.obj
512
512
  'ignorable': z.literal(true).readonly().optional(),
513
513
  'sourceEventSeqs': z.array(z.number()).readonly().optional(),
514
514
  'surfaceOp': z.union([z.literal("append"), z.object({
515
- 'op': z.literal("replace"),
516
- 'start': z.number(),
517
- 'end': z.number(),
515
+ 'op': z.literal("replace").readonly(),
516
+ 'start': z.number().readonly(),
517
+ 'end': z.number().readonly(),
518
518
  })]).readonly().optional(),
519
519
  }).readonly(),
520
520
  }), z.object({
@@ -731,7 +731,7 @@ export const TYPERT_REMOTE = {
731
731
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionAttachmentValue',
732
732
  schema: _deepseek_ai_dsh_api_session_controller_session_attachment_result$schema,
733
733
  },
734
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":333,"column":3},
734
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":338,"column":3},
735
735
  },
736
736
  {
737
737
  id: '@deepseek-ai/dsh-api-session-controller#session/cancel',
@@ -756,7 +756,7 @@ export const TYPERT_REMOTE = {
756
756
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionCancelValue',
757
757
  schema: _deepseek_ai_dsh_api_session_controller_session_cancel_result$schema,
758
758
  },
759
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":353,"column":3},
759
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":358,"column":3},
760
760
  },
761
761
  {
762
762
  id: '@deepseek-ai/dsh-api-session-controller#session/canOpenWorkspacePath',
@@ -771,7 +771,7 @@ export const TYPERT_REMOTE = {
771
771
  typeSymbol: '@deepseek-ai/dsh-api-session-controller#session/canOpenWorkspacePath:result',
772
772
  schema: _deepseek_ai_dsh_api_session_controller_session_canOpenWorkspacePath_result$schema,
773
773
  },
774
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":258,"column":3},
774
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":263,"column":3},
775
775
  },
776
776
  {
777
777
  id: '@deepseek-ai/dsh-api-session-controller#session/control',
@@ -788,7 +788,7 @@ export const TYPERT_REMOTE = {
788
788
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionControlFrame',
789
789
  schema: _deepseek_ai_dsh_api_session_controller_session_control_result$schema,
790
790
  },
791
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":385,"column":3},
791
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":390,"column":3},
792
792
  },
793
793
  {
794
794
  id: '@deepseek-ai/dsh-api-session-controller#session/create',
@@ -813,7 +813,7 @@ export const TYPERT_REMOTE = {
813
813
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionCreateValue',
814
814
  schema: _deepseek_ai_dsh_api_session_controller_session_create_result$schema,
815
815
  },
816
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":230,"column":3},
816
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":235,"column":3},
817
817
  },
818
818
  {
819
819
  id: '@deepseek-ai/dsh-api-session-controller#session/follow',
@@ -840,7 +840,7 @@ export const TYPERT_REMOTE = {
840
840
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionFollowFrame',
841
841
  schema: _deepseek_ai_dsh_api_session_controller_session_follow_result$schema,
842
842
  },
843
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":375,"column":3},
843
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":380,"column":3},
844
844
  },
845
845
  {
846
846
  id: '@deepseek-ai/dsh-api-session-controller#session/fork',
@@ -865,7 +865,7 @@ export const TYPERT_REMOTE = {
865
865
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionForkValue',
866
866
  schema: _deepseek_ai_dsh_api_session_controller_session_fork_result$schema,
867
867
  },
868
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":311,"column":3},
868
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":316,"column":3},
869
869
  },
870
870
  {
871
871
  id: '@deepseek-ai/dsh-api-session-controller#session/list',
@@ -891,7 +891,7 @@ export const TYPERT_REMOTE = {
891
891
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionListValue',
892
892
  schema: _deepseek_ai_dsh_api_session_controller_session_list_result$schema,
893
893
  },
894
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":209,"column":9},
894
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":214,"column":9},
895
895
  },
896
896
  {
897
897
  id: '@deepseek-ai/dsh-api-session-controller#session/modelCatalog',
@@ -906,7 +906,7 @@ export const TYPERT_REMOTE = {
906
906
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#ModelCatalog',
907
907
  schema: _deepseek_ai_dsh_api_session_controller_session_modelCatalog_result$schema,
908
908
  },
909
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":249,"column":3},
909
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":254,"column":3},
910
910
  },
911
911
  {
912
912
  id: '@deepseek-ai/dsh-api-session-controller#session/openWorkspacePath',
@@ -932,7 +932,7 @@ export const TYPERT_REMOTE = {
932
932
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionOpenWorkspacePathValue',
933
933
  schema: _deepseek_ai_dsh_api_session_controller_session_openWorkspacePath_result$schema,
934
934
  },
935
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":270,"column":9},
935
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":275,"column":9},
936
936
  },
937
937
  {
938
938
  id: '@deepseek-ai/dsh-api-session-controller#session/page',
@@ -958,7 +958,7 @@ export const TYPERT_REMOTE = {
958
958
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionPage',
959
959
  schema: _deepseek_ai_dsh_api_session_controller_session_page_result$schema,
960
960
  },
961
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":364,"column":3},
961
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":369,"column":3},
962
962
  },
963
963
  {
964
964
  id: '@deepseek-ai/dsh-api-session-controller#session/prompt',
@@ -984,7 +984,7 @@ export const TYPERT_REMOTE = {
984
984
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionPromptValue',
985
985
  schema: _deepseek_ai_dsh_api_session_controller_session_prompt_result$schema,
986
986
  },
987
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":322,"column":3},
987
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":327,"column":3},
988
988
  },
989
989
  {
990
990
  id: '@deepseek-ai/dsh-api-session-controller#session/rename',
@@ -1009,7 +1009,7 @@ export const TYPERT_REMOTE = {
1009
1009
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionRenameValue',
1010
1010
  schema: _deepseek_ai_dsh_api_session_controller_session_rename_result$schema,
1011
1011
  },
1012
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":301,"column":3},
1012
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":306,"column":3},
1013
1013
  },
1014
1014
  {
1015
1015
  id: '@deepseek-ai/dsh-api-session-controller#session/search',
@@ -1035,7 +1035,7 @@ export const TYPERT_REMOTE = {
1035
1035
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionSearchValue',
1036
1036
  schema: _deepseek_ai_dsh_api_session_controller_session_search_result$schema,
1037
1037
  },
1038
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":220,"column":3},
1038
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":225,"column":3},
1039
1039
  },
1040
1040
  {
1041
1041
  id: '@deepseek-ai/dsh-api-session-controller#session/selectModel',
@@ -1060,7 +1060,7 @@ export const TYPERT_REMOTE = {
1060
1060
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionSelectModelValue',
1061
1061
  schema: _deepseek_ai_dsh_api_session_controller_session_selectModel_result$schema,
1062
1062
  },
1063
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":240,"column":3},
1063
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":245,"column":3},
1064
1064
  },
1065
1065
  {
1066
1066
  id: '@deepseek-ai/dsh-api-session-controller#session/updateQueue',
@@ -1085,7 +1085,7 @@ export const TYPERT_REMOTE = {
1085
1085
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionUpdateQueueValue',
1086
1086
  schema: _deepseek_ai_dsh_api_session_controller_session_updateQueue_result$schema,
1087
1087
  },
1088
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":343,"column":3},
1088
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":348,"column":3},
1089
1089
  },
1090
1090
  {
1091
1091
  id: '@deepseek-ai/dsh-api-session-controller#skills/list',
@@ -1,7 +1,8 @@
1
1
  /** Agent activation, composition, and model-selection policy owned by API Session. */
2
2
  import type { Context } from '@deepseek-ai/cordis';
3
3
  import type { Agent, AgentSetup, ModelSelection as AgentModelSelection, ModelSelectionRef } from '@deepseek-ai/dsh-agent';
4
- import type { Session, SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session';
4
+ import type { Session, SessionId } from '@deepseek-ai/dsh-session';
5
+ import type { SessionInspection } from '@deepseek-ai/dsh-session-persistence';
5
6
  import { type SessionObservation } from '@deepseek-ai/dsh-session-query';
6
7
  import { RemoteError } from '@deepseek-ai/dsh-typert-protocol';
7
8
  /** Cold Session identity absent from persistence. */
@@ -60,10 +61,7 @@ export declare function apiSessionSubagentOwnershipError(sessionId: SessionId):
60
61
  * @param signal - optional cancellation for persistence reads.
61
62
  * @returns the persisted header and complete event prefix.
62
63
  */
63
- export declare function inspectApiSession(ctx: Context, sessionId: SessionId, signal?: AbortSignal): Promise<{
64
- meta: SessionHeader;
65
- events: SessionEvent[];
66
- }>;
64
+ export declare function inspectApiSession(ctx: Context, sessionId: SessionId, signal?: AbortSignal): Promise<SessionInspection>;
67
65
  /** Owns every operation that may create, resume, or configure a Web Agent. */
68
66
  export declare class ApiSessionAgentController {
69
67
  private readonly ctx;
@@ -138,7 +138,11 @@ export async function inspectApiSession(ctx, sessionId, signal) {
138
138
  if (observation.header.cwd === undefined) {
139
139
  throw new ApiSessionNotFound(`session "${sessionId}" not found`);
140
140
  }
141
- return { meta: observation.header, events: [...observation.events] };
141
+ return {
142
+ meta: observation.header,
143
+ inheritedEventCount: observation.inheritedEventCount,
144
+ events: [...observation.events],
145
+ };
142
146
  }
143
147
  catch (e_1) {
144
148
  env_1.error = e_1;
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import type { AttachmentIdType, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
11
11
  import type { MessageId } from '@deepseek-ai/dsh-llm/brand';
12
- import type { SessionId } from '@deepseek-ai/dsh-session/types';
12
+ import type { SessionId, SessionSeq } from '@deepseek-ai/dsh-session/types';
13
13
  import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
14
14
  import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
15
15
  import type { PromptContentPart, QueueAction, SessionRequestId } from '../../types.ts';
@@ -28,6 +28,8 @@ export type PendingSubmissionRetirement = {
28
28
  };
29
29
  /** Input registering one local submission echo ahead of its prompt call. */
30
30
  export interface BeginSubmissionInput {
31
+ /** Delivery mode used with the upcoming prompt. */
32
+ readonly mode: 'queue' | 'steer';
31
33
  /** Prompt text exactly as the upcoming prompt will send it. */
32
34
  readonly text: string;
33
35
  /** Ordered image previews matching the upcoming prompt's image parts. */
@@ -113,13 +115,22 @@ export interface ISession {
113
115
  */
114
116
  rename(title: string): Promise<RemoteResult<{
115
117
  title: string;
116
- seq: number;
118
+ seq: SessionSeq;
117
119
  }>>;
118
120
  /**
119
121
  * Extend the history window backwards (older messages pagination).
120
122
  * @returns completion; failures land in snapshot.openState/loadingOlder.
121
123
  */
122
124
  loadOlder(): Promise<void>;
125
+ /**
126
+ * Page history backwards until the window covers `seq` (inclusive) — the
127
+ * turn-jump loader. Repeated calls while a jump is paging lower its shared
128
+ * target and return the in-flight completion; `snapshot.loadingOlder` is
129
+ * the busy signal for the whole jump.
130
+ * @param seq - durable event seq the window must reach (a turn's `turn/start` seq).
131
+ * @returns completion once covered, exhausted, superseded, or failed soft.
132
+ */
133
+ loadThrough(seq: SessionSeq): Promise<void>;
123
134
  /**
124
135
  * Execute one slash-command line against this session's agent — pure
125
136
  * admission semantics (the host executor durably logs the lifecycle).
@@ -27,6 +27,8 @@ export interface PendingSubmissionImage {
27
27
  /** Intrinsic pixel height, when the submitter has probed it. */
28
28
  readonly height?: number;
29
29
  }
30
+ /** Client surface selected when a local submission begins. */
31
+ export type PendingSubmissionPlacement = 'transcript' | 'queued' | 'steering';
30
32
  /**
31
33
  * One local prompt-submission echo: inserted synchronously when a submission
32
34
  * begins, so the conversation can show the message before serialization,
@@ -36,6 +38,8 @@ export interface PendingSubmissionImage {
36
38
  export interface PendingSubmission {
37
39
  /** The prompt RPC identity; the durable `user/message` source echoes it as `rpcId`. */
38
40
  readonly requestId: SessionRequestId;
41
+ /** Expected surface until the Host reports the admitted queue or durable occurrence. */
42
+ readonly placement: PendingSubmissionPlacement;
39
43
  /** Client wall-clock ms when the submission began. */
40
44
  readonly time: number;
41
45
  /** Prompt text exactly as it will be sent (one text block). */
@@ -13,7 +13,7 @@ export type { BeginSubmissionInput, ISession, PendingSubmissionRetirement, Proje
13
13
  export type { ISessions } from './contract/sessions.ts';
14
14
  export { MutableSessionEventSource } from './contract/events.ts';
15
15
  export type { SessionEventChange, SessionEventLike, SessionEventLikeEntry, SessionEventSource, SessionEventWindow, SessionLiveEventEntry, } from './contract/events.ts';
16
- export type { OpenState, PendingSubmission, PendingSubmissionImage, PromptError, QueuedMessage, SessionSnapshot, } from './contract/snapshot.ts';
16
+ export type { OpenState, PendingSubmission, PendingSubmissionImage, PendingSubmissionPlacement, PromptError, QueuedMessage, SessionSnapshot, } from './contract/snapshot.ts';
17
17
  declare module '@deepseek-ai/cordis' {
18
18
  interface Context {
19
19
  /** Client Session object layer and Agent scope owner. */
@@ -1,5 +1,5 @@
1
1
  import type { SubagentAddress, SubagentCatalog } from '@deepseek-ai/dsh-subagent/client';
2
- import type { SessionId } from '@deepseek-ai/dsh-session/types';
2
+ import { SessionSeq, type SessionId } from '@deepseek-ai/dsh-session/types';
3
3
  import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types';
4
4
  import type { SessionControlFrame, SessionSummary, SessionJob as JobView } from '../../types.ts';
5
5
  import type { RemoteFailure, RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
@@ -193,7 +193,7 @@ export declare class SessionManager {
193
193
  */
194
194
  fork(opts: {
195
195
  sessionId: SessionId;
196
- atSeq?: number;
196
+ atSeq?: SessionSeq;
197
197
  }): Promise<RemoteResult<{
198
198
  sessionId: SessionId;
199
199
  }>>;
@@ -1,12 +1,16 @@
1
1
  // SessionManager: the instance cluster Map<SessionId, Session> (lazy-built, resident) + the frame
2
2
  // dispatch entry + list state, constructed and held by ClientSessions (one per browser client).
3
3
  // List data never enters zustand; React connects via subscribe/getListSnapshot.
4
+ import { SessionSeq } from '@deepseek-ai/dsh-session/types';
4
5
  import { mergeOrderedBaseline } from "../ordered-baseline.js";
5
6
  import { isRemoteFailure } from '@deepseek-ai/dsh-api-gateway/client';
6
7
  import { flattenLineage } from "./lineage.js";
7
8
  import { Notifier } from "./notifier.js";
8
9
  import { ProjectionValueStore } from "./projection-store.js";
9
10
  import { Session } from "./session.js";
11
+ function sessionSeqCursor(value) {
12
+ return value === -1 ? -1 : SessionSeq(value);
13
+ }
10
14
  function catalogAvailability(parentAvailable) {
11
15
  return parentAvailable === undefined ? {} : { parentAvailable };
12
16
  }
@@ -404,7 +408,7 @@ export class SessionManager {
404
408
  const store = this.projectionStore(s.sessionId);
405
409
  const values = block.values;
406
410
  for (const key of Object.keys(values))
407
- store.apply(key, values[key], block.asOfSeq);
411
+ store.apply(key, values[key], sessionSeqCursor(block.asOfSeq));
408
412
  }
409
413
  }
410
414
  else {
@@ -552,7 +556,7 @@ export class SessionManager {
552
556
  return;
553
557
  }
554
558
  if (frame.type === 'projection') {
555
- this.projectionStore(frame.sessionId).apply(frame.key, frame.value, frame.seq);
559
+ this.projectionStore(frame.sessionId).apply(frame.key, frame.value, SessionSeq(frame.seq));
556
560
  this.notifier.markDirty();
557
561
  return;
558
562
  }
@@ -579,8 +583,9 @@ export class SessionManager {
579
583
  }
580
584
  for (const [sessionId, block] of Object.entries(baseline.projections)) {
581
585
  const store = this.projectionStore(sessionId);
582
- store.truncate(block.asOfSeq);
583
- store.seed(block);
586
+ const asOfSeq = sessionSeqCursor(block.asOfSeq);
587
+ store.truncate(asOfSeq);
588
+ store.seed({ ...block, asOfSeq });
584
589
  }
585
590
  for (const [sessionId, session] of this.sessions) {
586
591
  session.replaceControl(this.queues.get(sessionId) ?? []);
@@ -598,7 +603,7 @@ export class SessionManager {
598
603
  if (projections !== undefined) {
599
604
  const store = this.projectionStore(summary.sessionId);
600
605
  for (const [key, value] of Object.entries(projections.values)) {
601
- store.apply(key, value, projections.asOfSeq);
606
+ store.apply(key, value, sessionSeqCursor(projections.asOfSeq));
602
607
  }
603
608
  }
604
609
  if (summary.origin === 'subagent' && summary.parentSessionId !== undefined) {
@@ -9,6 +9,7 @@
9
9
  * bare observable faces feed `useProjection` (ui-renderer binds them).
10
10
  */
11
11
  import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types';
12
+ import type { SessionSeqCursor } from '@deepseek-ai/dsh-session/types';
12
13
  import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
13
14
  export type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types';
14
15
  /**
@@ -31,7 +32,7 @@ export type UseProjection = {
31
32
  */
32
33
  export interface ProjectionsBaseline {
33
34
  /** The consistent-cut seq (equals the window tail seq by construction). */
34
- asOfSeq: number;
35
+ asOfSeq: SessionSeqCursor;
35
36
  /** Whole current values by key; a registered key absent here means the capability is absent. */
36
37
  values: Readonly<Record<string, unknown>>;
37
38
  }
@@ -84,7 +85,7 @@ export declare class ProjectionValueStore {
84
85
  * @param value - whole value computed by the host unit.
85
86
  * @param seq - the unit's watermark at emission.
86
87
  */
87
- apply(key: string, value: unknown, seq: number): void;
88
+ apply(key: string, value: unknown, seq: SessionSeqCursor): void;
88
89
  /**
89
90
  * Seed from a history tail page's projections block: every carried key
90
91
  * lands under the same seq rule as frames; a key the block omits is
@@ -101,7 +102,7 @@ export declare class ProjectionValueStore {
101
102
  * baseline immediately afterward.
102
103
  * @param lastSeq - highest durable sequence reflected by the baseline.
103
104
  */
104
- truncate(lastSeq: number): void;
105
+ truncate(lastSeq: SessionSeqCursor): void;
105
106
  private changed;
106
107
  private channel;
107
108
  }
@@ -1,6 +1,9 @@
1
1
  const QUEUE_PREVIEW_CHARS = 200;
2
+ // Image blocks are excluded: queue presentation renders them as thumbnails
3
+ // from `content`, so the text preview covers only what has no visual form.
2
4
  function previewOf(content) {
3
5
  const flat = content
6
+ .filter(block => block.type !== 'image')
4
7
  .map(block => (block.type === 'text' ? block.text : `[${block.type}]`))
5
8
  .join(' ').replace(/\s+/g, ' ').trim();
6
9
  const chars = Array.from(flat);
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import type { Context } from '@deepseek-ai/cordis';
18
18
  import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client';
19
- import type { SessionId } from '@deepseek-ai/dsh-session/types';
19
+ import { type SessionId } from '@deepseek-ai/dsh-session/types';
20
20
  import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types';
21
21
  import type { SessionJob as JobView } from '../../types.ts';
22
22
  import type { SessionProjectionMap } from '@deepseek-ai/dsh-session-projection/types';
@@ -1,3 +1,4 @@
1
+ import { SessionSeq } from '@deepseek-ai/dsh-session/types';
1
2
  import { workspaceTitleOf } from '@deepseek-ai/dsh-util-workspace-path';
2
3
  import { SESSION_SEARCH_RESULT_LIMIT } from "../../types.js";
3
4
  import { createSnapshotStore, } from '@deepseek-ai/dsh-client-store';
@@ -297,7 +298,7 @@ export class ClientSessions {
297
298
  // Flooring lands inside the anchor's own turn (every turn opens with a
298
299
  // turn/start), so the host's first-turn/end-at-or-after cut still ends
299
300
  // on that turn — never clipped back to the previous one.
300
- ...(opts.atSeq === undefined ? {} : { atSeq: Math.floor(opts.atSeq) }),
301
+ ...(opts.atSeq === undefined ? {} : { atSeq: SessionSeq(Math.floor(opts.atSeq)) }),
301
302
  });
302
303
  if (!result.ok)
303
304
  throw new SessionForkError(result.error, opts.sessionId);
@@ -2,7 +2,7 @@ import type { Context } from '@deepseek-ai/cordis';
2
2
  import type { AttachmentIdType, ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
3
3
  import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client';
4
4
  import type { MessageId } from '@deepseek-ai/dsh-llm/brand';
5
- import type { SessionId } from '@deepseek-ai/dsh-session/types';
5
+ import { SessionSeq, type SessionId } from '@deepseek-ai/dsh-session/types';
6
6
  import type { PromptContentPart, QueueAction, SessionControlFrame, SessionQueuedItem, SessionRequestId } from '../../types.ts';
7
7
  import type { BeginSubmissionInput, SessionFace, SubmissionHandle } from '../contract/session.ts';
8
8
  import type { SessionSnapshot } from '../contract/snapshot.ts';
@@ -12,6 +12,8 @@ import type { SessionRemotes } from './remotes.ts';
12
12
  import { ProjectionValueStore } from './projection-store.ts';
13
13
  /** Messages requested per history page. */
14
14
  export declare const PAGE_MESSAGES = 50;
15
+ /** Messages requested per page while a turn jump loops backwards (fewer, larger round trips). */
16
+ export declare const JUMP_PAGE_MESSAGES = 200;
15
17
  /** Manager-owned observers of a Session object's local state edges. */
16
18
  export interface SessionOptions {
17
19
  /** Catalog-discovered address selecting non-activating subagent transport. */
@@ -53,6 +55,10 @@ export declare class Session implements SessionFace {
53
55
  * passes drop all writes once the generation moves on. */
54
56
  private openGeneration;
55
57
  private loadingOlder;
58
+ /** Shared low-water target of the running jump loop; null when no jump is paging. */
59
+ private jumpTargetSeq;
60
+ /** The running jump loop's completion, shared by retargeting callers. */
61
+ private jumpPromise;
56
62
  /** Authoritative stream-only inbox snapshot; pending work never hits history. */
57
63
  private readonly queueMirror;
58
64
  private running;
@@ -173,7 +179,7 @@ export declare class Session implements SessionFace {
173
179
  */
174
180
  rename(title: string): Promise<RemoteResult<{
175
181
  title: string;
176
- seq: number;
182
+ seq: SessionSeq;
177
183
  }>>;
178
184
  /**
179
185
  * Execute one slash-command line against this session's agent — pure
@@ -189,6 +195,8 @@ export declare class Session implements SessionFace {
189
195
  open(): Promise<void>;
190
196
  /** Page up: pull one earlier page with the window's first seq as beforeSeq and prepend. */
191
197
  loadOlder(): Promise<void>;
198
+ /** Jump loader: page backwards until the window covers seq (see ISession.loadThrough). */
199
+ loadThrough(seq: SessionSeq): Promise<void>;
192
200
  /** Rebuild an opened history source after address replacement.
193
201
  * Invalidates any in-flight open first; queue state belongs to the independently
194
202
  * reconnecting control stream and remains untouched. */