@deepseek-ai/dsh-api-session-controller 0.1.3-alpha.2 → 0.1.5-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.
@@ -99,6 +99,10 @@ const _deepseek_ai_dsh_api_session_controller_session_control_result$schema = z.
99
99
  'projections': z.record(z.intersection(z.string(), z.unknown()), z.object({
100
100
  'asOfSeq': z.number().readonly(),
101
101
  'values': z.intersection(z.object({
102
+ 'inbox': z.object({
103
+ 'next-turn': z.array(z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))])).readonly(),
104
+ 'next-step': z.array(z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema4)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema4))])).readonly(),
105
+ }).optional(),
102
106
  'agentPreset': z.union([z.literal(null), z.string()]).optional(),
103
107
  'title': z.union([z.literal(null), z.string()]).optional(),
104
108
  'todos': z.union([z.literal(null), z.array(z.object({
@@ -129,6 +133,19 @@ const _deepseek_ai_dsh_api_session_controller_session_control_result$schema = z.
129
133
  'reasoningEffort': z.string().readonly().optional(),
130
134
  })]).readonly(),
131
135
  }).optional(),
136
+ 'subagentCatalog': z.array(z.union([z.intersection(z.object({
137
+ 'id': z.intersection(z.string(), z.unknown()).readonly(),
138
+ 'createdAt': z.number().readonly(),
139
+ }), z.object({
140
+ 'mode': z.literal("one-shot").readonly(),
141
+ 'label': z.string().readonly().optional(),
142
+ })), z.intersection(z.object({
143
+ 'id': z.intersection(z.string(), z.unknown()).readonly(),
144
+ 'createdAt': z.number().readonly(),
145
+ }), z.object({
146
+ 'mode': z.literal("continuable").readonly(),
147
+ 'label': z.string().readonly(),
148
+ }))])).optional(),
132
149
  'subagentTiming': z.object({
133
150
  'settledMs': z.number(),
134
151
  'active': z.object({
@@ -227,12 +244,8 @@ const _deepseek_ai_dsh_api_session_controller_session_follow_result$schema = z.u
227
244
  'time': z.number().readonly(),
228
245
  'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]).readonly(),
229
246
  'ignorable': z.literal(true).readonly().optional(),
230
- 'sourceEventSeqs': z.array(z.number()).readonly().optional(),
231
- 'surfaceOp': z.union([z.literal("append"), z.object({
232
- 'op': z.literal("replace").readonly(),
233
- 'start': z.number().readonly(),
234
- 'end': z.number().readonly(),
235
- })]).readonly().optional(),
247
+ 'sourceEventSeqs': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]).readonly().optional(),
248
+ 'surfaceOp': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]).readonly().optional(),
236
249
  }).readonly(),
237
250
  }), z.object({
238
251
  'type': z.literal("snapshot").readonly(),
@@ -256,18 +269,18 @@ const _deepseek_ai_dsh_api_session_controller_session_follow_result$schema = z.u
256
269
  'time': z.number().readonly(),
257
270
  'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]).readonly(),
258
271
  'ignorable': z.literal(true).readonly().optional(),
259
- 'sourceEventSeqs': z.array(z.number()).readonly().optional(),
260
- 'surfaceOp': z.union([z.literal("append"), z.object({
261
- 'op': z.literal("replace").readonly(),
262
- 'start': z.number().readonly(),
263
- 'end': z.number().readonly(),
264
- })]).readonly().optional(),
272
+ 'sourceEventSeqs': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]).readonly().optional(),
273
+ 'surfaceOp': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))]).readonly().optional(),
265
274
  }).readonly(),
266
275
  })).readonly(),
267
276
  'hasMore': z.boolean().readonly(),
268
277
  'projections': z.object({
269
278
  'asOfSeq': z.number().readonly(),
270
279
  'values': z.intersection(z.object({
280
+ 'inbox': z.object({
281
+ 'next-turn': z.array(z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))])).readonly(),
282
+ 'next-step': z.array(z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema3)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema3))])).readonly(),
283
+ }).optional(),
271
284
  'agentPreset': z.union([z.literal(null), z.string()]).optional(),
272
285
  'title': z.union([z.literal(null), z.string()]).optional(),
