@deepseek-ai/dsh-api-session-controller 0.1.5-rc.2 → 0.1.6-alpha.2

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.
Files changed (39) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +20 -4
  3. package/README.zh.md +26 -10
  4. package/lib/client.js +432 -474
  5. package/lib/index.js +18 -49
  6. package/lib/typert.host.js +242 -200
  7. package/lib/typert.remote-client.js +195 -165
  8. package/lib/types/agent.d.ts +1 -1
  9. package/lib/types/agent.js +8 -1
  10. package/lib/types/client/contract/sessions.d.ts +55 -20
  11. package/lib/types/client/contract/snapshot.d.ts +0 -14
  12. package/lib/types/client/index.d.ts +11 -2
  13. package/lib/types/client/index.js +16 -5
  14. package/lib/types/client/scope.d.ts +13 -3
  15. package/lib/types/client/scope.js +15 -22
  16. package/lib/types/client/sessions/lineage.d.ts +1 -4
  17. package/lib/types/client/sessions/lineage.js +1 -3
  18. package/lib/types/client/sessions/manager.d.ts +28 -49
  19. package/lib/types/client/sessions/manager.js +75 -174
  20. package/lib/types/client/sessions/projection-store.d.ts +5 -11
  21. package/lib/types/client/sessions/projection-store.js +6 -14
  22. package/lib/types/client/sessions/service.d.ts +34 -119
  23. package/lib/types/client/sessions/service.js +259 -244
  24. package/lib/types/client/sessions/session.d.ts +7 -20
  25. package/lib/types/client/sessions/session.js +29 -33
  26. package/lib/types/client/time-zone.d.ts +1 -1
  27. package/lib/types/client/time-zone.js +1 -1
  28. package/lib/types/commands.d.ts +2 -2
  29. package/lib/types/commands.js +13 -8
  30. package/lib/types/control.d.ts +1 -1
  31. package/lib/types/control.js +1 -41
  32. package/lib/types/history.js +1 -0
  33. package/lib/types/index.d.ts +2 -2
  34. package/lib/types/index.js +2 -1
  35. package/lib/types/skill-catalog.js +1 -0
  36. package/lib/types/types.d.ts +5 -17
  37. package/package.json +72 -69
  38. package/lib/types/client/sessions/queue-mirror.d.ts +0 -26
  39. package/lib/types/client/sessions/queue-mirror.js +0 -61
@@ -3,7 +3,7 @@ import type { AttachmentIdType, ImageAttachmentRef } from '@deepseek-ai/dsh-atta
3
3
  import type { SubagentAddress } from '@deepseek-ai/dsh-subagent/client';
4
4
  import type { MessageId } from '@deepseek-ai/dsh-llm/brand';
5
5
  import { SessionSeq, type SessionId } from '@deepseek-ai/dsh-session/types';
6
- import type { PromptContentPart, QueueAction, SessionControlFrame, SessionQueuedItem, SessionRequestId } from '../../types.ts';
6
+ import type { PromptContentPart, QueueAction, SessionRequestId } from '../../types.ts';
7
7
  import type { BeginSubmissionInput, SessionFace, SubmissionHandle } from '../contract/session.ts';
8
8
  import type { SessionSnapshot } from '../contract/snapshot.ts';
9
9
  import { MutableSessionEventSource } from '../contract/events.ts';
