@deepseek-ai/dsh-session-reference 0.1.6-alpha.1 → 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.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/context/session-reference/README.md
5
- README.md: 533a1282da920b6daa47ef5be98e49c691a8cb84
6
- README.zh.md: e7b43c9a56cd5b4062770144ccea0bf125153b40
5
+ README.md: e1afeef9b0e78826705ad2b3e426373b2bf0833d
6
+ README.zh.md: e55dab4f6403cb6aee947f80873ffe99919acc5f
package/README.md CHANGED
@@ -39,7 +39,7 @@ For a truncated reference, an optional spill backend saves the full captured tex
39
39
 
40
40
  ### Finding sessions to reference
41
41
 
42
- `listCandidates(agent, query?, limit?)` lists sessions other than the agent's own, filters case-insensitively by id, working directory, or the projected title, and ranks same-directory sessions first. Each candidate carries its latest title as the mention label, falling back to the session id when the title is absent or unreadable, and reports whether its working directory is the requesting agent's so a host can surface a location only when it distinguishes the row. Browser consumers call the same discovery as `ctx.remote.sessionReferenceResolver.candidates`, which attaches each candidate's canonical mention.
42
+ `listCandidates(agent, query?, limit?)` lists sessions other than the agent's own, filters case-insensitively by id, working directory, projected title, or display title, and ranks same-directory sessions first. Each candidate carries its latest title as `label`, falling back to the session id when the title is absent or unreadable. Its display title prefers a subagent's durable creation label over that title. The candidate also reports whether its working directory is the requesting agent's so a host can surface a location only when it distinguishes the row. Browser consumers call the same discovery as `ctx.remote.sessionReferenceResolver.candidates`, which labels the canonical mention with `displayTitle` when present.
43
43
 
44
44
  ### Configuration
45
45
 
package/README.zh.md CHANGED
@@ -39,7 +39,7 @@ kind: "package-reference"
39
39
 
40
40
  ### 查找可引用的会话
41
41
 
42
- `listCandidates(agent, query?, limit?)` 列出除 agent 自身外的会话,按 id、工作目录或投影标题做不区分大小写的过滤,并把同目录会话排在前面。每个候选以其最新标题作为 mention 标签;标题缺失或不可读时回退到会话 id,并报告其工作目录是否就是发起方 agent 的工作目录,宿主因此可以只在位置能区分该行时才显示它。浏览器消费方通过 `ctx.remote.sessionReferenceResolver.candidates` 调用同一发现能力,该方法会为每个候选附上规范 mention。
42
+ `listCandidates(agent, query?, limit?)` 列出除 agent 自身外的会话,按 id、工作目录、投影标题或显示标题做不区分大小写的过滤,并把同目录会话排在前面。每个候选的 `label` 使用最新标题;标题缺失或不可读时回退到会话 id。显示标题优先使用 subagent 的持久创建 label,再回退到该标题。候选还会报告其工作目录是否就是发起方 agent 的工作目录,宿主因此可以只在位置能区分该行时才显示它。浏览器消费方通过 `ctx.remote.sessionReferenceResolver.candidates` 调用同一发现能力;该方法在 `displayTitle` 存在时用它标记规范 mention。
43
43
 
44
44
  ### 配置
45
45
 