273
286
  'todos': z.union([z.literal(null), z.array(z.object({
@@ -298,6 +311,19 @@ const _deepseek_ai_dsh_api_session_controller_session_follow_result$schema = z.u
298
311
  'reasoningEffort': z.string().readonly().optional(),
299
312
  })]).readonly(),
300
313
  }).optional(),
314
+ 'subagentCatalog': z.array(z.union([z.intersection(z.object({
315
+ 'id': z.intersection(z.string(), z.unknown()).readonly(),
316
+ 'createdAt': z.number().readonly(),
317
+ }), z.object({
318
+ 'mode': z.literal("one-shot").readonly(),
319
+ 'label': z.string().readonly().optional(),
320
+ })), z.intersection(z.object({
321
+ 'id': z.intersection(z.string(), z.unknown()).readonly(),
322
+ 'createdAt': z.number().readonly(),
323
+ }), z.object({
324
+ 'mode': z.literal("continuable").readonly(),
325
+ 'label': z.string().readonly(),
326
+ }))])).optional(),
301
327
  'subagentTiming': z.object({
302
328
  'settledMs': z.number(),
303
329
  'active': z.object({
@@ -395,6 +421,10 @@ const _deepseek_ai_dsh_api_session_controller_session_list_result$schema = z.obj
395
421
  'projections': z.object({
396
422
  'asOfSeq': z.number().readonly(),
397
423
  'values': z.intersection(z.object({
424
+ 'inbox': z.object({
425
+ 'next-turn': z.array(z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))])).readonly(),
426
+ 'next-step': z.array(z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema))])).readonly(),
427
+ }).optional(),
398
428
  'agentPreset': z.union([z.literal(null), z.string()]).optional(),
399
429
  'title': z.union([z.literal(null), z.string()]).optional(),
400
430
  'todos': z.union([z.literal(null), z.array(z.object({
@@ -425,6 +455,19 @@ const _deepseek_ai_dsh_api_session_controller_session_list_result$schema = z.obj
425
455
  'reasoningEffort': z.string().readonly().optional(),
426
456
  })]).readonly(),
427
457
  }).optional(),
458
+ 'subagentCatalog': z.array(z.union([z.intersection(z.object({
459
+ 'id': z.intersection(z.string(), z.unknown()).readonly(),
460
+ 'createdAt': z.number().readonly(),
461
+ }), z.object({
462
+ 'mode': z.literal("one-shot").readonly(),
463
+ 'label': z.string().readonly().optional(),
464
+ })), z.intersection(z.object({
465
+ 'id': z.intersection(z.string(), z.unknown()).readonly(),
466
+ 'createdAt': z.number().readonly(),
467
+ }), z.object({
468
+ 'mode': z.literal("continuable").readonly(),
469
+ 'label': z.string().readonly(),
470
+ }))])).optional(),
428
471
  'subagentTiming': z.object({
429
472
  'settledMs': z.number(),
430
473
  'active': z.object({
@@ -492,6 +535,7 @@ const _deepseek_ai_dsh_api_session_controller_session_modelCatalog_result$schema
492
535
  })).readonly(),
493
536
  })
494
537
  const _deepseek_ai_dsh_api_session_controller_session_openWorkspacePath_parameter_0$schema = z.object({
538
+ 'action': z.literal("reveal").readonly().optional(),
495
539
  'path': z.string().readonly(),
496
540
  })
497
541
  const _deepseek_ai_dsh_api_session_controller_session_openWorkspacePath_result$schema = z.object({
@@ -520,12 +564,8 @@ const _deepseek_ai_dsh_api_session_controller_session_page_result$schema = z.obj
520
564
  'time': z.number().readonly(),
521
565
  'data': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]).readonly(),
522
566
  'ignorable': z.literal(true).readonly().optional(),
523
- 'sourceEventSeqs': z.array(z.number()).readonly().optional(),
524
- 'surfaceOp': z.union([z.literal("append"), z.object({
525
- 'op': z.literal("replace").readonly(),
526
- 'start': z.number().readonly(),
527
- 'end': z.number().readonly(),
528
- })]).readonly().optional(),
567
+ 'sourceEventSeqs': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]).readonly().optional(),
568
+ 'surfaceOp': z.union([z.literal(null), z.string(), z.number(), z.literal(false), z.literal(true), z.array(z.lazy(() => JsonValueRemoteCodec$schema2)), z.record(z.string(), z.lazy(() => JsonValueRemoteCodec$schema2))]).readonly().optional(),
529
569
  }).readonly(),