@@ -59,8 +59,7 @@ export declare class Session implements SessionFace {
59
59
  private jumpTargetSeq;
60
60
  /** The running jump loop's completion, shared by retargeting callers. */
61
61
  private jumpPromise;
62
- /** Authoritative stream-only inbox snapshot; pending work never hits history. */
63
- private readonly queueMirror;
62
+ private readonly stopObservingInbox;
64
63
  private readonly assistantStream;
65
64
  private running;
66
65
  private address;
@@ -81,7 +80,7 @@ export declare class Session implements SessionFace {
81
80
  /** Local submission echoes, insertion-ordered (see SessionSnapshot.pendingSubmissions). */
82
81
  private pendingSubmissions;
83
82
  /** Per-echo settlement state; `retiring` latches the first observation so a
84
- * queue frame and its durable event cannot both retire one echo. */
83
+ * Inbox projection and its durable event cannot both retire one echo. */
85
84
  private readonly submissionSettlements;
86
85
  /** Owns the addressed page/follow lifecycle while this Session is open. */
87
86
  private events;
@@ -199,7 +198,7 @@ export declare class Session implements SessionFace {
199
198
  /** Jump loader: page backwards until the window covers seq (see ISession.loadThrough). */
200
199
  loadThrough(seq: SessionSeq): Promise<void>;
201
200
  /** Rebuild an opened history source after address replacement.
202
- * Invalidates any in-flight open first; queue state belongs to the independently
201
+ * Invalidates any in-flight open first; projection state belongs to the independently
203
202
  * reconnecting control stream and remains untouched. */
204
203
  resync(): Promise<void>;
205
204
  /**
@@ -213,18 +212,6 @@ export declare class Session implements SessionFace {
213
212
  * @returns the cached reference (stable until the next flush).
214
213
  */
215
214
  getSnapshot(): SessionSnapshot;
216
- /**
217
- * Replace every transient control value for this Session from one stream baseline.
218
- * @param queue - complete pending queue for this Session.
219
- */
220
- replaceControl(queue: readonly SessionQueuedItem[]): void;
221
- /**
222
- * Apply one Session-addressed live control update.
223
- * @param frame - queue replacement addressed to this Session.
224
- */
225
- handleControlFrame(frame: Extract<SessionControlFrame, {
226
- type: 'queue';
227
- }>): void;
228
215
  /**
229
216
  * Running-bit relay from the host stream (list entry and snapshot stay consistent).
230
217
  * @param running - the new running state.
@@ -273,10 +260,10 @@ export declare class Session implements SessionFace {
273
260
  private prependWindow;
274
261
  /** Append one stream-validated live event. */
275
262
  private appendLive;
276
- /** Retire the matching echo when a durable browser-prompt `user/message` becomes visible. */
263
+ /** Observe durable acceptance even when insertion and claim share one projection notification. */
277
264
  private observeSubmissionEvent;
278
- /** Retire echoes whose prompts landed in the host inbox instead of the log (running-turn submissions). */
279
- private observeSubmissionQueue;
265
+ /** Retire local echoes when their accepted messages appear in the durable Inbox projection. */
266
+ private observeSubmissionInbox;
280
267
  /**
281
268
  * Latch one observed settlement and remove the echo an animation frame
282
269
  * later. The delay keeps the echo in the snapshot until the frame in which
@@ -8,7 +8,6 @@ import { isRemoteFailure } from '@deepseek-ai/dsh-api-gateway/client';
8
8
  import { RemoteError } from '@deepseek-ai/dsh-typert-protocol';
9
9
  import { ProjectionValueStore } from "./projection-store.js";
10
10
  import { resolvedClientTimeZone } from "../time-zone.js";
11
- import { SessionQueueMirror } from "./queue-mirror.js";
12
11
  import { ClientAssistantStream, } from "./assistant-stream.js";
13
12
  function projectionsBaseline(value) {
14
13
  return {
@@ -44,8 +43,7 @@ export class Session {
44
43
  jumpTargetSeq = null;
45
44
  /** The running jump loop's completion, shared by retargeting callers. */
46
45
  jumpPromise = null;
47
- /** Authoritative stream-only inbox snapshot; pending work never hits history. */
48
- queueMirror = new SessionQueueMirror();
46
+ stopObservingInbox;
49
47
  assistantStream = new ClientAssistantStream();
50
48
  running = false;
51
49
  address;
@@ -66,7 +64,7 @@ export class Session {
66
64
  /** Local submission echoes, insertion-ordered (see SessionSnapshot.pendingSubmissions). */
67
65
  pendingSubmissions = [];
68
66
  /** Per-echo settlement state; `retiring` latches the first observation so a
69
- * queue frame and its durable event cannot both retire one echo. */
67
+ * Inbox projection and its durable event cannot both retire one echo. */
70
68
  submissionSettlements = new Map();
71
69
  /** Owns the addressed page/follow lifecycle while this Session is open. */
72
70
  events;
@@ -111,6 +109,9 @@ export class Session {
111
109
  this.snapshotCache = this.buildSnapshot();
112
110
  });
113
111
  this.snapshotCache = this.buildSnapshot();
112
+ this.stopObservingInbox = this.projections.faceOf('inbox').subscribe(() => {
113
+ this.observeSubmissionInbox();
114
+ });
114
115
  }
115
116
  /**
116
117
  * Bind the Agent-scoped context minted by ClientSessions (single write;
@@ -384,7 +385,7 @@ export class Session {
384
385
  return this.jumpPromise;
385
386
  }
386
387
  /** Rebuild an opened history source after address replacement.
387
- * Invalidates any in-flight open first; queue state belongs to the independently
388
+ * Invalidates any in-flight open first; projection state belongs to the independently
388
389
  * reconnecting control stream and remains untouched. */
389
390
  async resync() {
390
391
  if (this.openState === 'cold')
@@ -418,24 +419,6 @@ export class Session {
418
419
  return this.snapshotCache;
419
420
  }
420
421
  // ---- Manager-only entry points (@internal; never called by the UI) ----
421
- /**
422
- * Replace every transient control value for this Session from one stream baseline.
423
- * @param queue - complete pending queue for this Session.
424
- */
425
- replaceControl(queue) {
426
- this.queueMirror.replace(queue);
427
- this.observeSubmissionQueue(queue);
428
- this.notifier.markDirty();
429
- }
430
- /**
431
- * Apply one Session-addressed live control update.
432
- * @param frame - queue replacement addressed to this Session.
433
- */
434
- handleControlFrame(frame) {
435
- this.queueMirror.replace(frame.items);
436
- this.observeSubmissionQueue(frame.items);
437
- this.notifier.markDirty();
438
- }
439
422
  /**
440
423
  * Running-bit relay from the host stream (list entry and snapshot stay consistent).
441
424
  * @param running - the new running state.
@@ -514,6 +497,7 @@ export class Session {
514
497
  * @returns when the Remote iterator has completed teardown.
515
498
  */
516
499
  async dispose() {
500
+ this.stopObservingInbox();
517
501
  // Unsettled echoes retire as failed so their owners can restore or
518
502
  // release browser resources; echoes already scheduled as observed keep
519
503
  // that settlement.
@@ -635,17 +619,26 @@ export class Session {
635
619
  const awaitingFirstTurn = this.firstPromptPendingTurn;
636
620
  if (event.type === 'turn/start')
637
621
  this.firstPromptPendingTurn = false;
638
- const queueChanged = this.queueMirror.acceptDurable(event);
639
622
  this.eventSource.append(entry);
640
623
  // After the feed append: the conversation assembly's animation frame is
641
624
  // registered by the feed subscribers above, so the echo-retirement frame
642
625
  // scheduled here always runs after the durable node became renderable.
643
626
  this.observeSubmissionEvent(event);
644
- return queueChanged || awaitingFirstTurn !== this.firstPromptPendingTurn;
627
+ return awaitingFirstTurn !== this.firstPromptPendingTurn;
645
628
  }
646
- /** Retire the matching echo when a durable browser-prompt `user/message` becomes visible. */
629
+ /** Observe durable acceptance even when insertion and claim share one projection notification. */
647
630
  observeSubmissionEvent(event) {
648
- if (this.submissionSettlements.size === 0 || event.type !== 'user/message')
631
+ if (this.submissionSettlements.size === 0)
632
+ return;
633
+ if (event.type === 'agent/inbox/spliced') {
634
+ const splice = event.data;
635
+ if (Array.isArray(splice?.inserted)) {
636
+ for (const message of splice.inserted)
637
+ this.observeSubmissionEvent({ type: 'user/message', data: message });
638
+ }
639
+ return;
640
+ }
641
+ if (event.type !== 'user/message')
649
642
  return;
650
643
  // Structural read: window entries may be compact history records, so the
651
644
  // fields are narrowed rather than trusted (same posture as Conversation
@@ -656,13 +649,17 @@ export class Session {
656
649
  return;
657
650
  this.scheduleObservedRetirement(source.rpcId, attachmentRefsIn(data?.content));
658
651
  }
659
- /** Retire echoes whose prompts landed in the host inbox instead of the log (running-turn submissions). */
660
- observeSubmissionQueue(items) {
652
+ /** Retire local echoes when their accepted messages appear in the durable Inbox projection. */
653
+ observeSubmissionInbox() {
661
654
  if (this.submissionSettlements.size === 0)
662
655
  return;
663
- for (const item of items) {
664
- if (item.rpcId !== undefined) {
665
- this.scheduleObservedRetirement(item.rpcId, attachmentRefsIn(item.message.content));
656
+ const inbox = this.projections.get('inbox');
657
+ if (inbox === undefined)
658
+ return;
659
+ for (const message of [...inbox['next-turn'], ...inbox['next-step']]) {
660
+ const source = message.source;
661
+ if (source.kind === 'user' && 'rpcId' in source) {
662
+ this.scheduleObservedRetirement(source.rpcId, attachmentRefsIn(message.content));
666
663
  }
667
664
  }
668
665
  }
@@ -715,7 +712,6 @@ export class Session {
715
712
  buildSnapshot() {
716
713
  return {
717
714
  sessionId: this.sessionId,
718
- queue: this.queueMirror.snapshot(),
719
715
  pendingSubmissions: this.pendingSubmissions,
720
716
  running: this.running,
721
717
  subagent: this.address === undefined
@@ -1,4 +1,4 @@
1
- /** Browser-owned time-zone sampling for prompt RPC provenance. */
1
+ /** Browser-owned time-zone sampling for one prompt RPC. */
2
2
  /**
3
3
  * Resolve the current browser IANA zone for one outbound operation.
4
4
  * @returns The browser-provided canonical zone.
@@ -1,4 +1,4 @@
1
- /** Browser-owned time-zone sampling for prompt RPC provenance. */
1
+ /** Browser-owned time-zone sampling for one prompt RPC. */
2
2
  /**
3
3
  * Resolve the current browser IANA zone for one outbound operation.
4
4
  * @returns The browser-provided canonical zone.
@@ -50,11 +50,11 @@ export declare class SessionCommandController {
50
50
  */
51
51
  attachment(request: SessionAttachmentRequest): Promise<SessionAttachmentValue>;
52
52
  /**
53
- * Mutate one still-pending queue occurrence without resuming a cold Agent.
53
+ * Mutate one pending Inbox occurrence, restoring an ordinary cold Agent when needed.
54
54
  * @param request - Session, queue item, and requested mutation.
55
55
  * @returns acknowledgement that the queue mutation was applied.
56
56
  */
57
- updateQueue(request: SessionUpdateQueueRequest): SessionUpdateQueueValue;
57
+ updateQueue(request: SessionUpdateQueueRequest): Promise<SessionUpdateQueueValue>;
58
58
  /**
59
59
  * Cancel one live ordinary Agent while retaining pending inbox work.
60
60
  * @param request - Session whose active Agent turn is cancelled.
@@ -221,10 +221,7 @@ export class SessionCommandController {
221
221
  ? `session "${request.sessionId}" has not completed the turn containing event ${String(atSeq)}`
222
222
  : `session "${request.sessionId}" has no completed turn to fork from`, { sessionId: request.sessionId });
223
223
  }
224
- let cut = SessionLogOffset(boundary.seq + 1);
225
- while (cut < source.events.length && source.events[cut]?.type !== 'turn/start') {
226
- cut = SessionLogOffset(cut + 1);
227
- }
224
+ const cut = SessionLogOffset(boundary.seq + 1);
228
225
  let workspace;
229
226
  try {
230
227
  workspace = await this.forkWorkspace(source.header);
@@ -380,11 +377,11 @@ export class SessionCommandController {
380
377
  }
381
378
  }
382
379
  /**
383
- * Mutate one still-pending queue occurrence without resuming a cold Agent.
380
+ * Mutate one pending Inbox occurrence, restoring an ordinary cold Agent when needed.
384
381
  * @param request - Session, queue item, and requested mutation.
385
382
  * @returns acknowledgement that the queue mutation was applied.
386
383
  */
387
- updateQueue(request) {
384
+ async updateQueue(request) {
388
385
  if (request.action.kind === 'edit') {
389
386
  if (request.action.content.some(block => block.type !== 'text')) {
390
387
  throw new RemoteError('session/attachment-invalid', 'queue edits accept text content only', { reason: 'QUEUE_EDIT_NON_TEXT' });
@@ -393,9 +390,15 @@ export class SessionCommandController {
393
390
  throw new RemoteError('gateway/bad-request', 'queue edit content must include non-whitespace text', {});
394
391
  }
395
392
  }
396
- const agent = this.ctx.agents.get(request.sessionId);
393
+ let agent = this.ctx.agents.get(request.sessionId);
397
394
  if (agent === undefined) {
398
- throw new RemoteError('session/queue-item-not-found', 'queued item is no longer pending', { itemId: request.itemId });
395
+ const found = await this.agents.resolveAgent(request.sessionId);
396
+ if ('error' in found) {
397
+ if (found.error.code !== 'session/not-found')
398
+ throw found.error;
399
+ throw new RemoteError('session/queue-item-not-found', 'queued item is no longer pending', { itemId: request.itemId });
400
+ }
401
+ agent = found.agent;
399
402
  }
400
403
  if (hasApiSessionSubagentOwner(this.ctx, agent.session, agent)) {
401
404
  const identity = this.ctx.sessionProjections
@@ -490,6 +493,7 @@ export class SessionCommandController {
490
493
  async readSessionState(sessionId) {
491
494
  const attached = this.ctx.sessions.get(sessionId);
492
495
  if (attached !== undefined) {
496
+ // oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
493
497
  return { id: attached.id, header: attached.header, events: attached.snapshotEvents() };
494
498
  }
495
499
  const inspected = await inspectApiSession(this.ctx, sessionId);
@@ -530,6 +534,7 @@ function hasPromptRequest(agent, requestId) {
530
534
  };
531
535
  if (agent.inbox.nextTurn.some(matches) || agent.inbox.nextStep.some(matches))
532
536
  return true;
537
+ // oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
533
538
  return agent.session.snapshotEvents().some((event) => {
534
539
  if (event.type !== 'user/message')
535
540
  return false;
@@ -1,4 +1,4 @@
1
- /** Live Session queue, jobs, and projection state with reconnect baselines. */
1
+ /** Live Session jobs and projection state with reconnect baselines. */
2
2
  import type { Context } from '@deepseek-ai/cordis';
3
3
  import type { SessionControlFrame } from './types.ts';
4
4
  /** Owns the Host-wide Session control stream. */
@@ -1,4 +1,4 @@
1
- /** Live Session queue, jobs, and projection state with reconnect baselines. */
1
+ /** Live Session jobs and projection state with reconnect baselines. */
2
2
  import { Deque } from '@deepseek-ai/dsh-deque';
3
3
  /** Owns the Host-wide Session control stream. */
4
4
  export class SessionControlController {
@@ -15,16 +15,6 @@ export class SessionControlController {
15
15
  value: value,
16
16
  seq,
17
17
  });
18
- if (key !== 'inbox')
19
- return;
20
- const agent = this.ctx.agents.get(session.id);
21
- if (agent?.session !== session)
22
- return;
23
- this.broadcast({
24
- type: 'queue',
25
- sessionId: session.id,
26
- items: queueItemsFromInbox(value),
27
- });
28
18
  });
29
19
  ctx.inject(['jobs'], (jobsCtx) => {
30
20
  jobsCtx.jobs.onJobsChanged((owner) => { this.onJobsChanged(owner); });
@@ -60,15 +50,12 @@ export class SessionControlController {
60
50
  }
61
51
  baseline() {
62
52
  const sessions = this.ctx.sessions.list();
63
- const queues = Object.create(null);
64
53
  const jobs = Object.create(null);
65
54
  for (const session of sessions) {
66
55
  const agent = this.ctx.agents.get(session.id);
67
- queues[session.id] = agent?.session === session ? queueItems(agent) : [];
68
56
  jobs[session.id] = this.jobsFor(agent);
69
57
  }
70
58
  return {
71
- queues,
72
59
  jobs,
73
60
  projections: this.projectionBaseline(sessions),
74
61
  };
@@ -148,33 +135,6 @@ class ControlQueue {
148
135
  }
149
136
  }
150
137
  }
151
- function queueItems(agent) {
152
- return queueItemsFromInbox({
153
- 'next-turn': agent.inbox.nextTurn,
154
- 'next-step': agent.inbox.nextStep,
155
- });
156
- }
157
- function queueItemsFromInbox(inbox) {
158
- return [
159
- ...inbox['next-turn'].map(message => ({
160
- id: message.id,
161
- placement: 'queued',
162
- ...promptRpcId(message),
163
- message: { id: message.id, content: message.content },
164
- })),
165
- ...inbox['next-step'].map(message => ({
166
- id: message.id,
167
- placement: message.source.kind === 'user' ? 'steering' : 'context',
168
- ...promptRpcId(message),
169
- message: { id: message.id, content: message.content },
170
- })),
171
- ];
172
- }
173
- /** Prompt-RPC identity carried by a browser-submitted message's user source. */
174
- function promptRpcId(message) {
175
- const source = message.source;
176
- return source.kind === 'user' && 'rpcId' in source ? { rpcId: source.rpcId } : {};
177
- }
178
138
  function jobView(job) {
179
139
  return {
180
140
  id: job.id,
@@ -167,6 +167,7 @@ export class SessionHistoryController {
167
167
  // Constructor seed events have no session/event notification. Normally
168
168
  // only the end-seed suffix is new; if persistence advanced after the
169
169
  // opening observation, replay everything beyond that snapshot cursor.
170
+ // oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
170
171
  const suffix = session.snapshotEvents(snapshotCursor === undefined
171
172
  ? session.firstLiveSeq
172
173
  : SessionLogOffset(snapshotCursor + 1));
@@ -143,11 +143,11 @@ export declare class SessionController extends TypertRemoteService {
143
143
  */
144
144
  attachment(request: SessionAttachmentRequest): Promise<SessionAttachmentValue>;
145
145
  /**
146
- * Mutate one still-pending queue occurrence on a live Agent.
146
+ * Mutate one still-pending queue occurrence, resuming a cold Agent first.
147
147
  * @param request - Session, queue item, and requested mutation.
148
148
  * @returns acknowledgement that the queue mutation was applied.
149
149
  */
150
- updateQueue(request: SessionUpdateQueueRequest): SessionUpdateQueueValue;
150
+ updateQueue(request: SessionUpdateQueueRequest): Promise<SessionUpdateQueueValue>;
151
151
  /**
152
152
  * Cancel one active Agent turn without dropping its pending inbox.
153
153
  * @param request - Session whose active Agent turn is cancelled.
@@ -281,6 +281,7 @@ let SessionController = (() => {
281
281
  return Promise.resolve({
282
282
  meta: attached.header,
283
283
  inheritedEventCount: attached.inheritedEventCount,
284
+ // oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
284
285
  events: attached.snapshotEvents(),
285
286
  });
286
287
  }
@@ -402,7 +403,7 @@ let SessionController = (() => {
402
403
  return this.commands.attachment(request);
403
404
  }
404
405
  /**
405
- * Mutate one still-pending queue occurrence on a live Agent.
406
+ * Mutate one still-pending queue occurrence, resuming a cold Agent first.
406
407
  * @param request - Session, queue item, and requested mutation.
407
408
  * @returns acknowledgement that the queue mutation was applied.
408
409
  */
@@ -159,6 +159,7 @@ let SessionSkillCatalog = (() => {
159
159
  return {
160
160
  skills: skills.map(skill => ({
161
161
  name: skill.name,
162
+ ...skill.path === undefined ? {} : { path: skill.path },
162
163
  description: skill.description,
163
164
  ...skill.whenToUse === undefined ? {} : { whenToUse: skill.whenToUse },
164
165
  modelInvocable: skill.invocation.modelInvocable,
@@ -172,6 +172,9 @@ declare module '@deepseek-ai/dsh-typert-protocol' {
172
172
  readonly requestedCwd: string;
173
173
  readonly existingCwd?: string;
174
174
  };
175
+ 'session/writer-held': {
176
+ readonly sessionId: SessionId;
177
+ };
175
178
  'session/agent-busy': {
176
179
  readonly reason: string;
177
180
  };
@@ -219,6 +222,8 @@ export interface SkillListRequest {
219
222
  }
220
223
  /** One skill available to the Session's human-facing composer. */
221
224
  export interface SkillEntry {
225
+ /** Absolute SKILL.md path when supplied by a filesystem provider. */
226
+ readonly path?: string;
222
227
  /** Kebab-case identifier referenced as `/name`. */
223
228
  readonly name: string;
224
229
  /** Short routing description. */
@@ -484,18 +489,6 @@ export type SessionFollowFrame = {
484
489
  readonly type: 'assistant-stream';
485
490
  readonly frame: SessionAssistantStreamFrame;
486
491
  };
487
- /** One pending inbox occurrence in the authoritative queue snapshot. */
488
- export interface SessionQueuedItem {
489
- readonly id: MessageId;
490
- readonly placement: 'queued' | 'steering' | 'context';
491
- /** Prompt-RPC identity from the queued message's user source; clients retire the matching local submission echo on it. */
492
- readonly rpcId?: SessionRequestId;
493
- /** JSON-safe message fields consumed by pending-queue presentation. */
494
- readonly message: {
495
- readonly id: MessageId;
496
- readonly content: readonly JsonValue[];
497
- };
498
- }
499
492
  /** Browser-safe background-job row. */
500
493
  export interface SessionJob {
501
494
  readonly id: JobId;
@@ -508,7 +501,6 @@ export interface SessionJob {
508
501
  }
509
502
  /** Complete live control baseline emitted once per control stream generation. */
510
503
  export interface SessionControlBaseline {
511
- readonly queues: Readonly<Record<SessionId, readonly SessionQueuedItem[]>>;
512
504
  readonly jobs: Readonly<Record<SessionId, readonly SessionJob[]>>;
513
505
  readonly projections: Readonly<Record<SessionId, SessionProjectionBaseline>>;
514
506
  }
@@ -523,10 +515,6 @@ export interface SessionProjectionUpdate {
523
515
  export type SessionControlFrame = {
524
516
  readonly type: 'baseline';
525
517
  readonly value: SessionControlBaseline;
526
- } | {
527
- readonly type: 'queue';
528
- readonly sessionId: SessionId;
529
- readonly items: readonly SessionQueuedItem[];
530
518
  } | {
531
519
  readonly type: 'jobs';
532
520
  readonly sessionId: SessionId;