package/lib/index.js CHANGED
@@ -508,14 +508,13 @@ let SessionReferenceResolver = (() => {
508
508
  /**
509
509
  * List reference candidates, ranked by working-directory affinity.
510
510
  *
511
- * Discovery runs at keystroke rate, so a title only ever comes from a
512
- * projection read: see {@link SessionReferenceResolver.projectedTitle} for
513
- * which sessions can answer one and which fall back to their id.
511
+ * Discovery runs at keystroke rate, so titles and subagent labels only ever
512
+ * come from projection reads; sessions without either fall back to their id.
514
513
  * @param agent - target agent; self is excluded and its cwd drives ranking.
515
- * @param query - optional case-insensitive session-id/cwd/title substring.
514
+ * @param query - optional case-insensitive session-id/cwd/title/display-title substring.
516
515
  * @param limit - optional positive result cap.
517
516
  * @param signal - optional cancellation boundary for host autocomplete teardown.
518
- * @returns candidates labeled by latest title or, when absent, session id.
517
+ * @returns candidates with canonical mention labels and presentation titles.
519
518
  */
520
519
  async listCandidates(agent, query = "", limit = this.config.candidateLimit, signal) {
521
520
  if (!Number.isSafeInteger(limit) || limit <= 0) throw new SessionReferenceError("candidate limit must be a positive safe integer", "SESSION_REFERENCE_INVALID_REFERENCE");
@@ -528,20 +527,21 @@ let SessionReferenceResolver = (() => {
528
527
  })).map(({ record, index }) => ({
529
528
  record,
530
529
  index,
531
- label: this.projectedTitle(record) ?? record.header.id
532
- })).filter(({ record, label }) => {
530
+ ...this.projectedLabels(record)
531
+ })).filter(({ record, label, displayTitle }) => {
533
532
  if (needle === "") return true;
534
- return record.header.id.toLocaleLowerCase().includes(needle) || record.header.cwd?.toLocaleLowerCase().includes(needle) === true || label.toLocaleLowerCase().includes(needle);
535
- }).sort((a, b) => candidateRank(a.record.header.cwd, targetCwd) - candidateRank(b.record.header.cwd, targetCwd) || a.index - b.index).slice(0, limit).map(({ record, label }) => ({
533
+ return record.header.id.toLocaleLowerCase().includes(needle) || record.header.cwd?.toLocaleLowerCase().includes(needle) === true || label.toLocaleLowerCase().includes(needle) || displayTitle.toLocaleLowerCase().includes(needle);
534
+ }).sort((a, b) => candidateRank(a.record.header.cwd, targetCwd) - candidateRank(b.record.header.cwd, targetCwd) || a.index - b.index).slice(0, limit).map(({ record, label, displayTitle }) => ({
536
535
  sessionId: record.header.id,
537
536
  label,
537
+ displayTitle,
538
538
  ...record.header.cwd === void 0 ? {} : { cwd: record.header.cwd },
539
539
  sameWorkspace: record.header.cwd !== void 0 && record.header.cwd === targetCwd,
540
540
  createdAt: record.header.createdAt
541
541
  }));
542
542
  }
543
543
  /**
544
- * The title a session's projections can answer without reading its log.
544
+ * The mention label and display title a Session's projections can answer without reading its log.
545
545
  *
546
546
  * Attachment is decided by the store at read time, not by the listing:
547
547
  * a session that attached in between would otherwise be answered from a
@@ -560,14 +560,18 @@ let SessionReferenceResolver = (() => {
560
560
  * and cannot be found by its title until it is opened once, which
561
561
  * checkpoints it.
562
562
  * @param record - the listed session, live or cold.
563
- * @returns the projected title, or undefined when no projection holds one.
563
+ * @returns the title-backed mention label and the subagent-label-first display title.
564
564
  */
565
- projectedTitle(record) {
565
+ projectedLabels(record) {
566
566
  const attached = this.ctx.get("sessions")?.get(record.header.id);
567
567
  const projections = this.ctx.get("sessionProjections");
568
- if (attached !== void 0 && projections !== void 0) return titleOf(projections.snapshot(attached, ["title"]));
569
- if (record.header.isSeeded) return void 0;
570
- return titleOf(this.ctx.get("sessionProjectionCache")?.cachedSnapshot(record.header, SessionLogOffset(0), ["title"]));
568
+ const snapshot = attached !== void 0 && projections !== void 0 ? projections.snapshot(attached, ["title", "subagent"]) : record.header.isSeeded ? void 0 : this.ctx.get("sessionProjectionCache")?.cachedSnapshot(record.header, SessionLogOffset(0), ["title", "subagent"]);
569
+ const label = titleOf(snapshot) ?? record.header.id;
570
+ const subagent = snapshot?.values.subagent;
571
+ return {
572
+ label,
573
+ displayTitle: subagent === void 0 || subagent === null ? label : subagent.label ?? label
574
+ };
571
575
  }
572
576
  /**
573
577
  * Remote face of {@link listCandidates}: the configured candidate limit
@@ -583,7 +587,7 @@ let SessionReferenceResolver = (() => {
583
587
  ...candidate,
584
588
  mention: formatSessionReferenceMention({
585
589
  sessionId: candidate.sessionId,
586
- label: candidate.label
590
+ label: candidate.displayTitle ?? candidate.label
587
591
  })
588
592
  }));
589
593
  }
@@ -1,16 +1,20 @@
1
1
  /* Generated by @deepseek-ai/dsh-typert-generator from FaceModel — do not edit. */
2
2
  import { z } from 'zod'
3
3
 
4
- const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema = z.intersection(z.string(), z.unknown())
5
- const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema = z.string()
6
- const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema = z.array(z.object({
4
+ let _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema$value
5
+ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema = () => (_deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema$value ??= z.intersection(z.string(), z.unknown()))
6
+ let _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema$value
7
+ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema = () => (_deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema$value ??= z.string())
8
+ let _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema$value
9
+ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema = () => (_deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema$value ??= z.array(z.object({
7
10
  'mention': z.string(),
8
11
  'sessionId': z.intersection(z.string(), z.unknown()),
9
12
  'label': z.string(),
13
+ 'displayTitle': z.string().optional(),
10
14
  'cwd': z.string().optional(),
11
15
  'sameWorkspace': z.boolean(),
12
16
  'createdAt': z.number(),
13
- }))
17
+ })))
14
18
 
15
19
  export const TYPERT = {
16
20
  package: '@deepseek-ai/dsh-session-reference',
@@ -38,7 +42,7 @@ export const TYPERT = {
38
42
  codec: {
39
43
  mode: 'strict',
40
44
  typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
41
- schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema,
45
+ create: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema,
42
46
  },
43
47
  },
44
48
  {
@@ -48,7 +52,7 @@ export const TYPERT = {
48
52
  codec: {
49
53
  mode: 'strict',
50
54
  typeSymbol: '@deepseek-ai/dsh-session-reference#sessionReferenceResolver/candidates:query',
51
- schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema,
55
+ create: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema,
52
56
  },
53
57
  },
54
58
  ],
@@ -56,9 +60,9 @@ export const TYPERT = {
56
60
  result: {
57
61
  mode: 'strict',
58
62
  typeSymbol: '@deepseek-ai/dsh-session-reference#sessionReferenceResolver/candidates:result',
59
- schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema,
63
+ create: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema,
60
64
  },
61
- sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":274,"column":9},
65
+ sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":280,"column":9},
62
66
  },
63
67
  ],
64
68
  model: {
@@ -76,7 +80,7 @@ export const TYPERT = {
76
80
  "name": "listCandidates",
77
81
  "signature": "async listCandidates( agent: Agent, query: string = '', limit: number = this.config.candidateLimit, signal?: AbortSignal, ): Promise<SessionReferenceCandidate[]>",
78
82
  "summary": "List reference candidates, ranked by working-directory affinity.",
79
- "jsDoc": "/**\n * List reference candidates, ranked by working-directory affinity.\n *\n * Discovery runs at keystroke rate, so a title only ever comes from a\n * projection read: see {@link SessionReferenceResolver.projectedTitle} for\n * which sessions can answer one and which fall back to their id.\n * @param agent - target agent; self is excluded and its cwd drives ranking.\n * @param query - optional case-insensitive session-id/cwd/title substring.\n * @param limit - optional positive result cap.\n * @param signal - optional cancellation boundary for host autocomplete teardown.\n * @returns candidates labeled by latest title or, when absent, session id.\n */"
83
+ "jsDoc": "/**\n * List reference candidates, ranked by working-directory affinity.\n *\n * Discovery runs at keystroke rate, so titles and subagent labels only ever\n * come from projection reads; sessions without either fall back to their id.\n * @param agent - target agent; self is excluded and its cwd drives ranking.\n * @param query - optional case-insensitive session-id/cwd/title/display-title substring.\n * @param limit - optional positive result cap.\n * @param signal - optional cancellation boundary for host autocomplete teardown.\n * @returns candidates with canonical mention labels and presentation titles.\n */"
80
84
  },
81
85
  {
82
86
  "kind": "method",
@@ -424,7 +428,7 @@ export const TYPERT = {
424
428
  },
425
429
  {
426
430
  "name": "SessionReferenceCandidate",
427
- "declaration": "export interface SessionReferenceCandidate {\n sessionId: SessionId;\n label: string;\n cwd?: string;\n sameWorkspace: boolean;\n createdAt: number;\n}"
431
+ "declaration": "export interface SessionReferenceCandidate {\n sessionId: SessionId;\n label: string;\n displayTitle?: string;\n cwd?: string;\n sameWorkspace: boolean;\n createdAt: number;\n}"
428
432
  },
429
433
  {
430
434
  "name": "SessionReferenceInput",
@@ -1,16 +1,20 @@
1
1
  /* Generated by @deepseek-ai/dsh-typert-generator from the Host FaceModel — do not edit. */
2
2
  import { z } from 'zod'
3
3
 
4
- const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema = z.intersection(z.string(), z.unknown())
5
- const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema = z.string()
6
- const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema = z.array(z.object({
4
+ let _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema$value
5
+ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema = () => (_deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema$value ??= z.intersection(z.string(), z.unknown()))
6
+ let _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema$value
7
+ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema = () => (_deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema$value ??= z.string())
8
+ let _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema$value
9
+ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema = () => (_deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema$value ??= z.array(z.object({
7
10
  'mention': z.string(),
8
11
  'sessionId': z.intersection(z.string(), z.unknown()),
9
12
  'label': z.string(),
13
+ 'displayTitle': z.string().optional(),
10
14
  'cwd': z.string().optional(),
11
15
  'sameWorkspace': z.boolean(),
12
16
  'createdAt': z.number(),
13
- }))
17
+ })))
14
18
 
15
19
  export const TYPERT_REMOTE = {
16
20
  package: '@deepseek-ai/dsh-session-reference',
@@ -35,7 +39,7 @@ export const TYPERT_REMOTE = {
35
39
  codec: {
36
40
  mode: 'strict',
37
41
  typeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
38
- schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema,
42
+ create: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_0$schema,
39
43
  },
40
44
  },
41
45
  {
@@ -45,7 +49,7 @@ export const TYPERT_REMOTE = {
45
49
  codec: {
46
50
  mode: 'strict',
47
51
  typeSymbol: '@deepseek-ai/dsh-session-reference#sessionReferenceResolver/candidates:query',
48
- schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema,
52
+ create: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_parameter_1$schema,
49
53
  },
50
54
  },
51
55
  ],
@@ -53,9 +57,9 @@ export const TYPERT_REMOTE = {
53
57
  result: {
54
58
  mode: 'strict',
55
59
  typeSymbol: '@deepseek-ai/dsh-session-reference#sessionReferenceResolver/candidates:result',
56
- schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema,
60
+ create: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema,
57
61
  },
58
- sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":274,"column":9},
62
+ sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":280,"column":9},
59
63
  },
60
64
  ],
61
65
  }
@@ -39,18 +39,17 @@ export declare class SessionReferenceResolver extends TypertRemoteService {
39
39
  /**
40
40
  * List reference candidates, ranked by working-directory affinity.
41
41
  *
42
- * Discovery runs at keystroke rate, so a title only ever comes from a
43
- * projection read: see {@link SessionReferenceResolver.projectedTitle} for
44
- * which sessions can answer one and which fall back to their id.
42
+ * Discovery runs at keystroke rate, so titles and subagent labels only ever
43
+ * come from projection reads; sessions without either fall back to their id.
45
44
  * @param agent - target agent; self is excluded and its cwd drives ranking.
46
- * @param query - optional case-insensitive session-id/cwd/title substring.
45
+ * @param query - optional case-insensitive session-id/cwd/title/display-title substring.
47
46
  * @param limit - optional positive result cap.
48
47
  * @param signal - optional cancellation boundary for host autocomplete teardown.
49
- * @returns candidates labeled by latest title or, when absent, session id.
48
+ * @returns candidates with canonical mention labels and presentation titles.
50
49
  */
51
50
  listCandidates(agent: Agent, query?: string, limit?: number, signal?: AbortSignal): Promise<SessionReferenceCandidate[]>;
52
51
  /**
53
- * The title a session's projections can answer without reading its log.
52
+ * The mention label and display title a Session's projections can answer without reading its log.
54
53
  *
55
54
  * Attachment is decided by the store at read time, not by the listing:
56
55
  * a session that attached in between would otherwise be answered from a
@@ -69,9 +68,9 @@ export declare class SessionReferenceResolver extends TypertRemoteService {
69
68
  * and cannot be found by its title until it is opened once, which
70
69
  * checkpoints it.
71
70
  * @param record - the listed session, live or cold.
72
- * @returns the projected title, or undefined when no projection holds one.
71
+ * @returns the title-backed mention label and the subagent-label-first display title.
73
72
  */
74
- private projectedTitle;
73
+ private projectedLabels;
75
74
  /**
76
75
  * Remote face of {@link listCandidates}: the configured candidate limit
77
76
  * applies, and every candidate carries the canonical mention a host inserts
@@ -153,14 +153,13 @@ let SessionReferenceResolver = (() => {
153
153
  /**
154
154
  * List reference candidates, ranked by working-directory affinity.
155
155
  *
156
- * Discovery runs at keystroke rate, so a title only ever comes from a
157
- * projection read: see {@link SessionReferenceResolver.projectedTitle} for
158
- * which sessions can answer one and which fall back to their id.
156
+ * Discovery runs at keystroke rate, so titles and subagent labels only ever
157
+ * come from projection reads; sessions without either fall back to their id.
159
158
  * @param agent - target agent; self is excluded and its cwd drives ranking.
160
- * @param query - optional case-insensitive session-id/cwd/title substring.
159
+ * @param query - optional case-insensitive session-id/cwd/title/display-title substring.
161
160
  * @param limit - optional positive result cap.
162
161
  * @param signal - optional cancellation boundary for host autocomplete teardown.
163
- * @returns candidates labeled by latest title or, when absent, session id.
162
+ * @returns candidates with canonical mention labels and presentation titles.
164
163
  */
165
164
  async listCandidates(agent, query = '', limit = this.config.candidateLimit, signal) {
166
165
  if (!Number.isSafeInteger(limit) || limit <= 0) {
@@ -172,30 +171,28 @@ let SessionReferenceResolver = (() => {
172
171
  const records = (await settleWithCancellation(this.ctx.sessionQuery.listSessions(signal), signal))
173
172
  .filter(record => record.header.id !== agent.id)
174
173
  .map((record, index) => ({ record, index }));
175
- const labelled = records.map(({ record, index }) => ({
176
- record,
177
- index,
178
- label: this.projectedTitle(record) ?? record.header.id,
179
- }));
180
- return labelled.filter(({ record, label }) => {
174
+ const labelled = records.map(({ record, index }) => ({ record, index, ...this.projectedLabels(record) }));
175
+ return labelled.filter(({ record, label, displayTitle }) => {
181
176
  if (needle === '')
182
177
  return true;
183
178
  return record.header.id.toLocaleLowerCase().includes(needle)
184
179
  || record.header.cwd?.toLocaleLowerCase().includes(needle) === true
185
- || label.toLocaleLowerCase().includes(needle);
180
+ || label.toLocaleLowerCase().includes(needle)
181
+ || displayTitle.toLocaleLowerCase().includes(needle);
186
182
  }).sort((a, b) => candidateRank(a.record.header.cwd, targetCwd) - candidateRank(b.record.header.cwd, targetCwd)
187
183
  || a.index - b.index)
188
184
  .slice(0, limit)
189
- .map(({ record, label }) => ({
185
+ .map(({ record, label, displayTitle }) => ({
190
186
  sessionId: record.header.id,
191
187
  label,
188
+ displayTitle,
192
189
  ...record.header.cwd === undefined ? {} : { cwd: record.header.cwd },
193
190
  sameWorkspace: record.header.cwd !== undefined && record.header.cwd === targetCwd,
194
191
  createdAt: record.header.createdAt,
195
192
  }));
196
193
  }
197
194
  /**
198
- * The title a session's projections can answer without reading its log.
195
+ * The mention label and display title a Session's projections can answer without reading its log.
199
196
  *
200
197
  * Attachment is decided by the store at read time, not by the listing:
201
198
  * a session that attached in between would otherwise be answered from a
@@ -214,17 +211,24 @@ let SessionReferenceResolver = (() => {
214
211
  * and cannot be found by its title until it is opened once, which
215
212
  * checkpoints it.
216
213
  * @param record - the listed session, live or cold.
217
- * @returns the projected title, or undefined when no projection holds one.
214
+ * @returns the title-backed mention label and the subagent-label-first display title.
218
215
  */
219
- projectedTitle(record) {
216
+ projectedLabels(record) {
220
217
  const attached = this.ctx.get('sessions')?.get(record.header.id);
221
218
  const projections = this.ctx.get('sessionProjections');
222
- if (attached !== undefined && projections !== undefined) {
223
- return titleOf(projections.snapshot(attached, ['title']));
224
- }
225
- if (record.header.isSeeded)
226
- return undefined;
227
- return titleOf(this.ctx.get('sessionProjectionCache')?.cachedSnapshot(record.header, SessionLogOffset(0), ['title']));
219
+ const snapshot = attached !== undefined && projections !== undefined
220
+ ? projections.snapshot(attached, ['title', 'subagent'])
221
+ : record.header.isSeeded
222
+ ? undefined
223
+ : this.ctx.get('sessionProjectionCache')?.cachedSnapshot(record.header, SessionLogOffset(0), ['title', 'subagent']);
224
+ const label = titleOf(snapshot) ?? record.header.id;
225
+ const subagent = snapshot?.values.subagent;
226
+ return {
227
+ label,
228
+ displayTitle: subagent === undefined || subagent === null
229
+ ? label
230
+ : subagent.label ?? label,
231
+ };
228
232
  }
229
233
  /**
230
234
  * Remote face of {@link listCandidates}: the configured candidate limit
@@ -239,7 +243,10 @@ let SessionReferenceResolver = (() => {
239
243
  const candidates = await this.listCandidates(agent, query, this.config.candidateLimit, signal);
240
244
  return candidates.map(candidate => ({
241
245
  ...candidate,
242
- mention: formatSessionReferenceMention({ sessionId: candidate.sessionId, label: candidate.label }),
246
+ mention: formatSessionReferenceMention({
247
+ sessionId: candidate.sessionId,
248
+ label: candidate.displayTitle ?? candidate.label,
249
+ }),
243
250
  }));
244
251
  }
245
252
  /**
@@ -46,6 +46,8 @@ export interface SessionReferenceCandidate {
46
46
  sessionId: SessionId;
47
47
  /** Latest log-backed title, falling back to the opaque session id. */
48
48
  label: string;
49
+ /** Display and canonical-mention text, preferring a subagent's durable creation label over {@link label}. */
50
+ displayTitle?: string;
49
51
  /** Source session working directory, when recorded. */
50
52
  cwd?: string;
51
53
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-session-reference",
3
3
  "description": "Cross-session snapshot references and durable untrusted model context (ctx.sessionReferenceResolver)",
4
- "version": "0.1.6-alpha.1",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -45,24 +45,25 @@
45
45
  "license": "MIT",
46
46
  "dependencies": {
47
47
  "zod": "^4.4.3",
48
- "@deepseek-ai/dsh-util-values": "^0.1.6-alpha.1",
49
- "@deepseek-ai/schemastery": "^3.18.2",
50
- "@deepseek-ai/dsh-brand": "^0.1.6-alpha.1"
48
+ "@deepseek-ai/dsh-brand": "^0.1.6-alpha.2",
49
+ "@deepseek-ai/dsh-util-values": "^0.1.6-alpha.2",
50
+ "@deepseek-ai/schemastery": "^3.18.2"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@deepseek-ai/cordis": "^4.0.2",
54
- "@deepseek-ai/dsh-agent": "^0.1.6-alpha.1",
55
- "@deepseek-ai/dsh-llm": "^0.1.6-alpha.1",
56
- "@deepseek-ai/dsh-output-retention": "^0.1.6-alpha.1",
57
- "@deepseek-ai/dsh-session": "^0.1.6-alpha.1",
58
- "@deepseek-ai/dsh-session-projection": "^0.1.6-alpha.1",
59
- "@deepseek-ai/dsh-compaction": "^0.1.6-alpha.1",
60
- "@deepseek-ai/dsh-session-projection-cache": "^0.1.6-alpha.1",
61
- "@deepseek-ai/dsh-session-query": "^0.1.6-alpha.1",
62
- "@deepseek-ai/dsh-session-title": "^0.1.6-alpha.1",
63
- "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.1",
64
- "@deepseek-ai/dsh-spill": "^0.1.6-alpha.1",
65
- "@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.1"
54
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
55
+ "@deepseek-ai/dsh-compaction": "^0.1.6-alpha.2",
56
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
57
+ "@deepseek-ai/dsh-output-retention": "^0.1.6-alpha.2",
58
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
59
+ "@deepseek-ai/dsh-session-projection": "^0.1.6-alpha.2",
60
+ "@deepseek-ai/dsh-session-projection-cache": "^0.1.6-alpha.2",
61
+ "@deepseek-ai/dsh-session-query": "^0.1.6-alpha.2",
62
+ "@deepseek-ai/dsh-session-title": "^0.1.6-alpha.2",
63
+ "@deepseek-ai/dsh-spill": "^0.1.6-alpha.2",
64
+ "@deepseek-ai/dsh-subagent": "^0.1.6-alpha.2",
65
+ "@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.2",
66
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2"
66
67
  },
67
68
  "peerDependenciesMeta": {
68
69
  "@deepseek-ai/dsh-spill": {
@@ -76,22 +77,23 @@
76
77
  "@deepseek-ai/cordis": "^4.0.2",
77
78
  "@deepseek-ai/cordis-plugin-include": "^1.0.7",
78
79
  "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
79
- "@deepseek-ai/dsh-compaction": "^0.1.6-alpha.1",
80
- "@deepseek-ai/dsh-agent": "^0.1.6-alpha.1",
81
- "@deepseek-ai/dsh-llm": "^0.1.6-alpha.1",
82
- "@deepseek-ai/dsh-output-retention": "^0.1.6-alpha.1",
83
- "@deepseek-ai/dsh-session": "^0.1.6-alpha.1",
84
- "@deepseek-ai/dsh-fs-local": "^0.1.6-alpha.1",
85
- "@deepseek-ai/dsh-session-projection": "^0.1.6-alpha.1",
86
- "@deepseek-ai/dsh-session-projection-cache": "^0.1.6-alpha.1",
87
- "@deepseek-ai/dsh-session-query": "^0.1.6-alpha.1",
88
- "@deepseek-ai/dsh-session-query-sqlite": "^0.1.6-alpha.1",
89
- "@deepseek-ai/dsh-session-title": "^0.1.6-alpha.1",
90
- "@deepseek-ai/dsh-spill": "^0.1.6-alpha.1",
91
- "@deepseek-ai/dsh-spill-local": "^0.1.6-alpha.1",
92
- "@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.1",
93
- "@deepseek-ai/dsh-tool-fs": "^0.1.6-alpha.1",
94
- "@deepseek-ai/dsh-tools": "^0.1.6-alpha.1",
95
- "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.1"
80
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
81
+ "@deepseek-ai/dsh-compaction": "^0.1.6-alpha.2",
82
+ "@deepseek-ai/dsh-fs-local": "^0.1.6-alpha.2",
83
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
84
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
85
+ "@deepseek-ai/dsh-session-projection": "^0.1.6-alpha.2",
86
+ "@deepseek-ai/dsh-session-projection-cache": "^0.1.6-alpha.2",
87
+ "@deepseek-ai/dsh-output-retention": "^0.1.6-alpha.2",
88
+ "@deepseek-ai/dsh-session-query-sqlite": "^0.1.6-alpha.2",
89
+ "@deepseek-ai/dsh-session-title": "^0.1.6-alpha.2",
90
+ "@deepseek-ai/dsh-spill": "^0.1.6-alpha.2",
91
+ "@deepseek-ai/dsh-subagent": "^0.1.6-alpha.2",
92
+ "@deepseek-ai/dsh-spill-local": "^0.1.6-alpha.2",
93
+ "@deepseek-ai/dsh-system-prompt": "^0.1.6-alpha.2",
94
+ "@deepseek-ai/dsh-tool-fs": "^0.1.6-alpha.2",
95
+ "@deepseek-ai/dsh-session-query": "^0.1.6-alpha.2",
96
+ "@deepseek-ai/dsh-tools": "^0.1.6-alpha.2",
97
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2"
96
98
  }
97
99
  }