530
570
  })).readonly(),
531
571
  'hasMore': z.boolean().readonly(),
@@ -713,7 +753,7 @@ export const TYPERT_REMOTE = {
713
753
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionAttachmentValue',
714
754
  schema: _deepseek_ai_dsh_api_session_controller_session_attachment_result$schema,
715
755
  },
716
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":340,"column":3},
756
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":357,"column":3},
717
757
  },
718
758
  {
719
759
  id: '@deepseek-ai/dsh-api-session-controller#session/cancel',
@@ -738,7 +778,7 @@ export const TYPERT_REMOTE = {
738
778
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionCancelValue',
739
779
  schema: _deepseek_ai_dsh_api_session_controller_session_cancel_result$schema,
740
780
  },
741
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":360,"column":3},
781
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":377,"column":3},
742
782
  },
743
783
  {
744
784
  id: '@deepseek-ai/dsh-api-session-controller#session/canOpenWorkspacePath',
@@ -753,7 +793,7 @@ export const TYPERT_REMOTE = {
753
793
  typeSymbol: '@deepseek-ai/dsh-api-session-controller#session/canOpenWorkspacePath:result',
754
794
  schema: _deepseek_ai_dsh_api_session_controller_session_canOpenWorkspacePath_result$schema,
755
795
  },
756
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":265,"column":3},
796
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":272,"column":3},
757
797
  },
758
798
  {
759
799
  id: '@deepseek-ai/dsh-api-session-controller#session/control',
@@ -770,7 +810,7 @@ export const TYPERT_REMOTE = {
770
810
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionControlFrame',
771
811
  schema: _deepseek_ai_dsh_api_session_controller_session_control_result$schema,
772
812
  },
773
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":393,"column":3},
813
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":410,"column":3},
774
814
  },
775
815
  {
776
816
  id: '@deepseek-ai/dsh-api-session-controller#session/create',
@@ -795,7 +835,7 @@ export const TYPERT_REMOTE = {
795
835
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionCreateValue',
796
836
  schema: _deepseek_ai_dsh_api_session_controller_session_create_result$schema,
797
837
  },
798
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":237,"column":3},
838
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":244,"column":3},
799
839
  },
800
840
  {
801
841
  id: '@deepseek-ai/dsh-api-session-controller#session/follow',
@@ -822,7 +862,7 @@ export const TYPERT_REMOTE = {
822
862
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionFollowFrame',
823
863
  schema: _deepseek_ai_dsh_api_session_controller_session_follow_result$schema,
824
864
  },
825
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":383,"column":3},
865
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":400,"column":3},
826
866
  },
827
867
  {
828
868
  id: '@deepseek-ai/dsh-api-session-controller#session/fork',
@@ -847,7 +887,7 @@ export const TYPERT_REMOTE = {
847
887
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionForkValue',
848
888
  schema: _deepseek_ai_dsh_api_session_controller_session_fork_result$schema,
849
889
  },
850
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":318,"column":3},
890
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":335,"column":3},
851
891
  },
852
892
  {
853
893
  id: '@deepseek-ai/dsh-api-session-controller#session/list',
@@ -873,7 +913,7 @@ export const TYPERT_REMOTE = {
873
913
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionListValue',
874
914
  schema: _deepseek_ai_dsh_api_session_controller_session_list_result$schema,
875
915
  },
876
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":216,"column":9},
916
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":223,"column":9},
877
917
  },
878
918
  {
879
919
  id: '@deepseek-ai/dsh-api-session-controller#session/modelCatalog',
@@ -888,7 +928,7 @@ export const TYPERT_REMOTE = {
888
928
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#ModelCatalog',
889
929
  schema: _deepseek_ai_dsh_api_session_controller_session_modelCatalog_result$schema,
890
930
  },
891
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":256,"column":3},
931
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":263,"column":3},
892
932
  },
