@deepseek-ai/dsh-api-session-controller 0.2.1-alpha.1 → 0.2.1-alpha.3
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.
- package/README.i18n.yaml +2 -2
- package/README.md +6 -2
- package/README.zh.md +6 -2
- package/lib/client.js +55 -26
- package/lib/index.js +265 -110
- package/lib/typert.host.js +1328 -590
- package/lib/typert.remote-client.d.ts +25 -2
- package/lib/typert.remote-client.js +1102 -561
- package/lib/types/agent.d.ts +61 -17
- package/lib/types/agent.js +148 -84
- package/lib/types/client/contract/sessions.d.ts +10 -5
- package/lib/types/client/sessions/lineage.d.ts +2 -0
- package/lib/types/client/sessions/manager.d.ts +10 -7
- package/lib/types/client/sessions/manager.js +42 -14
- package/lib/types/client/sessions/projection-store.d.ts +3 -3
- package/lib/types/client/sessions/projection-store.js +1 -1
- package/lib/types/client/sessions/service.d.ts +11 -6
- package/lib/types/client/sessions/service.js +9 -5
- package/lib/types/client/sessions/session.js +1 -1
- package/lib/types/commands.d.ts +20 -6
- package/lib/types/commands.js +28 -34
- package/lib/types/index.d.ts +11 -8
- package/lib/types/index.js +105 -25
- package/lib/types/list.js +6 -4
- package/lib/types/skill-catalog.js +7 -6
- package/lib/types/types.d.ts +28 -5
- package/locale/en.json +5 -0
- package/locale/zh.json +6 -0
- package/package.json +83 -77
|
@@ -78,8 +78,9 @@ export class SessionManager {
|
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
80
|
* Resolve an address for breadcrumb navigation without retaining transport authority.
|
|
81
|
-
* @param sessionId - possible child id in
|
|
82
|
-
* @returns A retained
|
|
81
|
+
* @param sessionId - possible child id in received Session metadata.
|
|
82
|
+
* @returns A retained address, then a catalog address, then an unknown-mode address
|
|
83
|
+
* from a listed subagent header; undefined without that evidence.
|
|
83
84
|
*/
|
|
84
85
|
subagentAddress(sessionId) {
|
|
85
86
|
const retained = this.addresses.get(sessionId);
|
|
@@ -88,7 +89,7 @@ export class SessionManager {
|
|
|
88
89
|
for (const parentSessionId of this.projectionStores.keys()) {
|
|
89
90
|
const child = this.projectionStores.get(parentSessionId)?.values().subagentCatalog
|
|
90
91
|
?.find(entry => entry.id === sessionId);
|
|
91
|
-
if (child !== undefined) {
|
|
92
|
+
if (child !== undefined && child.mode !== 'external') {
|
|
92
93
|
return {
|
|
93
94
|
parentSessionId,
|
|
94
95
|
childSessionId: sessionId,
|
|
@@ -96,7 +97,14 @@ export class SessionManager {
|
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
+
const summary = this.summaries.find(summary => summary.sessionId === sessionId);
|
|
101
|
+
if (summary?.origin !== 'subagent' || summary.parentSessionId === undefined)
|
|
102
|
+
return undefined;
|
|
103
|
+
return {
|
|
104
|
+
parentSessionId: summary.parentSessionId,
|
|
105
|
+
childSessionId: sessionId,
|
|
106
|
+
mode: 'unknown',
|
|
107
|
+
};
|
|
100
108
|
}
|
|
101
109
|
// ---- Instance management ----
|
|
102
110
|
/**
|
|
@@ -169,7 +177,7 @@ export class SessionManager {
|
|
|
169
177
|
const address = this.addresses.get(sessionId);
|
|
170
178
|
const child = address === undefined ? undefined : this.projectionStores.get(address.parentSessionId)?.values().subagentCatalog
|
|
171
179
|
?.find(entry => entry.id === sessionId);
|
|
172
|
-
if (child !== undefined) {
|
|
180
|
+
if (child !== undefined && child.mode !== 'external') {
|
|
173
181
|
// A catalogued child exists only after its delegated session has
|
|
174
182
|
// durable history, even though child rows do not carry `blank`.
|
|
175
183
|
session.handleBlank(false);
|
|
@@ -252,7 +260,7 @@ export class SessionManager {
|
|
|
252
260
|
return store;
|
|
253
261
|
}
|
|
254
262
|
/**
|
|
255
|
-
*
|
|
263
|
+
* Read projections without starting migration; retry failed or migration-deferred reads.
|
|
256
264
|
* @param sessionId - Session to inspect without opening its conversation.
|
|
257
265
|
* @returns completion of the current or newly started read.
|
|
258
266
|
*/
|
|
@@ -273,14 +281,27 @@ export class SessionManager {
|
|
|
273
281
|
if (controller.signal.aborted)
|
|
274
282
|
return;
|
|
275
283
|
if (result.ok) {
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
const value = result.value;
|
|
285
|
+
if (value !== null) {
|
|
286
|
+
switch (value.kind) {
|
|
287
|
+
case 'sequenced':
|
|
288
|
+
store.seed({ values: value.values, asOfSeq: sessionSeqCursor(value.asOfSeq) });
|
|
289
|
+
break;
|
|
290
|
+
case 'migration-required':
|
|
291
|
+
store.applyCached(value.values);
|
|
292
|
+
break;
|
|
293
|
+
default:
|
|
294
|
+
assertNever(value, 'session projections result');
|
|
295
|
+
}
|
|
278
296
|
}
|
|
279
297
|
else if (store.values() === initialValues) {
|
|
280
298
|
// A later frame proves existence independently of an earlier missing read.
|
|
281
299
|
store.clear();
|
|
282
300
|
}
|
|
283
|
-
this.projectionLoads.set(sessionId, {
|
|
301
|
+
this.projectionLoads.set(sessionId, {
|
|
302
|
+
state: value?.kind === 'migration-required' ? 'migration-required' : 'ready',
|
|
303
|
+
error: null,
|
|
304
|
+
});
|
|
284
305
|
}
|
|
285
306
|
else {
|
|
286
307
|
this.projectionLoads.set(sessionId, { state: 'error', error: result.error });
|
|
@@ -416,11 +437,14 @@ export class SessionManager {
|
|
|
416
437
|
* Contract session.create; on success merge into summaries immediately (no
|
|
417
438
|
* wait for the next refresh). A created session is blank by definition
|
|
418
439
|
* (entity birth precedes the first message).
|
|
419
|
-
* @param opts - target workspace or working directory,
|
|
420
|
-
* @returns the create result.
|
|
440
|
+
* @param opts - target workspace or working directory, an optional blank Session to reuse, and an optional Agent preset.
|
|
441
|
+
* @returns the create result, naming the Session the Host created or reused.
|
|
421
442
|
*/
|
|
422
443
|
async create(opts = {}) {
|
|
423
|
-
const shared =
|
|
444
|
+
const shared = {
|
|
445
|
+
...(opts.sessionId === undefined ? {} : { sessionId: opts.sessionId }),
|
|
446
|
+
...(opts.agentPreset === undefined ? {} : { agentPreset: opts.agentPreset }),
|
|
447
|
+
};
|
|
424
448
|
const payload = opts.workspaceId !== undefined
|
|
425
449
|
? { workspaceId: opts.workspaceId, ...shared }
|
|
426
450
|
: { ...(opts.cwd === undefined ? {} : { cwd: opts.cwd }), ...shared };
|
|
@@ -454,7 +478,7 @@ export class SessionManager {
|
|
|
454
478
|
* preserve it or lower it after an exact cut before the first `turn/start`;
|
|
455
479
|
* lineage rides parentSessionId. A child published before Workspace
|
|
456
480
|
* attachment fails is also reconciled into the list.
|
|
457
|
-
* @param opts - source session
|
|
481
|
+
* @param opts - source session, optional exact inclusive boundary seq, and permission to start migration.
|
|
458
482
|
* @returns the fork result (the child session id).
|
|
459
483
|
*/
|
|
460
484
|
async fork(opts) {
|
|
@@ -462,6 +486,7 @@ export class SessionManager {
|
|
|
462
486
|
const result = await this.remote.session.fork({
|
|
463
487
|
sessionId: opts.sessionId,
|
|
464
488
|
...opts.atSeq === undefined ? {} : { atSeq: opts.atSeq },
|
|
489
|
+
...opts.allowMigration === undefined ? {} : { allowMigration: opts.allowMigration },
|
|
465
490
|
});
|
|
466
491
|
const childId = result.ok
|
|
467
492
|
? result.value.sessionId
|
|
@@ -691,6 +716,7 @@ export class SessionManager {
|
|
|
691
716
|
&& prev.blank === entry.blank
|
|
692
717
|
&& prev.parentSessionId === entry.parentSessionId && prev.cwd === entry.cwd
|
|
693
718
|
&& prev.origin === entry.origin && prev.title === entry.title && prev.depth === entry.depth
|
|
719
|
+
&& prev.formatStatus === entry.formatStatus
|
|
694
720
|
&& prev.projectionValues === entry.projectionValues)
|
|
695
721
|
return prev;
|
|
696
722
|
this.entryCache.set(entry.sessionId, entry);
|
|
@@ -732,6 +758,7 @@ function applyMutation(summaries, mutation) {
|
|
|
732
758
|
...(mutation.kind === 'upsert' ? {
|
|
733
759
|
agentAvailable: mutation.summary.agentAvailable,
|
|
734
760
|
running: mutation.summary.running,
|
|
761
|
+
...(mutation.summary.formatStatus === undefined ? {} : { formatStatus: mutation.summary.formatStatus }),
|
|
735
762
|
} : {}),
|
|
736
763
|
...(existing.cwd === undefined && mutation.summary.cwd !== undefined ? { cwd: mutation.summary.cwd } : {}),
|
|
737
764
|
...(existing.parentSessionId === undefined && mutation.summary.parentSessionId !== undefined
|
|
@@ -741,7 +768,8 @@ function applyMutation(summaries, mutation) {
|
|
|
741
768
|
};
|
|
742
769
|
if (filled.cwd === existing.cwd && filled.parentSessionId === existing.parentSessionId
|
|
743
770
|
&& filled.origin === existing.origin && filled.blank === existing.blank
|
|
744
|
-
&& filled.agentAvailable === existing.agentAvailable && filled.running === existing.running
|
|
771
|
+
&& filled.agentAvailable === existing.agentAvailable && filled.running === existing.running
|
|
772
|
+
&& filled.formatStatus === existing.formatStatus)
|
|
745
773
|
return [...summaries];
|
|
746
774
|
return summaries.map(summary => summary.sessionId === mutation.summary.sessionId ? filled : summary);
|
|
747
775
|
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* (`{ value, seq }`) comes from the connected Host — a follow opening
|
|
7
7
|
* baseline, a Session Controller `projection` frame, a list block the Host
|
|
8
8
|
* computed for an attached Session — and merges under **higher seq wins**
|
|
9
|
-
* against other sequenced rows. A `cached` row (`{ value }`) comes from
|
|
10
|
-
*
|
|
9
|
+
* against other sequenced rows. A `cached` row (`{ value }`) comes from
|
|
10
|
+
* a Host view of the persisted checkpoint, carries no comparable
|
|
11
11
|
* seq, and yields to every sequenced write. No client-side domain folding
|
|
12
12
|
* exists: a domain ships projection support with zero client code. Per-key
|
|
13
13
|
* bare observable faces feed `useProjection` (ui-renderer binds them).
|
|
@@ -101,7 +101,7 @@ export declare class ProjectionValueStore {
|
|
|
101
101
|
*/
|
|
102
102
|
apply(key: string, value: unknown, seq: SessionSeqCursor): void;
|
|
103
103
|
/**
|
|
104
|
-
* Fill keys from a
|
|
104
|
+
* Fill keys from a Host block labeled `cached`: a zero-I/O
|
|
105
105
|
* view of the persisted checkpoint. A cached value lands only where no
|
|
106
106
|
* sequenced row exists: a connected Session has already answered for such
|
|
107
107
|
* a key, and the list's view of the persisted checkpoint cannot be newer
|
|
@@ -82,7 +82,7 @@ export class ProjectionValueStore {
|
|
|
82
82
|
this.changed(key);
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
-
* Fill keys from a
|
|
85
|
+
* Fill keys from a Host block labeled `cached`: a zero-I/O
|
|
86
86
|
* view of the persisted checkpoint. A cached value lands only where no
|
|
87
87
|
* sequenced row exists: a connected Session has already answered for such
|
|
88
88
|
* a key, and the list's view of the persisted checkpoint cannot be newer
|
|
@@ -12,6 +12,7 @@ import type { AgentContext, ISessions, SessionReference, SessionRetainInfo, Sess
|
|
|
12
12
|
import { SessionManager } from './manager.ts';
|
|
13
13
|
import type { SessionRemotes } from './remotes.ts';
|
|
14
14
|
import type { SessionListPhase, SessionSearchResultItem, SessionProjectionSnapshot } from './manager.ts';
|
|
15
|
+
import type { SessionListEntry } from './lineage.ts';
|
|
15
16
|
/** Session list row projected from the host list RPC plus live stream increments. */
|
|
16
17
|
export interface SessionSummary {
|
|
17
18
|
id: SessionId;
|
|
@@ -23,6 +24,8 @@ export interface SessionSummary {
|
|
|
23
24
|
parentId?: SessionId;
|
|
24
25
|
/** Coarse durable origin for navigation filtering; not a continuation capability. */
|
|
25
26
|
origin?: 'subagent';
|
|
27
|
+
/** Format classification supplied by the Host list, when available. */
|
|
28
|
+
formatStatus?: SessionListEntry['formatStatus'];
|
|
26
29
|
/** Host running state for `ids` members; a display fallback for other rows. */
|
|
27
30
|
running: boolean;
|
|
28
31
|
/** Local ownership counts; Host metadata refreshes cannot overwrite them. */
|
|
@@ -30,7 +33,7 @@ export interface SessionSummary {
|
|
|
30
33
|
/**
|
|
31
34
|
* New Session presentation and reuse eligibility, derived from the Host
|
|
32
35
|
* summary, `sessionListMetadata`, and client acceptance/running observations.
|
|
33
|
-
*
|
|
36
|
+
* Workspace reconnection may reuse a blank in the same workspace. Filtering
|
|
34
37
|
* stays with the consumer: the store carries every row, while the Workspace
|
|
35
38
|
* browser shows only the selected blank entry.
|
|
36
39
|
*/
|
|
@@ -113,11 +116,11 @@ export declare class ClientSessions implements ISessions {
|
|
|
113
116
|
* Resolve an already discovered direct-parent address without opening it.
|
|
114
117
|
* Feature plugins use this to avoid Agent-bound RPCs in persisted child views.
|
|
115
118
|
* @param id - possible addressed child id.
|
|
116
|
-
* @returns A retained or
|
|
119
|
+
* @returns A retained, catalog-derived, or unknown-mode listed address, without retaining a new selection or scope.
|
|
117
120
|
*/
|
|
118
121
|
subagentAddress(id: SessionId): SubagentAddress | undefined;
|
|
119
122
|
/**
|
|
120
|
-
*
|
|
123
|
+
* Read projections without starting migration; retry failed or migration-deferred reads.
|
|
121
124
|
* @param sessionId - Session to inspect without opening its conversation.
|
|
122
125
|
*/
|
|
123
126
|
refreshProjections(sessionId: SessionId): Promise<void>;
|
|
@@ -172,14 +175,15 @@ export declare class ClientSessions implements ISessions {
|
|
|
172
175
|
/**
|
|
173
176
|
* Create a Host Session and publish its catalog row before resolving.
|
|
174
177
|
* Callers retain the returned identity before borrowing its binding.
|
|
175
|
-
* @param opts - target workspace or directory and an optional
|
|
176
|
-
* @returns the
|
|
178
|
+
* @param opts - target workspace or directory, an optional blank Session to reuse, and an optional Agent preset.
|
|
179
|
+
* @returns the created or reused session id.
|
|
177
180
|
* @throws {SessionCreateError} with the requested id.
|
|
178
181
|
*/
|
|
179
182
|
create(opts?: {
|
|
180
183
|
workspaceId?: WorkspaceId;
|
|
181
184
|
cwd?: string;
|
|
182
185
|
sessionId?: SessionId;
|
|
186
|
+
agentPreset?: string;
|
|
183
187
|
}): Promise<SessionId>;
|
|
184
188
|
/**
|
|
185
189
|
* Fork a session from an exact inclusive prefix of the source (same
|
|
@@ -189,7 +193,7 @@ export declare class ClientSessions implements ISessions {
|
|
|
189
193
|
* seq (a real event seq the caller already knows; a cut inside an open
|
|
190
194
|
* turn is balanced Host-side with synthetic closers, and omission selects
|
|
191
195
|
* the latest completed-turn prefix), and whether to increment an
|
|
192
|
-
* inherited durable title before resolving.
|
|
196
|
+
* inherited durable title before resolving, plus permission to start source migration.
|
|
193
197
|
* @returns the child session id.
|
|
194
198
|
* @throws {SessionForkError} with the source id.
|
|
195
199
|
* @throws {Error} when a requested child-title rename fails after creation.
|
|
@@ -199,6 +203,7 @@ export declare class ClientSessions implements ISessions {
|
|
|
199
203
|
atSeq?: number;
|
|
200
204
|
increaseTitle?: boolean;
|
|
201
205
|
onCreated?: (childId: SessionId) => void;
|
|
206
|
+
allowMigration?: boolean;
|
|
202
207
|
}): Promise<SessionId>;
|
|
203
208
|
/**
|
|
204
209
|
* Borrow an already-retained Agent-scoped Context.
|
|
@@ -234,13 +234,13 @@ export class ClientSessions {
|
|
|
234
234
|
* Resolve an already discovered direct-parent address without opening it.
|
|
235
235
|
* Feature plugins use this to avoid Agent-bound RPCs in persisted child views.
|
|
236
236
|
* @param id - possible addressed child id.
|
|
237
|
-
* @returns A retained or
|
|
237
|
+
* @returns A retained, catalog-derived, or unknown-mode listed address, without retaining a new selection or scope.
|
|
238
238
|
*/
|
|
239
239
|
subagentAddress(id) {
|
|
240
240
|
return this.manager.subagentAddress(id);
|
|
241
241
|
}
|
|
242
242
|
/**
|
|
243
|
-
*
|
|
243
|
+
* Read projections without starting migration; retry failed or migration-deferred reads.
|
|
244
244
|
* @param sessionId - Session to inspect without opening its conversation.
|
|
245
245
|
*/
|
|
246
246
|
refreshProjections(sessionId) {
|
|
@@ -312,8 +312,8 @@ export class ClientSessions {
|
|
|
312
312
|
/**
|
|
313
313
|
* Create a Host Session and publish its catalog row before resolving.
|
|
314
314
|
* Callers retain the returned identity before borrowing its binding.
|
|
315
|
-
* @param opts - target workspace or directory and an optional
|
|
316
|
-
* @returns the
|
|
315
|
+
* @param opts - target workspace or directory, an optional blank Session to reuse, and an optional Agent preset.
|
|
316
|
+
* @returns the created or reused session id.
|
|
317
317
|
* @throws {SessionCreateError} with the requested id.
|
|
318
318
|
*/
|
|
319
319
|
async create(opts = {}) {
|
|
@@ -331,7 +331,7 @@ export class ClientSessions {
|
|
|
331
331
|
* seq (a real event seq the caller already knows; a cut inside an open
|
|
332
332
|
* turn is balanced Host-side with synthetic closers, and omission selects
|
|
333
333
|
* the latest completed-turn prefix), and whether to increment an
|
|
334
|
-
* inherited durable title before resolving.
|
|
334
|
+
* inherited durable title before resolving, plus permission to start source migration.
|
|
335
335
|
* @returns the child session id.
|
|
336
336
|
* @throws {SessionForkError} with the source id.
|
|
337
337
|
* @throws {Error} when a requested child-title rename fails after creation.
|
|
@@ -343,6 +343,7 @@ export class ClientSessions {
|
|
|
343
343
|
const result = await this.manager.fork({
|
|
344
344
|
sessionId: opts.sessionId,
|
|
345
345
|
...(opts.atSeq === undefined ? {} : { atSeq: SessionSeq(opts.atSeq) }),
|
|
346
|
+
...(opts.allowMigration === undefined ? {} : { allowMigration: opts.allowMigration }),
|
|
346
347
|
});
|
|
347
348
|
if (!result.ok)
|
|
348
349
|
throw new SessionForkError(result.error, opts.sessionId);
|
|
@@ -502,6 +503,7 @@ export class ClientSessions {
|
|
|
502
503
|
retainedBy: this.retentionSnapshot(entry.sessionId).retainedBy,
|
|
503
504
|
blank: entry.blank,
|
|
504
505
|
updatedAt: entry.updatedAt,
|
|
506
|
+
formatStatus: entry.formatStatus,
|
|
505
507
|
...(entry.projectionValues === undefined
|
|
506
508
|
? {}
|
|
507
509
|
: { projectionValues: entry.projectionValues }),
|
|
@@ -513,6 +515,8 @@ export class ClientSessions {
|
|
|
513
515
|
}
|
|
514
516
|
for (const [parentId, projection] of Object.entries(projectionsBySession)) {
|
|
515
517
|
for (const child of projection.values.subagentCatalog ?? []) {
|
|
518
|
+
if (child.mode === 'external')
|
|
519
|
+
continue;
|
|
516
520
|
const childId = child.id;
|
|
517
521
|
const summary = byId[childId];
|
|
518
522
|
const projectionValues = summary?.projectionValues ?? this.manager.projectionValues(childId);
|
|
@@ -202,7 +202,7 @@ export class Session {
|
|
|
202
202
|
// wire type is used; this array is not filtered or reordered.
|
|
203
203
|
const routedContent = content;
|
|
204
204
|
const routed = await this.remote.subagents.prompt({
|
|
205
|
-
requestId: randomUUID(),
|
|
205
|
+
requestId: requestId ?? randomUUID(),
|
|
206
206
|
parentSessionId: this.address.parentSessionId,
|
|
207
207
|
childSessionId: this.address.childSessionId,
|
|
208
208
|
mode: 'continuable',
|
package/lib/types/commands.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
/** Session commands whose activation policy is explicit at each Remote method. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { MessageSource } from '@deepseek-ai/dsh-llm';
|
|
3
4
|
import { ApiSessionAgentController } from './agent.ts';
|
|
4
5
|
import type { SessionAttachmentRequest, SessionAttachmentValue, SessionCancelRequest, SessionCancelValue, SessionCreateRequest, SessionCreateValue, SessionForkRequest, SessionForkValue, SessionPromptRequest, SessionPromptValue, SessionRenameRequest, SessionRenameValue, SessionSelectModelRequest, SessionSelectModelValue, SessionUpdateQueueRequest, SessionUpdateQueueValue } from './types.ts';
|
|
6
|
+
type PromptContentCandidate = SessionPromptRequest['content'][number] | Extract<SessionUpdateQueueRequest['action'], {
|
|
7
|
+
readonly kind: 'edit';
|
|
8
|
+
}>['content'][number];
|
|
9
|
+
/**
|
|
10
|
+
* Whether prompt content carries non-whitespace text or an attachment.
|
|
11
|
+
* @param content - submitted or edited prompt parts.
|
|
12
|
+
* @returns false for content the Agent must not receive.
|
|
13
|
+
*/
|
|
14
|
+
export declare function hasPromptContent(content: readonly PromptContentCandidate[]): boolean;
|
|
5
15
|
/** Implements Session business commands delegated by the Session Controller Remote service. */
|
|
6
16
|
export declare class SessionCommandController {
|
|
7
17
|
private readonly ctx;
|
|
@@ -14,9 +24,10 @@ export declare class SessionCommandController {
|
|
|
14
24
|
*/
|
|
15
25
|
constructor(ctx: Context, agents: ApiSessionAgentController, defaultCwd: string);
|
|
16
26
|
/**
|
|
17
|
-
* Create
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
27
|
+
* Create one ordinary Session for a new conversation, reusing the named
|
|
28
|
+
* blank Session while it is an unarchived member of the requested Workspace.
|
|
29
|
+
* @param request - optional blank Session to reuse, location, and Agent preset.
|
|
30
|
+
* @returns the created or reused Session identity and its preset when configured.
|
|
20
31
|
*/
|
|
21
32
|
create(request: SessionCreateRequest): Promise<SessionCreateValue>;
|
|
22
33
|
/**
|
|
@@ -40,11 +51,13 @@ export declare class SessionCommandController {
|
|
|
40
51
|
*/
|
|
41
52
|
fork(request: SessionForkRequest): Promise<SessionForkValue>;
|
|
42
53
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
54
|
+
* Admit one prompt after Agent and attachment validation; the Remote method
|
|
55
|
+
* has already validated the content and built the durable message source.
|
|
56
|
+
* @param request - Session identity, prompt content, and delivery mode.
|
|
57
|
+
* @param source - the `user-rpc` source recorded on the accepted message.
|
|
45
58
|
* @returns acknowledgement that the Agent accepted the prompt.
|
|
46
59
|
*/
|
|
47
|
-
prompt(request: SessionPromptRequest): Promise<SessionPromptValue>;
|
|
60
|
+
prompt(request: SessionPromptRequest, source: MessageSource): Promise<SessionPromptValue>;
|
|
48
61
|
private requireModel;
|
|
49
62
|
/**
|
|
50
63
|
* Read one durable image after proving the Session log references it.
|
|
@@ -69,4 +82,5 @@ export declare class SessionCommandController {
|
|
|
69
82
|
private readSessionState;
|
|
70
83
|
private forkWorkspace;
|
|
71
84
|
}
|
|
85
|
+
export {};
|
|
72
86
|
//# sourceMappingURL=commands.d.ts.map
|
package/lib/types/commands.js
CHANGED
|
@@ -60,11 +60,15 @@ import { buildForkSeed } from '@deepseek-ai/dsh-session/fork';
|
|
|
60
60
|
import { SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session';
|
|
61
61
|
import { SessionQueryError } from '@deepseek-ai/dsh-session-query';
|
|
62
62
|
import { SessionTitleInvalidError } from '@deepseek-ai/dsh-session-title';
|
|
63
|
-
import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time';
|
|
64
63
|
import { assertNever } from '@deepseek-ai/dsh-util-values';
|
|
65
64
|
import { RemoteError, remoteErrorOf } from '@deepseek-ai/dsh-typert-protocol';
|
|
66
65
|
import { ApiSessionCwdConflict, ApiSessionNotFound, ApiSessionPresetConflict, ApiSessionSubagentOwnership, apiSessionSubagentOwnershipError, hasApiSessionSubagentOwner, inspectApiSession, } from "./agent.js";
|
|
67
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Whether prompt content carries non-whitespace text or an attachment.
|
|
68
|
+
* @param content - submitted or edited prompt parts.
|
|
69
|
+
* @returns false for content the Agent must not receive.
|
|
70
|
+
*/
|
|
71
|
+
export function hasPromptContent(content) {
|
|
68
72
|
return content.some(part => part.type !== 'text' || part.text.trim().length > 0);
|
|
69
73
|
}
|
|
70
74
|
/**
|
|
@@ -100,15 +104,15 @@ export class SessionCommandController {
|
|
|
100
104
|
this.defaultCwd = defaultCwd;
|
|
101
105
|
}
|
|
102
106
|
/**
|
|
103
|
-
* Create
|
|
104
|
-
*
|
|
105
|
-
* @
|
|
107
|
+
* Create one ordinary Session for a new conversation, reusing the named
|
|
108
|
+
* blank Session while it is an unarchived member of the requested Workspace.
|
|
109
|
+
* @param request - optional blank Session to reuse, location, and Agent preset.
|
|
110
|
+
* @returns the created or reused Session identity and its preset when configured.
|
|
106
111
|
*/
|
|
107
112
|
async create(request) {
|
|
108
113
|
if (request.workspaceId !== undefined && request.cwd !== undefined) {
|
|
109
114
|
throw new RemoteError('gateway/bad-request', 'session.create accepts workspaceId or cwd, not both', {});
|
|
110
115
|
}
|
|
111
|
-
const sessionId = request.sessionId ?? brandString(`session-${randomUUID()}`);
|
|
112
116
|
let workspace;
|
|
113
117
|
if (request.workspaceId !== undefined) {
|
|
114
118
|
workspace = this.ctx.workspaceRegistry.get(request.workspaceId);
|
|
@@ -119,13 +123,20 @@ export class SessionCommandController {
|
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
const cwd = workspace?.path ?? request.cwd ?? this.defaultCwd;
|
|
122
|
-
let
|
|
126
|
+
let created;
|
|
123
127
|
try {
|
|
124
|
-
|
|
128
|
+
created = await this.agents.createSession({
|
|
129
|
+
...(request.sessionId === undefined ? {} : { sessionId: request.sessionId }),
|
|
130
|
+
cwd,
|
|
131
|
+
...(request.agentPreset === undefined ? {} : { agentPreset: request.agentPreset }),
|
|
132
|
+
reusable: sessionId => !this.ctx.workspaceRegistry.archivedSessionIds.includes(sessionId)
|
|
133
|
+
&& (workspace === undefined || workspace.sessionIds.includes(sessionId)),
|
|
134
|
+
});
|
|
125
135
|
}
|
|
126
136
|
catch (error) {
|
|
127
|
-
this.rejectCreation(
|
|
137
|
+
this.rejectCreation(error);
|
|
128
138
|
}
|
|
139
|
+
const sessionId = created.agent.id;
|
|
129
140
|
if (workspace !== undefined) {
|
|
130
141
|
try {
|
|
131
142
|
await workspace.attachSession(sessionId);
|
|
@@ -134,8 +145,7 @@ export class SessionCommandController {
|
|
|
134
145
|
throw new RemoteError('session/workspace-attach-failed', `session "${sessionId}" was created but could not attach to workspace "${workspace.id}": ${String(error)}`, { sessionId, workspaceId: workspace.id });
|
|
135
146
|
}
|
|
136
147
|
}
|
|
137
|
-
|
|
138
|
-
return { sessionId, ...(agentPreset === undefined ? {} : { agentPreset }) };
|
|
148
|
+
return { sessionId, ...(created.agentPreset === undefined ? {} : { agentPreset: created.agentPreset }) };
|
|
139
149
|
}
|
|
140
150
|
/**
|
|
141
151
|
* Validate and install one Session-local model selection; save the default in the background.
|
|
@@ -283,28 +293,16 @@ export class SessionCommandController {
|
|
|
283
293
|
}
|
|
284
294
|
}
|
|
285
295
|
/**
|
|
286
|
-
*
|
|
287
|
-
*
|
|
296
|
+
* Admit one prompt after Agent and attachment validation; the Remote method
|
|
297
|
+
* has already validated the content and built the durable message source.
|
|
298
|
+
* @param request - Session identity, prompt content, and delivery mode.
|
|
299
|
+
* @param source - the `user-rpc` source recorded on the accepted message.
|
|
288
300
|
* @returns acknowledgement that the Agent accepted the prompt.
|
|
289
301
|
*/
|
|
290
|
-
async prompt(request) {
|
|
291
|
-
if (!hasPromptContent(request.content)) {
|
|
292
|
-
throw new RemoteError('gateway/bad-request', 'prompt content must include non-whitespace text or an attachment', {});
|
|
293
|
-
}
|
|
294
|
-
const clientTimeZone = request.clientTimeZone === undefined
|
|
295
|
-
? undefined
|
|
296
|
-
: canonicalClientTimeZone(request.clientTimeZone);
|
|
297
|
-
if (request.clientTimeZone !== undefined && clientTimeZone === undefined) {
|
|
298
|
-
throw new RemoteError('session/invalid-time-zone', 'clientTimeZone must be UTC or a valid IANA Area/Location name', { value: request.clientTimeZone });
|
|
299
|
-
}
|
|
302
|
+
async prompt(request, source) {
|
|
300
303
|
const agent = await this.resolveAgent(request.sessionId);
|
|
301
304
|
if (hasPromptRequest(agent, request.requestId))
|
|
302
305
|
return { accepted: true };
|
|
303
|
-
const source = {
|
|
304
|
-
kind: 'user',
|
|
305
|
-
rpcId: request.requestId,
|
|
306
|
-
...(clientTimeZone === undefined ? {} : { clientTimeZone }),
|
|
307
|
-
};
|
|
308
306
|
const hasImage = request.content.some(part => part.type === 'image');
|
|
309
307
|
const admit = async () => {
|
|
310
308
|
try {
|
|
@@ -482,17 +480,13 @@ export class SessionCommandController {
|
|
|
482
480
|
throw found.error;
|
|
483
481
|
return found.agent;
|
|
484
482
|
}
|
|
485
|
-
rejectCreation(
|
|
483
|
+
rejectCreation(error) {
|
|
486
484
|
if (remoteErrorOf(error) !== undefined)
|
|
487
485
|
throw error;
|
|
488
|
-
if (error instanceof Error && error.name === 'SessionAlreadyOwnedError') {
|
|
489
|
-
throw new RemoteError('session/writer-held', error.message, { sessionId });
|
|
490
|
-
}
|
|
491
486
|
if (error instanceof ApiSessionPresetConflict) {
|
|
492
487
|
throw new RemoteError('agent-preset/conflict', error.message, {
|
|
493
488
|
sessionId: error.sessionId,
|
|
494
489
|
requestedPreset: error.requestedPreset,
|
|
495
|
-
...(error.existingPreset === undefined ? {} : { existingPreset: error.existingPreset }),
|
|
496
490
|
});
|
|
497
491
|
}
|
|
498
492
|
if (error instanceof ApiSessionCwdConflict) {
|
|
@@ -505,7 +499,7 @@ export class SessionCommandController {
|
|
|
505
499
|
if (error instanceof ApiSessionSubagentOwnership) {
|
|
506
500
|
throw apiSessionSubagentOwnershipError(error.sessionId);
|
|
507
501
|
}
|
|
508
|
-
throw new RemoteError('gateway/internal', `failed to create session
|
|
502
|
+
throw new RemoteError('gateway/internal', `failed to create session: ${String(error)}`, {});
|
|
509
503
|
}
|
|
510
504
|
async readSessionState(sessionId) {
|
|
511
505
|
const attached = this.ctx.sessions.get(sessionId);
|
package/lib/types/index.d.ts
CHANGED
|
@@ -85,16 +85,18 @@ export declare class SessionController extends TypertRemoteService {
|
|
|
85
85
|
*/
|
|
86
86
|
list(_request: SessionListRequest, signal: AbortSignal): Promise<SessionListValue>;
|
|
87
87
|
/**
|
|
88
|
-
* Search visible Session content without resuming an Agent.
|
|
88
|
+
* Search visible Session content without resuming an Agent. A non-owner
|
|
89
|
+
* receives only the hits whose Session `allows()` admits; `hasMore`
|
|
90
|
+
* describes the bounded result before that filtering.
|
|
89
91
|
* @param request - literal message-content query.
|
|
90
92
|
* @param signal - cancellation for list and search reads.
|
|
91
93
|
* @returns authorized bounded Session search results.
|
|
92
94
|
*/
|
|
93
95
|
search(request: SessionSearchRequest, signal: AbortSignal): Promise<SessionSearchValue>;
|
|
94
96
|
/**
|
|
95
|
-
* Create
|
|
96
|
-
* @param request -
|
|
97
|
-
* @returns the Session identity and
|
|
97
|
+
* Create one ordinary Session for a new conversation, reusing the named blank Session while it is reusable.
|
|
98
|
+
* @param request - optional blank Session to reuse, location, and Agent preset.
|
|
99
|
+
* @returns the created or reused Session identity and its preset when configured.
|
|
98
100
|
*/
|
|
99
101
|
create(request: SessionCreateRequest): Promise<SessionCreateValue>;
|
|
100
102
|
/**
|
|
@@ -156,7 +158,7 @@ export declare class SessionController extends TypertRemoteService {
|
|
|
156
158
|
* Fork one cold-readable exact event prefix into a new Session. An omitted
|
|
157
159
|
* boundary selects the latest completed-turn prefix; an open cut receives
|
|
158
160
|
* synthetic fork closers.
|
|
159
|
-
* @param request - source Session
|
|
161
|
+
* @param request - source Session, optional exact inclusive event boundary, and migration preflight choice.
|
|
160
162
|
* @returns the new Session identity.
|
|
161
163
|
*/
|
|
162
164
|
fork(request: SessionForkRequest): Promise<SessionForkValue>;
|
|
@@ -201,12 +203,13 @@ export declare class SessionController extends TypertRemoteService {
|
|
|
201
203
|
*/
|
|
202
204
|
follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>;
|
|
203
205
|
/**
|
|
204
|
-
* Read
|
|
206
|
+
* Read exact projections, returning cached hints only when migration is required.
|
|
205
207
|
* @param request - Session whose current values are required.
|
|
206
|
-
* @param signal - cancellation for the Session
|
|
207
|
-
* @returns
|
|
208
|
+
* @param signal - cancellation for the Session read.
|
|
209
|
+
* @returns a sequenced baseline, cached hints when migration is deferred, or null when absent.
|
|
208
210
|
*/
|
|
209
211
|
projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise<SessionProjectionsValue>;
|
|
212
|
+
private liveProjections;
|
|
210
213
|
/**
|
|
211
214
|
* Stream a complete live-control baseline followed by replacement frames.
|
|
212
215
|
* @param signal - cancellation owned by the Remote stream carrier.
|