893
933
  {
894
934
  id: '@deepseek-ai/dsh-api-session-controller#session/openWorkspacePath',
@@ -914,7 +954,7 @@ export const TYPERT_REMOTE = {
914
954
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionOpenWorkspacePathValue',
915
955
  schema: _deepseek_ai_dsh_api_session_controller_session_openWorkspacePath_result$schema,
916
956
  },
917
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":277,"column":9},
957
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":293,"column":9},
918
958
  },
919
959
  {
920
960
  id: '@deepseek-ai/dsh-api-session-controller#session/page',
@@ -940,7 +980,7 @@ export const TYPERT_REMOTE = {
940
980
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionPage',
941
981
  schema: _deepseek_ai_dsh_api_session_controller_session_page_result$schema,
942
982
  },
943
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":371,"column":3},
983
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":388,"column":3},
944
984
  },
945
985
  {
946
986
  id: '@deepseek-ai/dsh-api-session-controller#session/prompt',
@@ -966,7 +1006,7 @@ export const TYPERT_REMOTE = {
966
1006
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionPromptValue',
967
1007
  schema: _deepseek_ai_dsh_api_session_controller_session_prompt_result$schema,
968
1008
  },
969
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":329,"column":3},
1009
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":346,"column":3},
970
1010
  },
971
1011
  {
972
1012
  id: '@deepseek-ai/dsh-api-session-controller#session/rename',
@@ -991,7 +1031,7 @@ export const TYPERT_REMOTE = {
991
1031
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionRenameValue',
992
1032
  schema: _deepseek_ai_dsh_api_session_controller_session_rename_result$schema,
993
1033
  },
994
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":308,"column":3},
1034
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":325,"column":3},
995
1035
  },
996
1036
  {
997
1037
  id: '@deepseek-ai/dsh-api-session-controller#session/search',
@@ -1017,7 +1057,7 @@ export const TYPERT_REMOTE = {
1017
1057
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionSearchValue',
1018
1058
  schema: _deepseek_ai_dsh_api_session_controller_session_search_result$schema,
1019
1059
  },
1020
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":227,"column":3},
1060
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":234,"column":3},
1021
1061
  },
1022
1062
  {
1023
1063
  id: '@deepseek-ai/dsh-api-session-controller#session/selectModel',
@@ -1042,7 +1082,7 @@ export const TYPERT_REMOTE = {
1042
1082
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionSelectModelValue',
1043
1083
  schema: _deepseek_ai_dsh_api_session_controller_session_selectModel_result$schema,
1044
1084
  },
1045
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":247,"column":3},
1085
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":254,"column":3},
1046
1086
  },
1047
1087
  {
1048
1088
  id: '@deepseek-ai/dsh-api-session-controller#session/updateQueue',
@@ -1067,7 +1107,7 @@ export const TYPERT_REMOTE = {
1067
1107
  typeSymbol: '@deepseek-ai/dsh-api-session-controller/types#SessionUpdateQueueValue',
1068
1108
  schema: _deepseek_ai_dsh_api_session_controller_session_updateQueue_result$schema,
1069
1109
  },
1070
- sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":350,"column":3},
1110
+ sourceLocation: {"file":"packages/api/session-controller/src/index.ts","line":367,"column":3},
1071
1111
  },
1072
1112
  {
1073
1113
  id: '@deepseek-ai/dsh-api-session-controller#skills/list',
@@ -380,13 +380,14 @@ export class ApiSessionAgentController {
380
380
  */
381
381
  async composeAgent(presetId) {
382
382
  const presets = this.ctx.get('agentPresets');
383
- if (presets === undefined)
384
- return { setup: (agentCtx) => { this.installSelection(agentCtx); } };
383
+ if (presets === undefined) {
384
+ return { setup: (_agentCtx, agent) => { this.installSelection(agent); } };
385
+ }
385
386
  const resolvedId = (await presets.resolve(presetId)).id;
386
387
  return {
387
388
  agentPreset: resolvedId,
388
- setup: async (agentCtx) => {
389
- this.installSelection(agentCtx);
389
+ setup: async (agentCtx, agent) => {
390
+ this.installSelection(agent);
390
391
  await presets.mount(agentCtx, resolvedId);
391
392
  },
392
393
  };
@@ -506,10 +507,7 @@ export class ApiSessionAgentController {
506
507
  const { provider, model } = this.ctx.agentDefaultModel.currentSelection();
507
508
  return { provider, model };
508
509
  }
509
- installSelection(agentCtx) {
510
- const agent = agentCtx.agent;
511
- if (agent === undefined)
512
- throw new Error('api-session: Agent setup has no scoped Agent');
510
+ installSelection(agent) {
513
511
  this.selectionFor(agent);
514
512
  }
515
513
  /**
@@ -0,0 +1,11 @@
1
+ /** Event-local acceptance for raw Session journal responses; payloads remain owner-defined JSON. */
2
+ import type { SessionWireEvent } from '../types.ts';
3
+ /**
4
+ * Reject non-current event envelopes without stripping or normalizing wire fields.
5
+ * Range membership and source existence require the durable log and remain Host-owned.
6
+ * @param value - one event received in a follow frame or history page.
7
+ * @returns nothing after narrowing the accepted event envelope.
8
+ * @throws when the envelope or current event-local metadata is invalid.
9
+ */
10
+ export declare function assertSessionWireEvent(value: unknown): asserts value is SessionWireEvent;
11
+ //# sourceMappingURL=session-wire-event.d.ts.map
@@ -0,0 +1,43 @@
1
+ /** Event-local acceptance for raw Session journal responses; payloads remain owner-defined JSON. */
2
+ import { validateSessionEventData, validateSurfaceMetadata } from '@deepseek-ai/dsh-session/surface';
3
+ /**
4
+ * Reject non-current event envelopes without stripping or normalizing wire fields.
5
+ * Range membership and source existence require the durable log and remain Host-owned.
6
+ * @param value - one event received in a follow frame or history page.
7
+ * @returns nothing after narrowing the accepted event envelope.
8
+ * @throws when the envelope or current event-local metadata is invalid.
9
+ */
10
+ export function assertSessionWireEvent(value) {
11
+ const subject = 'session wire event';
12
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
13
+ throw new Error(`${subject} must be an object`);
14
+ }
15
+ const event = value;
16
+ for (const key of Object.keys(event)) {
17
+ switch (key) {
18
+ case 'type':
19
+ case 'seq':
20
+ case 'time':
21
+ case 'data':
22
+ case 'ignorable':
23
+ case 'surfaceOp':
24
+ case 'sourceEventSeqs':
25
+ break;
26
+ default:
27
+ throw new Error(`${subject} has unexpected field ${key}`);
28
+ }
29
+ }
30
+ const seq = event['seq'];
31
+ if (typeof event['type'] !== 'string'
32
+ || typeof seq !== 'number' || !Number.isSafeInteger(seq) || seq < 0 || Object.is(seq, -0)
33
+ || typeof event['time'] !== 'number' || !Number.isSafeInteger(event['time'])
34
+ || !Object.hasOwn(event, 'data') || event['data'] === undefined
35
+ || (Object.hasOwn(event, 'ignorable') && event['ignorable'] !== true)) {
36
+ throw new Error(`${subject} has an invalid envelope`);
37
+ }
38
+ // Event names and payloads are merge-extensible; only event-local owner rules run here.
39
+ const current = event;
40
+ validateSurfaceMetadata(current);
41
+ validateSessionEventData(current, subject);
42
+ }
43
+ //# sourceMappingURL=session-wire-event.js.map
@@ -2,6 +2,7 @@
2
2
  import { RemoteError } from '@deepseek-ai/dsh-typert-protocol';
3
3
  import { RemoteJournalStream, RemoteSnapshotStream, RemoteStreamCarrierError, } from '@deepseek-ai/dsh-api-gateway/client';
4
4
  import { historyEntries, historyRecordFirstSeq, historyRecordLastSeq, } from "./sessions/history-records.js";
5
+ import { assertSessionWireEvent } from "./session-wire-event.js";
5
6
  export { SESSION_SEARCH_RESULT_LIMIT, SESSION_SEARCH_SNIPPET_MAX_CODE_POINTS, } from "../types.js";
6
7
  function toSessionJournalChange(change) {
7
8
  switch (change.type) {
@@ -78,6 +79,8 @@ export class SessionEventStream extends RemoteJournalStream {
78
79
  ...(request.maxMessages === undefined ? {} : { maxMessages: request.maxMessages }),
79
80
  }, signal)) {
80
81
  if (frame.type === 'snapshot') {
82
+ for (const record of frame.records)
83
+ assertSessionWireEvent(record.event);
81
84
  if (frame.assistantStream === undefined) {
82
85
  throw new RemoteError('gateway/internal', 'session assistant stream omitted its opted-in opening baseline', {});
83
86
  }
@@ -103,6 +106,7 @@ export class SessionEventStream extends RemoteJournalStream {
103
106
  yield { type: 'notification', notification: frame.frame };
104
107
  continue;
105
108
  }
109
+ assertSessionWireEvent(frame.event);
106
110
  yield { type: 'entry', entry: frame };
107
111
  }
108
112
  }
@@ -111,6 +115,8 @@ export class SessionEventStream extends RemoteJournalStream {
111
115
  const result = await this.remote.session.page({ address: this.address, throughSeq, ...request }, signal);
112
116
  if (!result.ok)
113
117
  throw result.error;
118
+ for (const record of result.value.records)
119
+ assertSessionWireEvent(record.event);
114
120
  return result.value;
115
121
  }
116
122
  /** @inheritdoc */
@@ -38,7 +38,7 @@ export declare class SessionCommandController {
38
38
  */
39
39
  fork(request: SessionForkRequest): Promise<SessionForkValue>;
40
40
  /**
41
- * Admit one browser prompt after explicit Agent resume and image validation.
41
+ * Reject empty content, then admit one prompt after Agent and attachment validation.
42
42
  * @param request - Session identity, prompt content, source metadata, and delivery mode.
43
43
  * @returns acknowledgement that the Agent accepted the prompt.
44
44
  */
@@ -62,6 +62,9 @@ import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time';
62
62
  import { assertNever } from '@deepseek-ai/dsh-util-values';
63
63
  import { RemoteError, remoteErrorOf } from '@deepseek-ai/dsh-typert-protocol';
64
64
  import { ApiSessionCwdConflict, ApiSessionNotFound, ApiSessionPresetConflict, ApiSessionSubagentOwnership, apiSessionSubagentOwnershipError, hasApiSessionSubagentOwner, inspectApiSession, } from "./agent.js";
65
+ function hasPromptContent(content) {
66
+ return content.some(part => part.type !== 'text' || part.text.trim().length > 0);
67
+ }
65
68
  /** Implements Session business commands delegated by the Session Controller Remote service. */
66
69
  export class SessionCommandController {
67
70
  ctx;
@@ -271,11 +274,14 @@ export class SessionCommandController {
271
274
  }
272
275
  }
273
276
  /**
274
- * Admit one browser prompt after explicit Agent resume and image validation.
277
+ * Reject empty content, then admit one prompt after Agent and attachment validation.
275
278
  * @param request - Session identity, prompt content, source metadata, and delivery mode.
276
279
  * @returns acknowledgement that the Agent accepted the prompt.
277
280
  */
278
281
  async prompt(request) {
282
+ if (!hasPromptContent(request.content)) {
283
+ throw new RemoteError('gateway/bad-request', 'prompt content must include non-whitespace text or an attachment', {});
284
+ }
279
285
  const clientTimeZone = request.clientTimeZone === undefined
280
286
  ? undefined
281
287
  : canonicalClientTimeZone(request.clientTimeZone);
@@ -379,9 +385,13 @@ export class SessionCommandController {
379
385
  * @returns acknowledgement that the queue mutation was applied.
380
386
  */
381
387
  updateQueue(request) {
382
- if (request.action.kind === 'edit'
383
- && request.action.content.some(block => block.type !== 'text')) {
384
- throw new RemoteError('session/attachment-invalid', 'queue edits accept text content only', { reason: 'QUEUE_EDIT_NON_TEXT' });
388
+ if (request.action.kind === 'edit') {
389
+ if (request.action.content.some(block => block.type !== 'text')) {
390
+ throw new RemoteError('session/attachment-invalid', 'queue edits accept text content only', { reason: 'QUEUE_EDIT_NON_TEXT' });
391
+ }
392
+ if (!hasPromptContent(request.action.content)) {
393
+ throw new RemoteError('gateway/bad-request', 'queue edit content must include non-whitespace text', {});
394
+ }
385
395
  }
386
396
  const agent = this.ctx.agents.get(request.sessionId);
387
397
  if (agent === undefined) {
@@ -15,7 +15,6 @@ export declare class SessionControlController {
15
15
  control(signal: AbortSignal): AsyncIterable<SessionControlFrame>;
16
16
  private baseline;
17
17
  private projectionBaseline;
18
- private onSessionEvent;
19
18
  private onJobsChanged;
20
19
  private jobsFor;
21
20
  private broadcast;
@@ -7,7 +7,6 @@ export class SessionControlController {
7
7
  /** @param ctx - Host context carrying live Agent, projection, and jobs services. */
8
8
  constructor(ctx) {
9
9
  this.ctx = ctx;
10
- ctx.on('session/event', (session, event) => { this.onSessionEvent(session, event); });
11
10
  ctx.sessionProjections.onChanged((session, key, value, seq) => {
12
11
  this.broadcast({
13
12
  type: 'projection',
@@ -16,6 +15,16 @@ export class SessionControlController {
16
15
  value: value,
17
16
  seq,
18
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
+ });
19
28
  });
20
29
  ctx.inject(['jobs'], (jobsCtx) => {
21
30
  jobsCtx.jobs.onJobsChanged((owner) => { this.onJobsChanged(owner); });
@@ -76,18 +85,6 @@ export class SessionControlController {
76
85
  }
77
86
  return blocks;
78
87
  }
79
- onSessionEvent(session, event) {
80
- if (event.type !== 'agent/inbox/spliced')
81
- return;
82
- const agent = this.ctx.agents.get(session.id);
83
- if (agent?.session !== session)
84
- return;
85
- this.broadcast({
86
- type: 'queue',
87
- sessionId: session.id,
88
- items: queueItems(agent, event.data),
89
- });
90
- }
91
88
  onJobsChanged(owner) {
92
89
  if (owner !== undefined) {
93
90
  this.broadcast({ type: 'jobs', sessionId: owner.id, jobs: this.jobsFor(owner) });
@@ -151,21 +148,21 @@ class ControlQueue {
151
148
  }
152
149
  }
153
150
  }
154
- function queueItems(agent, splice) {
155
- const project = (target) => {
156
- const messages = target === 'next-turn' ? agent.inbox.nextTurn : agent.inbox.nextStep;
157
- return splice?.target === target
158
- ? messages.toSpliced(splice.start, splice.removedCount ?? 0, ...splice.inserted)
159
- : messages;
160
- };
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) {
161
158
  return [
162
- ...project('next-turn').map(message => ({
159
+ ...inbox['next-turn'].map(message => ({
163
160
  id: message.id,
164
161
  placement: 'queued',
165
162
  ...promptRpcId(message),
166
163
  message: { id: message.id, content: message.content },
167
164
  })),
168
- ...project('next-step').map(message => ({
165
+ ...inbox['next-step'].map(message => ({
169
166
  id: message.id,
170
167
  placement: message.source.kind === 'user' ? 'steering' : 'context',
171
168
  ...promptRpcId(message),
@@ -26,6 +26,8 @@ export interface Config {
26
26
  export interface SessionControllerInternals {
27
27
  /** Native default-application handoff. */
28
28
  readonly openPath?: (path: string, signal: AbortSignal) => Promise<void>;
29
+ /** Native file-manager handoff. */
30
+ readonly revealPath?: (path: string, signal: AbortSignal) => Promise<void>;
29
31
  /** Native handoff availability probe. */
30
32
  readonly canOpenPath?: () => boolean;
31
33
  }
@@ -39,6 +41,7 @@ export declare class SessionController extends TypertRemoteService {
39
41
  private readonly history;
40
42
  private readonly listState;
41
43
  private readonly openPath;
44
+ private readonly revealPath;
42
45
  private readonly canOpenPath;
43
46
  private readonly promotions;
44
47
  /**
@@ -97,6 +100,15 @@ export declare class SessionController extends TypertRemoteService {
97
100
  * @returns true when the matching open operation is available.
98
101
  */
99
102
  canOpenWorkspacePath(): boolean;
103
+ /**
104
+ * Describe the serving desktop for authenticated file-action routes.
105
+ * @returns Host name, configured availability, and platform-specific file-manager behavior.
106
+ */
107
+ workspaceDesktop(): {
108
+ name: string;
109
+ available: boolean;
110
+ fileManager: 'finder' | 'explorer' | 'directory' | null;
111
+ };
100
112
  /**
101
113
  * Open one path prepared by a Session-aware caller on the Host desktop.
102
114
  * @param request - path after best-effort Session workspace resolution.
@@ -85,9 +85,10 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
85
85
  var e = new Error(message);
86
86
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
87
87
  });
88
+ import { hostname } from 'node:os';
88
89
  import z from '@deepseek-ai/schemastery';
89
90
  import { errorChain } from '@deepseek-ai/dsh-llm';
90
- import { canOpenNativePath, openNativePath } from '@deepseek-ai/dsh-native-command';
91
+ import { canOpenNativePath, nativeFileManager, openNativePath, revealNativePath } from '@deepseek-ai/dsh-native-command';
91
92
  import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
92
93
  import { ApiSessionAgentController, inspectApiSession, } from "./agent.js";
93
94
  import { SessionCommandController } from "./commands.js";
@@ -98,6 +99,7 @@ import { ApiSessionList } from "./list.js";
98
99
  import { buildModelCatalog } from "./catalog.js";
99
100
  import { installModelSelectionProjection } from "./model-selection-projection.js";
100
101
  import { SessionSkillCatalog } from "./skill-catalog.js";
102
+ import { SessionMediaReferences } from "./media-references.js";
101
103
  export { ApiSessionNotFound } from "./agent.js";
102
104
  export { SessionFileReferences } from "./file-references.js";
103
105
  export { SessionSkillCatalog } from "./skill-catalog.js";
@@ -179,6 +181,7 @@ let SessionController = (() => {
179
181
  history;
180
182
  listState;
181
183
  openPath;
184
+ revealPath;
182
185
  canOpenPath;
183
186
  promotions = new Set();
184
187
  /**
@@ -206,9 +209,11 @@ let SessionController = (() => {
206
209
  this.history = new SessionHistoryController(ctx, (observation) => { this.promote(observation); });
207
210
  this.listState = new ApiSessionList(ctx);
208
211
  this.openPath = internals.openPath ?? openNativePath;
212
+ this.revealPath = internals.revealPath ?? revealNativePath;
209
213
  this.canOpenPath = internals.canOpenPath
210
214
  ?? (() => config.nativeOpen ?? (internals.openPath !== undefined || canOpenNativePath()));
211
215
  ctx.plugin(SessionFileReferences);
216
+ ctx.plugin(SessionMediaReferences);
212
217
  ctx.plugin(SessionSkillCatalog);
213
218
  ctx.on('session/created', (session) => {
214
219
  ctx.emit('api-session/added', this.listState.summaryFor(session));
@@ -329,6 +334,14 @@ let SessionController = (() => {
329
334
  canOpenWorkspacePath() {
330
335
  return this.canOpenPath();
331
336
  }
337
+ /**
338
+ * Describe the serving desktop for authenticated file-action routes.
339
+ * @returns Host name, configured availability, and platform-specific file-manager behavior.
340
+ */
341
+ workspaceDesktop() {
342
+ const fileManager = nativeFileManager();
343
+ return { name: hostname(), available: fileManager !== null && this.canOpenPath(), fileManager };
344
+ }
332
345
  /**
333
346
  * Open one path prepared by a Session-aware caller on the Host desktop.
334
347
  * @param request - path after best-effort Session workspace resolution.
@@ -342,7 +355,10 @@ let SessionController = (() => {
342
355
  }
343
356
  signal.throwIfAborted();
344
357
  try {
345
- await this.openPath(request.path, signal);
358
+ if (request.action === 'reveal')
359
+ await this.revealPath(request.path, signal);
360
+ else
361
+ await this.openPath(request.path, signal);
346
362
  return { opened: true };
347
363
  }
348
364
  catch (error) {