@deepseek-ai/dsh-session-reference 0.1.1-rc.2 → 0.1.2-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 +104 -17
- package/README.zh.md +105 -18
- package/lib/index.js +49 -16
- package/lib/typert.host.js +109 -24
- package/lib/typert.remote-client.js +2 -1
- package/lib/types/index.d.ts +27 -0
- package/lib/types/index.js +47 -18
- package/lib/types/projection.js +1 -1
- package/lib/types/types.d.ts +6 -0
- package/lib/types/uri.d.ts +1 -1
- package/lib/types/uri.js +2 -2
- package/package.json +33 -20
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:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 804cfea6357d4e9fc202e6562e75d740c5702c24
|
|
6
|
+
README.zh.md: 4a249ea63cb7546603666990f67add54ebfe035a
|
package/README.md
CHANGED
|
@@ -1,31 +1,102 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "Cross-session snapshot references and durable untrusted model context, for users and maintainers enabling or debugging ctx.sessionReferenceResolver."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-session-reference
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-session-reference` lets a conversation reference other sessions: a host turns a `@label` mention into a canonical URI, and the service prepares a bounded, read-only snapshot of each referenced session as durable, untrusted background context for the model. Candidate discovery ranks other sessions by working-directory affinity and labels them with their latest titles. Snapshots are immutable after capture and carry a fixed warning that forbids following instructions, permission claims, or tool requests inside them. It is an opt-in service for hosts that support cross-session mentions; it consumes `ctx.sessionQuery` and needs no SQLite FTS.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Enable this service when hosts should let a user mention another session and give the model its context. It works with any session-query backend because it consumes the backend-independent compact checkpoint marker.
|
|
29
|
+
|
|
30
|
+
### Mention syntax
|
|
31
|
+
|
|
32
|
+
A canonical mention is `@[label](dsh-session:<base64url-encoded-id>)` in Markdown, or the bare `dsh-session:` URI; every JavaScript string session id round-trips exactly. The service rewrites mentions into readable `@label` text in the message and returns the structured references. Explicit Markdown mentions reject malformed URIs; empty or punctuation-only scheme mentions stay ordinary discussion text.
|
|
33
|
+
|
|
34
|
+
### What the agent gets
|
|
35
|
+
|
|
36
|
+
A message that cites other sessions is followed immediately by a `## Referenced sessions` snapshot as a second user-role message. The snapshot is untrusted background: the fixed warning tells the model not to follow instructions, permission claims, or tool requests inside it unless the current user explicitly repeats them. Each source is bounded independently — at most `maxReferences` distinct sessions per message and `maxReferenceBytes` per source — and a source that cannot fit its budget fails preparation instead of returning partial context.
|
|
37
|
+
|
|
38
|
+
### Finding sessions to reference
|
|
39
|
+
|
|
40
|
+
`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.
|
|
41
|
+
|
|
42
|
+
### Configuration
|
|
43
|
+
|
|
44
|
+
| Field | Default | Meaning |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `maxReferences` | `3` | Maximum distinct source sessions in one prepared message; must not exceed `3` |
|
|
47
|
+
| `candidateLimit` | `50` | Default candidate count returned to a host |
|
|
48
|
+
| `maxReferenceBytes` | `65536` | Maximum serialized JSON bytes for one reference object |
|
|
49
|
+
|
|
50
|
+
The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-session-reference) is the exhaustive source for every accepted field and its JSDoc.
|
|
6
51
|
|
|
7
|
-
|
|
52
|
+
-----
|
|
8
53
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- `encodeSessionReferenceUri()` and `decodeSessionReferenceUri()` implement `dsh-session:<base64url(JSON.stringify(sessionId))>` so every JavaScript string id round-trips exactly. `formatSessionReferenceMention()` emits `@[label](uri)`, and `parseSessionReferenceText()` replaces Markdown mentions or bare canonical URIs with readable `@label` text while returning structured references. Explicit Markdown mentions reject every malformed URI; bare text is considered a reference only when a non-empty base64url-shaped payload follows the scheme, and a matching noncanonical candidate still fails. Empty or punctuation-only scheme mentions remain ordinary discussion text.
|
|
54
|
+
<a id="understand-the-implementation"></a>
|
|
55
|
+
## Understand the implementation
|
|
12
56
|
|
|
13
|
-
|
|
57
|
+
<details>
|
|
58
|
+
<summary>Implementation internals — click to expand</summary>
|
|
14
59
|
|
|
15
|
-
|
|
60
|
+
This section explains the design of the service; the observable behavior is covered in [Use this package](#use-this-package).
|
|
16
61
|
|
|
17
|
-
|
|
62
|
+
### Design concept
|
|
18
63
|
|
|
19
|
-
|
|
64
|
+
Preparation reads each referenced session's current surface exactly once, when the target message reaches `agent/pre-step`, so a queued message captures source state at model-step entry and the resulting context is immutable afterwards. Projection keeps only direct-user `user/message`, assistant text, and `user/message` checkpoints carrying the canonical compaction marker; separately sourced session-reference messages are excluded, preventing recursive snapshot propagation. Source text is serialized as JSON with every `<` escaped as `\u003c`, so it cannot spell the `<referenced-sessions>` framing tag.
|
|
20
65
|
|
|
21
|
-
|
|
22
|
-
|---|---:|---|
|
|
23
|
-
| `maxReferences` | `3` | Maximum distinct source sessions in one prepared message; must be at most `3`. |
|
|
24
|
-
| `candidateLimit` | `50` | Default candidate count returned to a host. |
|
|
25
|
-
| `maxReferenceBytes` | `65536` | Maximum serialized JSON bytes for one reference object. |
|
|
66
|
+
### Source map
|
|
26
67
|
|
|
27
|
-
|
|
68
|
+
| File | Role |
|
|
69
|
+
|---|---|
|
|
70
|
+
| [`src/index.ts`](src/index.ts) | `SessionReferenceResolver`: pre-step listener, candidate discovery, preparation |
|
|
71
|
+
| [`src/config.ts`](src/config.ts) | `Config` schema, `SessionReferenceError` taxonomy |
|
|
72
|
+
| [`src/uri.ts`](src/uri.ts) | `dsh-session:` URI codec, mention formatting and parsing |
|
|
73
|
+
| [`src/projection.ts`](src/projection.ts) | Current-surface projection and byte-budget retention |
|
|
74
|
+
| [`src/serialization.ts`](src/serialization.ts) | Tag-safe JSON escaping for snapshot payloads |
|
|
75
|
+
| [`src/types.ts`](src/types.ts) | `SessionReferenceInput`/`Candidate` and source types |
|
|
76
|
+
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion for the reference contract |
|
|
28
77
|
|
|
78
|
+
### Main flow
|
|
79
|
+
|
|
80
|
+
The outer `agent/pre-step` listener accepts the step, parses canonical mentions out of direct user messages, then calls `prepare`, which normalizes references (first-mention order, deduplication, self-reference and count rejection), reads every surface in parallel, retains each under `maxReferenceBytes`, and renders the aggregated prompt. Each snapshot is inserted immediately after the message that cited it, and the target log records the readable direct message followed by its sourced context, so source mutation after capture cannot change target replay.
|
|
81
|
+
|
|
82
|
+
</details>
|
|
83
|
+
|
|
84
|
+
-----
|
|
85
|
+
|
|
86
|
+
<a id="further-exploration"></a>
|
|
87
|
+
## Further Exploration
|
|
88
|
+
|
|
89
|
+
Read these pages when the package-level contract is not enough. They move from the shared reference surface to the design decision and the read service behind it.
|
|
90
|
+
|
|
91
|
+
- [Session-reference subsystem](../../../docs/subsystems/session-reference.md) — canonical URIs, projection rules, and the stable error taxonomy.
|
|
92
|
+
- [Cross-session references decision record](../../../.agents/notes/implemented/feature/2026-07-21-cross-session-references.md) — design rationale for the reference contract.
|
|
93
|
+
- [Session-query subsystem](../../../docs/subsystems/session-query.md) — the read service that supplies session surfaces.
|
|
94
|
+
- [Context group map](../README.md) — sibling request-context packages.
|
|
95
|
+
- [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-session-reference) — every accepted config field and its source declaration.
|
|
96
|
+
|
|
97
|
+
-----
|
|
98
|
+
|
|
99
|
+
<a id="model-experience"></a>
|
|
29
100
|
## Model Experience
|
|
30
101
|
|
|
31
102
|
### Referenced session background
|
|
@@ -44,7 +115,23 @@ The request and snapshot are consecutive append-only target messages and preserv
|
|
|
44
115
|
|
|
45
116
|
## Known Limitations and Deferred Work
|
|
46
117
|
|
|
47
|
-
|
|
118
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
These limits define when cross-session references are a poor fit. They are current package constraints.
|
|
122
|
+
|
|
123
|
+
- **No body discovery** — candidate queries inspect titles but do not search message bodies.
|
|
124
|
+
- **Labels come from projections alone** — an attached session is labeled from its live projection cut, a cold one from its durable checkpoint, and a session neither answers for is labeled by its id and cannot be found by its title. Discovery never reads a log: folding one title costs a whole log, and this runs under every completion keystroke. A session persisted before the projection cache was composed regains its title the first time it is opened, which checkpoints it.
|
|
48
125
|
- **Trusted caller boundary** — the service assumes its host is authorized to read every session exposed by `ctx.sessionQuery`; it is not a model-facing search tool.
|
|
49
126
|
- **Text projection only** — non-text user and assistant blocks are not propagated across sessions.
|
|
50
127
|
- **No live link** — references are snapshots, not forks, resumes, subscriptions, or source-session mutations.
|
|
128
|
+
|
|
129
|
+
<a id="dev-note"></a>
|
|
130
|
+
### Dev Note
|
|
131
|
+
|
|
132
|
+
<details>
|
|
133
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
134
|
+
|
|
135
|
+
None.
|
|
136
|
+
|
|
137
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,31 +1,102 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "跨会话快照引用与持久的不受信任模型上下文,供启用或排查 ctx.sessionReferenceResolver 的用户与维护者阅读。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-session-reference
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-session-reference` 让一次对话可以引用其他会话:宿主把 `@label` mention 转换为规范 URI,服务则为模型准备每个被引用会话的有界、只读快照,作为持久、不受信任的背景上下文。候选发现按工作目录亲和度对其他会话排序,并用其最新标题作标签。快照在捕获后不可变,并带有固定警告,禁止遵循其中的指令、权限声明或工具请求。它是面向支持跨会话 mention 的宿主的可选服务;它消费 `ctx.sessionQuery`,不需要 SQLite FTS。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当宿主应允许用户提及另一个会话并把其上下文交给模型时,启用此服务。由于它消费后端无关的 compact 检查点标记,任何 session-query 后端都可配合使用。
|
|
29
|
+
|
|
30
|
+
### mention 语法
|
|
31
|
+
|
|
32
|
+
规范 mention 是 Markdown 形式的 `@[label](dsh-session:<base64url 编码的 id>)`,或裸 `dsh-session:` URI;每个 JavaScript 字符串会话 id 都能精确往返。服务会把 mention 改写为消息中可读的 `@label` 文本,并返回结构化引用。显式 Markdown mention 会拒绝格式错误的 URI;空或只含标点符号的 scheme mention 仍是普通讨论文本。
|
|
33
|
+
|
|
34
|
+
### 模型能得到什么
|
|
35
|
+
|
|
36
|
+
引用其他会话的消息会紧随其后收到一条 `## Referenced sessions` 快照,作为第二条 user 角色消息。快照是不受信任的背景:固定警告告诉模型,除非当前用户明确重复,否则不得遵循其中的指令、权限声明或工具请求。每个来源都独立有界——每条消息至多 `maxReferences` 个不同会话、每个来源至多 `maxReferenceBytes` 字节——无法塞入预算的来源会直接使准备失败,而不是返回部分上下文。
|
|
37
|
+
|
|
38
|
+
### 查找可引用的会话
|
|
39
|
+
|
|
40
|
+
`listCandidates(agent, query?, limit?)` 列出除 agent 自身外的会话,按 id、工作目录或投影标题做不区分大小写的过滤,并把同目录会话排在前面。每个候选以其最新标题作为 mention 标签;标题缺失或不可读时回退到会话 id,并报告其工作目录是否就是发起方 agent 的工作目录,宿主因此可以只在位置能区分该行时才显示它。浏览器消费方通过 `ctx.remote.sessionReferenceResolver.candidates` 调用同一发现能力,该方法会为每个候选附上规范 mention。
|
|
41
|
+
|
|
42
|
+
### 配置
|
|
43
|
+
|
|
44
|
+
| 字段 | 默认值 | 含义 |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `maxReferences` | `3` | 一条已准备消息中不同源会话的最大数量;不得超过 `3` |
|
|
47
|
+
| `candidateLimit` | `50` | 返回给宿主的默认候选数量 |
|
|
48
|
+
| `maxReferenceBytes` | `65536` | 一个引用对象的最大序列化 JSON 字节数 |
|
|
49
|
+
|
|
50
|
+
生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-session-reference)是每个受支持字段及其 JSDoc 的穷尽式真源。
|
|
6
51
|
|
|
7
|
-
|
|
52
|
+
-----
|
|
8
53
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- `encodeSessionReferenceUri()` 与 `decodeSessionReferenceUri()` 实现 `dsh-session:<base64url(JSON.stringify(sessionId))>`,因此每个 JavaScript 字符串 id 都能精确往返。`formatSessionReferenceMention()` 发出 `@[label](uri)`,`parseSessionReferenceText()` 将 Markdown mention 或裸规范 URI 替换为可读的 `@label` 文本,并返回结构化引用。解析器会拒绝显式 Markdown mention 中任何格式错误的 URI;只当 scheme 后跟非空、符合 base64url 形状的 payload 时,裸文本才被视为引用,匹配但非规范的候选项仍会失败。空 scheme mention 或只含标点符号的 scheme mention 仍是普通讨论文本。
|
|
54
|
+
<a id="understand-the-implementation"></a>
|
|
55
|
+
## 理解实现
|
|
12
56
|
|
|
13
|
-
|
|
57
|
+
<details>
|
|
58
|
+
<summary>实现细节——点击展开</summary>
|
|
14
59
|
|
|
15
|
-
|
|
60
|
+
本节解释服务的设计;可观察行为见[使用本包](#use-this-package)。
|
|
16
61
|
|
|
17
|
-
|
|
62
|
+
### 设计理念
|
|
18
63
|
|
|
19
|
-
|
|
64
|
+
准备阶段在目标消息到达 `agent/pre-step` 时,对每个被引用会话的当前表层各精确读取一次,因此 queued 消息在进入模型步骤时捕获源状态,此后生成的上下文不可变。投影只保留用户直接发出的 `user/message`、assistant 文本,以及携带规范压缩标记的 `user/message` 检查点;带独立来源的 session-reference 消息会被排除,防止快照递归传播。源文本以 JSON 序列化,每个 `<` 都转义为 `\u003c`,因此无法拼出 `<referenced-sessions>` 定界标签。
|
|
20
65
|
|
|
21
|
-
|
|
22
|
-
|---|---:|---|
|
|
23
|
-
| `maxReferences` | `3` | 一条已准备消息中不同源会话的最大数量;必须不大于 `3`。 |
|
|
24
|
-
| `candidateLimit` | `50` | 返回给宿主的默认候选数量。 |
|
|
25
|
-
| `maxReferenceBytes` | `65536` | 一个引用对象的最大序列化 JSON 字节数。 |
|
|
66
|
+
### 源码地图
|
|
26
67
|
|
|
27
|
-
|
|
68
|
+
| 文件 | 职责 |
|
|
69
|
+
|---|---|
|
|
70
|
+
| [`src/index.ts`](src/index.ts) | `SessionReferenceResolver`:pre-step 监听器、候选发现、准备 |
|
|
71
|
+
| [`src/config.ts`](src/config.ts) | `Config` schema、`SessionReferenceError` 错误分类 |
|
|
72
|
+
| [`src/uri.ts`](src/uri.ts) | `dsh-session:` URI 编解码、mention 格式化与解析 |
|
|
73
|
+
| [`src/projection.ts`](src/projection.ts) | 当前表层投影与字节预算保留 |
|
|
74
|
+
| [`src/serialization.ts`](src/serialization.ts) | 快照载荷的标签安全 JSON 转义 |
|
|
75
|
+
| [`src/types.ts`](src/types.ts) | `SessionReferenceInput`/`Candidate` 与来源类型 |
|
|
76
|
+
| [`src/invariant.ts`](src/invariant.ts) | 引用约定的不变式伴生插件 |
|
|
28
77
|
|
|
78
|
+
### 主要流程
|
|
79
|
+
|
|
80
|
+
外层 `agent/pre-step` 监听器接受步骤,从直接用户消息中解析规范 mention,再调用 `prepare`:规范化引用(保持首次 mention 顺序、去重、拒绝自引用与超限数量),并行读取每个表层,在 `maxReferenceBytes` 下逐源保留,并渲染聚合提示词。每份快照都插入到引用它的消息紧后,目标日志先记录可读的直接消息、再记录其带来源上下文,因此捕获后的源变更无法改变目标回放。
|
|
81
|
+
|
|
82
|
+
</details>
|
|
83
|
+
|
|
84
|
+
-----
|
|
85
|
+
|
|
86
|
+
<a id="further-exploration"></a>
|
|
87
|
+
## 进一步探索
|
|
88
|
+
|
|
89
|
+
包级约定不够用时阅读以下页面。它们从共享引用表面进入设计决策与其背后的读取服务。
|
|
90
|
+
|
|
91
|
+
- [会话引用子系统](../../../docs/subsystems/session-reference.zh.md)——规范 URI、投影规则与稳定的错误分类。
|
|
92
|
+
- [跨会话引用决策记录](../../../.agents/notes/implemented/feature/2026-07-21-cross-session-references.zh.md)——引用约定的设计理由。
|
|
93
|
+
- [会话查询子系统](../../../docs/subsystems/session-query.zh.md)——提供会话表层的读取服务。
|
|
94
|
+
- [context 组地图](../README.zh.md)——相邻的请求上下文包。
|
|
95
|
+
- [生成的配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-session-reference)——每个受支持配置字段及其源声明。
|
|
96
|
+
|
|
97
|
+
-----
|
|
98
|
+
|
|
99
|
+
<a id="model-experience"></a>
|
|
29
100
|
## 模型体验
|
|
30
101
|
|
|
31
102
|
### 引用会话背景
|
|
@@ -42,9 +113,25 @@
|
|
|
42
113
|
|
|
43
114
|
请求与快照是两条连续、仅追加的目标消息,并保留较早的可缓存历史。不同引用或源捕获内容只改变新后缀;后续目标压缩可能使从替换边界起的复用失效。
|
|
44
115
|
|
|
45
|
-
##
|
|
116
|
+
## 已知限制与延期工作
|
|
46
117
|
|
|
47
|
-
|
|
118
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
这些限制说明跨会话引用何时不合适。它们是当前包约束。
|
|
122
|
+
|
|
123
|
+
- **不支持消息正文检索**:候选查询会检查标题,但不搜索消息主体。
|
|
124
|
+
- **标签只来自投影**:已挂载的会话由实时投影切面标注,冷会话由持久化 checkpoint 标注,两者都答不上来的会话用 id 作标签且无法按标题搜到。发现路径绝不读日志:折叠一个标题的代价是整份日志,而这段代码位于补全的每一次击键之下。早于投影缓存组合存在的会话,只要被打开一次(销毁时即写 checkpoint)就会恢复标题。
|
|
48
125
|
- **受信任调用方边界**:该服务假设宿主有权读取 `ctx.sessionQuery` 公开的每个会话;它不是面向模型的搜索工具。
|
|
49
126
|
- **只投影文本**:不会在会话间传播非文本 user 与 assistant 块。
|
|
50
127
|
- **没有实时链接**:引用是快照,不是 fork、恢复、订阅或源会话变更。
|
|
128
|
+
|
|
129
|
+
<a id="dev-note"></a>
|
|
130
|
+
### 开发备注
|
|
131
|
+
|
|
132
|
+
<details>
|
|
133
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
134
|
+
|
|
135
|
+
无。
|
|
136
|
+
|
|
137
|
+
</details>
|
package/lib/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
2
|
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
3
|
-
import {
|
|
3
|
+
import { createUserMessage, freezeMessage } from "@deepseek-ai/dsh-llm";
|
|
4
4
|
import { isCompactCheckpointSource } from "@deepseek-ai/dsh-compaction";
|
|
5
5
|
import { TextRetainer } from "@deepseek-ai/dsh-output-retention";
|
|
6
|
-
import {
|
|
6
|
+
import { assertNever } from "@deepseek-ai/dsh-util-values";
|
|
7
|
+
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
7
8
|
//#region lib/types/config.js
|
|
8
9
|
/** Configuration and stable diagnostics for session references. */
|
|
9
10
|
/** Hard maximum references accepted by one message. */
|
|
@@ -207,7 +208,7 @@ function decodeSessionReferenceUri(uri) {
|
|
|
207
208
|
try {
|
|
208
209
|
const parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
209
210
|
if (typeof parsed !== "string") throw new TypeError("decoded session id is not a string");
|
|
210
|
-
const sessionId =
|
|
211
|
+
const sessionId = brandString(parsed);
|
|
211
212
|
if (encodeSessionReferenceUri(sessionId) !== uri) throw new TypeError("URI is not canonical");
|
|
212
213
|
return sessionId;
|
|
213
214
|
} catch (error) {
|
|
@@ -360,7 +361,7 @@ let SessionReferenceResolver = (() => {
|
|
|
360
361
|
const decision = await next();
|
|
361
362
|
if (decision.kind === "reject") return decision;
|
|
362
363
|
return {
|
|
363
|
-
|
|
364
|
+
...decision,
|
|
364
365
|
messages: await this.prepareDirectMessages(agent, decision.messages, signal)
|
|
365
366
|
};
|
|
366
367
|
}, { prepend: true });
|
|
@@ -399,6 +400,10 @@ let SessionReferenceResolver = (() => {
|
|
|
399
400
|
}
|
|
400
401
|
/**
|
|
401
402
|
* List reference candidates, ranked by working-directory affinity.
|
|
403
|
+
*
|
|
404
|
+
* Discovery runs at keystroke rate, so a title only ever comes from a
|
|
405
|
+
* projection read: see {@link SessionReferenceResolver.projectedTitle} for
|
|
406
|
+
* which sessions can answer one and which fall back to their id.
|
|
402
407
|
* @param agent - target agent; self is excluded and its cwd drives ranking.
|
|
403
408
|
* @param query - optional case-insensitive session-id/cwd/title substring.
|
|
404
409
|
* @param limit - optional positive result cap.
|
|
@@ -410,30 +415,53 @@ let SessionReferenceResolver = (() => {
|
|
|
410
415
|
const needle = query.toLocaleLowerCase();
|
|
411
416
|
const targetCwd = agent.session.header.cwd;
|
|
412
417
|
assertNotCancelled(signal);
|
|
413
|
-
|
|
418
|
+
return (await settleWithCancellation(this.ctx.sessionQuery.listSessions(signal), signal)).filter((record) => record.header.id !== agent.id).map((record, index) => ({
|
|
414
419
|
record,
|
|
415
420
|
index
|
|
416
|
-
}))
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return {
|
|
422
|
-
record,
|
|
423
|
-
index,
|
|
424
|
-
label: observation.status === "fulfilled" ? observation.value.title?.title ?? record.header.id : record.header.id
|
|
425
|
-
};
|
|
426
|
-
}).filter(({ record, label }) => {
|
|
421
|
+
})).map(({ record, index }) => ({
|
|
422
|
+
record,
|
|
423
|
+
index,
|
|
424
|
+
label: this.projectedTitle(record) ?? record.header.id
|
|
425
|
+
})).filter(({ record, label }) => {
|
|
427
426
|
if (needle === "") return true;
|
|
428
427
|
return record.header.id.toLocaleLowerCase().includes(needle) || record.header.cwd?.toLocaleLowerCase().includes(needle) === true || label.toLocaleLowerCase().includes(needle);
|
|
429
428
|
}).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 }) => ({
|
|
430
429
|
sessionId: record.header.id,
|
|
431
430
|
label,
|
|
432
431
|
...record.header.cwd === void 0 ? {} : { cwd: record.header.cwd },
|
|
432
|
+
sameWorkspace: record.header.cwd !== void 0 && record.header.cwd === targetCwd,
|
|
433
433
|
createdAt: record.header.createdAt
|
|
434
434
|
}));
|
|
435
435
|
}
|
|
436
436
|
/**
|
|
437
|
+
* The title a session's projections can answer without reading its log.
|
|
438
|
+
*
|
|
439
|
+
* Attachment is decided by the store at read time, not by the listing:
|
|
440
|
+
* a session that attached in between would otherwise be answered from a
|
|
441
|
+
* checkpoint its live log has already moved past.
|
|
442
|
+
*
|
|
443
|
+
* An attached session answers from its live registry cut, which advances
|
|
444
|
+
* with every committed event, so a rename or a just-generated title is
|
|
445
|
+
* visible immediately; its events are already in memory, so the lazy fold
|
|
446
|
+
* costs no I/O. A cold session answers from the durable checkpoint the
|
|
447
|
+
* projection cache wrote when it went cold.
|
|
448
|
+
*
|
|
449
|
+
* Nothing else is attempted. Folding a title from a log costs the whole
|
|
450
|
+
* log, and this call sits under every keystroke of `@` completion. A
|
|
451
|
+
* session that no projection can answer for — one persisted before the
|
|
452
|
+
* cache was composed, or seeded straight to disk — is labeled by its id
|
|
453
|
+
* and cannot be found by its title until it is opened once, which
|
|
454
|
+
* checkpoints it.
|
|
455
|
+
* @param record - the listed session, live or cold.
|
|
456
|
+
* @returns the projected title, or undefined when no projection holds one.
|
|
457
|
+
*/
|
|
458
|
+
projectedTitle(record) {
|
|
459
|
+
const attached = this.ctx.get("sessions")?.get(record.header.id);
|
|
460
|
+
const projections = this.ctx.get("sessionProjections");
|
|
461
|
+
if (attached !== void 0 && projections !== void 0) return titleOf(projections.snapshot(attached, ["title"]));
|
|
462
|
+
return titleOf(this.ctx.get("sessionProjectionCache")?.cachedSnapshot(record.header, ["title"]));
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
437
465
|
* Remote face of {@link listCandidates}: the configured candidate limit
|
|
438
466
|
* applies, and every candidate carries the canonical mention a host inserts
|
|
439
467
|
* into the prompt draft.
|
|
@@ -531,6 +559,11 @@ function normalizeReferences(targetId, references, maxReferences) {
|
|
|
531
559
|
function renderPrompt(data) {
|
|
532
560
|
return `${PROMPT_PREFIX}${stringifyTagSafeJson(data)}${PROMPT_SUFFIX}`;
|
|
533
561
|
}
|
|
562
|
+
/** The title in one projection snapshot; undefined when the unit is absent or still untitled. */
|
|
563
|
+
function titleOf(snapshot) {
|
|
564
|
+
const title = snapshot?.values.title;
|
|
565
|
+
return title === void 0 || title === null ? void 0 : title;
|
|
566
|
+
}
|
|
534
567
|
function candidateRank(candidateCwd, targetCwd) {
|
|
535
568
|
if (candidateCwd !== void 0 && targetCwd !== void 0 && candidateCwd === targetCwd) return 0;
|
|
536
569
|
if (candidateCwd === void 0) return 1;
|
package/lib/typert.host.js
CHANGED
|
@@ -8,6 +8,7 @@ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_res
|
|
|
8
8
|
'sessionId': z.intersection(z.string(), z.unknown()),
|
|
9
9
|
'label': z.string(),
|
|
10
10
|
'cwd': z.string().optional(),
|
|
11
|
+
'sameWorkspace': z.boolean(),
|
|
11
12
|
'createdAt': z.number(),
|
|
12
13
|
}))
|
|
13
14
|
|
|
@@ -57,7 +58,7 @@ export const TYPERT = {
|
|
|
57
58
|
typeSymbol: '@deepseek-ai/dsh-session-reference#sessionReferenceResolver/candidates:result',
|
|
58
59
|
schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema,
|
|
59
60
|
},
|
|
60
|
-
sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":
|
|
61
|
+
sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":245,"column":9},
|
|
61
62
|
},
|
|
62
63
|
],
|
|
63
64
|
model: {
|
|
@@ -75,7 +76,7 @@ export const TYPERT = {
|
|
|
75
76
|
"name": "listCandidates",
|
|
76
77
|
"signature": "async listCandidates( agent: Agent, query: string = '', limit: number = this.config.candidateLimit, signal?: AbortSignal, ): Promise<SessionReferenceCandidate[]>",
|
|
77
78
|
"summary": "List reference candidates, ranked by working-directory affinity.",
|
|
78
|
-
"jsDoc": "/**\n * List reference candidates, ranked by working-directory affinity.\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 */"
|
|
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 */"
|
|
79
80
|
},
|
|
80
81
|
{
|
|
81
82
|
"kind": "method",
|
|
@@ -103,7 +104,7 @@ export const TYPERT = {
|
|
|
103
104
|
},
|
|
104
105
|
{
|
|
105
106
|
"name": "AgentOptions",
|
|
106
|
-
"declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n maxTokens?: number;\n}"
|
|
107
|
+
"declaration": "export interface AgentOptions {\n provider?: string;\n model?: string;\n reasoningEffort?: ReasoningEffortId;\n maxTokens?: number;\n subagentDepth?: number;\n}"
|
|
107
108
|
},
|
|
108
109
|
{
|
|
109
110
|
"name": "AgentStatus",
|
|
@@ -137,22 +138,10 @@ export const TYPERT = {
|
|
|
137
138
|
"name": "Branded",
|
|
138
139
|
"declaration": "export type Branded<B extends string> = string & { readonly [BRAND]: B; };"
|
|
139
140
|
},
|
|
140
|
-
{
|
|
141
|
-
"name": "CallId",
|
|
142
|
-
"declaration": "export type CallId = Branded<'CallId'>;"
|
|
143
|
-
},
|
|
144
141
|
{
|
|
145
142
|
"name": "CancelOptions",
|
|
146
143
|
"declaration": "export interface CancelOptions {\n keepInbox?: boolean | undefined;\n}"
|
|
147
144
|
},
|
|
148
|
-
{
|
|
149
|
-
"name": "CodeDispatchEventData",
|
|
150
|
-
"declaration": "export interface CodeDispatchEventData extends CodeDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}"
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
"name": "CodeDispatchStartEventData",
|
|
154
|
-
"declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}"
|
|
155
|
-
},
|
|
156
145
|
{
|
|
157
146
|
"name": "CommandId",
|
|
158
147
|
"declaration": "export type CommandId = Branded<'CommandId'>;"
|
|
@@ -189,6 +178,14 @@ export const TYPERT = {
|
|
|
189
178
|
"name": "ContextSnapshotSection",
|
|
190
179
|
"declaration": "export interface ContextSnapshotSection {\n readonly name: string;\n readonly text: string;\n}"
|
|
191
180
|
},
|
|
181
|
+
{
|
|
182
|
+
"name": "ContinuableSubagentDescriptorData",
|
|
183
|
+
"declaration": "export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase {\n readonly mode: 'continuable';\n readonly label: string;\n readonly agentProvider?: string;\n readonly agentModel?: string;\n readonly agentReasoningEffort?: ReasoningEffortId;\n readonly persona?: string;\n readonly toolFilter?: ToolRestriction;\n}"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"name": "CoordinatorMessageSource",
|
|
187
|
+
"declaration": "export interface CoordinatorMessageSource {\n readonly kind: 'coordinator';\n readonly form: 'relay';\n readonly senderSessionId: SessionId;\n}"
|
|
188
|
+
},
|
|
192
189
|
{
|
|
193
190
|
"name": "EpochHeader",
|
|
194
191
|
"declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n system?: string;\n tools?: ToolSchema[];\n}"
|
|
@@ -291,12 +288,20 @@ export const TYPERT = {
|
|
|
291
288
|
},
|
|
292
289
|
{
|
|
293
290
|
"name": "MessageSourceMap",
|
|
294
|
-
"declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n goal: GoalMessageSource;\n 'session-reference': SessionReferenceSource;\n}"
|
|
291
|
+
"declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n coordinator: CoordinatorMessageSource;\n 'subagent-report': SubagentReportMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'team-message': TeamMessageSource;\n goal: GoalMessageSource;\n 'session-reference': SessionReferenceSource;\n}"
|
|
295
292
|
},
|
|
296
293
|
{
|
|
297
294
|
"name": "ModelMessageSource",
|
|
298
295
|
"declaration": "export interface ModelMessageSource extends AssistantProvenance {\n kind: 'model';\n}"
|
|
299
296
|
},
|
|
297
|
+
{
|
|
298
|
+
"name": "ModelSelection",
|
|
299
|
+
"declaration": "export interface ModelSelection {\n readonly provider: string;\n readonly model: string;\n readonly reasoningEffort?: string;\n}"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"name": "OneShotSubagentDescriptorData",
|
|
303
|
+
"declaration": "export interface OneShotSubagentDescriptorData extends SubagentDescriptorBase {\n readonly mode: 'one-shot';\n readonly label?: string;\n}"
|
|
304
|
+
},
|
|
300
305
|
{
|
|
301
306
|
"name": "PreparedReferencedMessage",
|
|
302
307
|
"declaration": "export interface PreparedReferencedMessage {\n content: ContentBlock[];\n additionalContext?: UserMessage;\n}"
|
|
@@ -305,6 +310,14 @@ export const TYPERT = {
|
|
|
305
310
|
"name": "ProviderRequestId",
|
|
306
311
|
"declaration": "export type ProviderRequestId = Branded<'ProviderRequestId'>;"
|
|
307
312
|
},
|
|
313
|
+
{
|
|
314
|
+
"name": "PtcDispatchEventData",
|
|
315
|
+
"declaration": "export interface PtcDispatchEventData extends PtcDispatchStartEventData {\n isError: boolean;\n content: ContentBlock[];\n}"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"name": "PtcDispatchStartEventData",
|
|
319
|
+
"declaration": "export interface PtcDispatchStartEventData {\n rootCallId: ToolCallId;\n parentCallId: ToolCallId;\n subCallId: ToolCallId;\n name: string;\n arguments: unknown;\n}"
|
|
320
|
+
},
|
|
308
321
|
{
|
|
309
322
|
"name": "ReasoningBlock",
|
|
310
323
|
"declaration": "export interface ReasoningBlock {\n type: 'reasoning';\n text: string;\n}"
|
|
@@ -323,7 +336,11 @@ export const TYPERT = {
|
|
|
323
336
|
},
|
|
324
337
|
{
|
|
325
338
|
"name": "RequestHeaderReason",
|
|
326
|
-
"declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change';"
|
|
339
|
+
"declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change' | 'series';"
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
"name": "SandboxMode",
|
|
343
|
+
"declaration": "export type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';"
|
|
327
344
|
},
|
|
328
345
|
{
|
|
329
346
|
"name": "Session",
|
|
@@ -335,7 +352,7 @@ export const TYPERT = {
|
|
|
335
352
|
},
|
|
336
353
|
{
|
|
337
354
|
"name": "SessionEventMap",
|
|
338
|
-
"declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true; };\n 'tool/call': { turn: number; step: number; callId:
|
|
355
|
+
"declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': Record<string, never>;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': PtcDispatchStartEventData;\n 'tool/code-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'subagent/descriptor': SubagentDescriptorData;\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: number; };\n 'team/member': { version: 1; teamId: TeamId; member: TeamMemberSnapshot; };\n 'team/task': { version: 1; teamId: TeamId; task: TeamTaskSnapshot; };\n 'team/message/queued': { version: 1; teamId: TeamId; message: TeamMessageSnapshot; };\n 'team/message/delivered': { version: 1; teamId: TeamId; messageId: TeamMessageId; targetId: SessionId; };\n 'goal/change': GoalChangeMeta;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: number; end: number; }; shadowedSeqs: number[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: number; end: number; }; shadowedSeqs: number[]; shadowedTokenCount: number; };\n}"
|
|
339
356
|
},
|
|
340
357
|
{
|
|
341
358
|
"name": "SessionEventType",
|
|
@@ -351,7 +368,7 @@ export const TYPERT = {
|
|
|
351
368
|
},
|
|
352
369
|
{
|
|
353
370
|
"name": "SessionReferenceCandidate",
|
|
354
|
-
"declaration": "export interface SessionReferenceCandidate {\n sessionId: SessionId;\n label: string;\n cwd?: string;\n createdAt: number;\n}"
|
|
371
|
+
"declaration": "export interface SessionReferenceCandidate {\n sessionId: SessionId;\n label: string;\n cwd?: string;\n sameWorkspace: boolean;\n createdAt: number;\n}"
|
|
355
372
|
},
|
|
356
373
|
{
|
|
357
374
|
"name": "SessionReferenceInput",
|
|
@@ -365,6 +382,10 @@ export const TYPERT = {
|
|
|
365
382
|
"name": "SessionReferenceSource",
|
|
366
383
|
"declaration": "export interface SessionReferenceSource {\n kind: 'session-reference';\n form: 'recall';\n version: 1;\n references: { sessionId: string; label: string; capturedThroughSeq: number | null; compacted: boolean; originalMessages: number; retainedMessages: number; omittedMessages: number; omittedBytes: number; truncated: boolean; inputIndex: number; }[];\n}"
|
|
367
384
|
},
|
|
385
|
+
{
|
|
386
|
+
"name": "SessionRequestId",
|
|
387
|
+
"declaration": "export type SessionRequestId = Branded<'session-request-id'>;"
|
|
388
|
+
},
|
|
368
389
|
{
|
|
369
390
|
"name": "SessionSurface",
|
|
370
391
|
"declaration": "export interface SessionSurface {\n readonly nodes: readonly number[];\n readonly replaceGeneration: number;\n}"
|
|
@@ -385,9 +406,29 @@ export const TYPERT = {
|
|
|
385
406
|
"name": "SessionTitleSource",
|
|
386
407
|
"declaration": "export type SessionTitleSource = { readonly kind: 'fallback'; } | { readonly kind: 'provider'; readonly provider: SessionTitleProviderId; readonly model?: SessionTitleModelProvenance; } | { readonly kind: 'user'; };"
|
|
387
408
|
},
|
|
409
|
+
{
|
|
410
|
+
"name": "SkillInvocationSource",
|
|
411
|
+
"declaration": "export interface SkillInvocationSource {\n readonly kind: 'skill-invocation';\n readonly name: string;\n readonly form: 'instructions';\n}"
|
|
412
|
+
},
|
|
388
413
|
{
|
|
389
414
|
"name": "StreamChunk",
|
|
390
|
-
"declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id:
|
|
415
|
+
"declaration": "export type StreamChunk = { type: 'block-start'; index: number; blockType: ContentBlockType; } | { type: 'text-delta'; index: number; text: string; } | { type: 'reasoning-delta'; index: number; text: string; } | { type: 'tool-call-delta'; index: number; id: ToolCallId; name?: string; argumentsDelta: string; } | { type: 'block-end'; index: number; block: ContentBlock; } | { type: 'usage'; usage: TokenUsage; } | { type: 'finish'; reason: FinishReason; replayState?: ReplayEnvelope; };"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"name": "SubagentDescriptorBase",
|
|
419
|
+
"declaration": "export interface SubagentDescriptorBase {\n readonly version: number;\n readonly mode: 'one-shot' | 'continuable';\n readonly provider: string;\n}"
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"name": "SubagentDescriptorData",
|
|
423
|
+
"declaration": "export type SubagentDescriptorData = OneShotSubagentDescriptorData | ContinuableSubagentDescriptorData;"
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"name": "SubagentReportMessageSource",
|
|
427
|
+
"declaration": "export interface SubagentReportMessageSource {\n readonly kind: 'subagent-report';\n readonly form: 'relay';\n readonly senderSessionId: SessionId;\n}"
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"name": "SubagentSettledMessageSource",
|
|
431
|
+
"declaration": "export interface SubagentSettledMessageSource {\n readonly kind: 'subagent-settled';\n readonly form: 'notice';\n readonly summary: string;\n readonly senderSessionId: SessionId;\n}"
|
|
391
432
|
},
|
|
392
433
|
{
|
|
393
434
|
"name": "SurfaceEventType",
|
|
@@ -401,6 +442,42 @@ export const TYPERT = {
|
|
|
401
442
|
"name": "SurfaceOp",
|
|
402
443
|
"declaration": "export type SurfaceOp = 'append' | { op: 'replace'; start: number; end: number; };"
|
|
403
444
|
},
|
|
445
|
+
{
|
|
446
|
+
"name": "TeamId",
|
|
447
|
+
"declaration": "export type TeamId = Branded<'TeamId'>;"
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"name": "TeamMemberPhase",
|
|
451
|
+
"declaration": "export type TeamMemberPhase = 'provisioning' | 'active' | 'failed';"
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"name": "TeamMemberSnapshot",
|
|
455
|
+
"declaration": "export interface TeamMemberSnapshot {\n readonly id: SessionId;\n readonly name: string;\n readonly description: string;\n readonly provider: string;\n readonly context: 'fresh' | 'fork';\n readonly phase: TeamMemberPhase;\n readonly error?: string;\n}"
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"name": "TeamMessageId",
|
|
459
|
+
"declaration": "export type TeamMessageId = Branded<'TeamMessageId'>;"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
"name": "TeamMessageSnapshot",
|
|
463
|
+
"declaration": "export interface TeamMessageSnapshot {\n readonly id: TeamMessageId;\n readonly senderId: SessionId;\n readonly senderName: string;\n readonly targetId: SessionId;\n readonly delivery: 'quiet' | 'wakeup';\n readonly content: ContentBlock[];\n}"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"name": "TeamMessageSource",
|
|
467
|
+
"declaration": "export interface TeamMessageSource {\n readonly kind: 'team-message';\n readonly teamId: TeamId;\n readonly messageId: TeamMessageId;\n readonly senderId: SessionId;\n readonly senderName: string;\n}"
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"name": "TeamTaskId",
|
|
471
|
+
"declaration": "export type TeamTaskId = Branded<'TeamTaskId'>;"
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"name": "TeamTaskSnapshot",
|
|
475
|
+
"declaration": "export interface TeamTaskSnapshot {\n readonly id: TeamTaskId;\n readonly revision: number;\n readonly subject: string;\n readonly description: string;\n readonly status: TeamTaskStatus;\n readonly ownerId?: SessionId;\n readonly blockedBy: TeamTaskId[];\n readonly writeScopes: string[];\n}"
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"name": "TeamTaskStatus",
|
|
479
|
+
"declaration": "export type TeamTaskStatus = 'pending' | 'in_progress' | 'completed' | 'deleted';"
|
|
480
|
+
},
|
|
404
481
|
{
|
|
405
482
|
"name": "TextBlock",
|
|
406
483
|
"declaration": "export interface TextBlock {\n type: 'text';\n text: string;\n}"
|
|
@@ -411,19 +488,27 @@ export const TYPERT = {
|
|
|
411
488
|
},
|
|
412
489
|
{
|
|
413
490
|
"name": "TokenUsage",
|
|
414
|
-
"declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}"
|
|
491
|
+
"declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}"
|
|
415
492
|
},
|
|
416
493
|
{
|
|
417
494
|
"name": "ToolCallBlock",
|
|
418
|
-
"declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id:
|
|
495
|
+
"declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: ToolCallId;\n name: string;\n arguments: string;\n}"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"name": "ToolCallId",
|
|
499
|
+
"declaration": "export type ToolCallId = Branded<'ToolCallId'>;"
|
|
419
500
|
},
|
|
420
501
|
{
|
|
421
502
|
"name": "ToolMessageSource",
|
|
422
|
-
"declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId:
|
|
503
|
+
"declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: ToolCallId;\n}"
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
"name": "ToolRestriction",
|
|
507
|
+
"declaration": "export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n}"
|
|
423
508
|
},
|
|
424
509
|
{
|
|
425
510
|
"name": "ToolResultBlock",
|
|
426
|
-
"declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId:
|
|
511
|
+
"declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: ToolCallId;\n content: ContentBlock[];\n isError?: boolean;\n}"
|
|
427
512
|
},
|
|
428
513
|
{
|
|
429
514
|
"name": "ToolResultMessage",
|
|
@@ -8,6 +8,7 @@ const _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_res
|
|
|
8
8
|
'sessionId': z.intersection(z.string(), z.unknown()),
|
|
9
9
|
'label': z.string(),
|
|
10
10
|
'cwd': z.string().optional(),
|
|
11
|
+
'sameWorkspace': z.boolean(),
|
|
11
12
|
'createdAt': z.number(),
|
|
12
13
|
}))
|
|
13
14
|
|
|
@@ -54,7 +55,7 @@ export const TYPERT_REMOTE = {
|
|
|
54
55
|
typeSymbol: '@deepseek-ai/dsh-session-reference#sessionReferenceResolver/candidates:result',
|
|
55
56
|
schema: _deepseek_ai_dsh_session_reference_sessionReferenceResolver_candidates_result$schema,
|
|
56
57
|
},
|
|
57
|
-
sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":
|
|
58
|
+
sourceLocation: {"file":"packages/context/session-reference/src/index.ts","line":245,"column":9},
|
|
58
59
|
},
|
|
59
60
|
],
|
|
60
61
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ export declare class SessionReferenceResolver extends TypertRemoteService {
|
|
|
37
37
|
private prepareDirectMessages;
|
|
38
38
|
/**
|
|
39
39
|
* List reference candidates, ranked by working-directory affinity.
|
|
40
|
+
*
|
|
41
|
+
* Discovery runs at keystroke rate, so a title only ever comes from a
|
|
42
|
+
* projection read: see {@link SessionReferenceResolver.projectedTitle} for
|
|
43
|
+
* which sessions can answer one and which fall back to their id.
|
|
40
44
|
* @param agent - target agent; self is excluded and its cwd drives ranking.
|
|
41
45
|
* @param query - optional case-insensitive session-id/cwd/title substring.
|
|
42
46
|
* @param limit - optional positive result cap.
|
|
@@ -44,6 +48,29 @@ export declare class SessionReferenceResolver extends TypertRemoteService {
|
|
|
44
48
|
* @returns candidates labeled by latest title or, when absent, session id.
|
|
45
49
|
*/
|
|
46
50
|
listCandidates(agent: Agent, query?: string, limit?: number, signal?: AbortSignal): Promise<SessionReferenceCandidate[]>;
|
|
51
|
+
/**
|
|
52
|
+
* The title a session's projections can answer without reading its log.
|
|
53
|
+
*
|
|
54
|
+
* Attachment is decided by the store at read time, not by the listing:
|
|
55
|
+
* a session that attached in between would otherwise be answered from a
|
|
56
|
+
* checkpoint its live log has already moved past.
|
|
57
|
+
*
|
|
58
|
+
* An attached session answers from its live registry cut, which advances
|
|
59
|
+
* with every committed event, so a rename or a just-generated title is
|
|
60
|
+
* visible immediately; its events are already in memory, so the lazy fold
|
|
61
|
+
* costs no I/O. A cold session answers from the durable checkpoint the
|
|
62
|
+
* projection cache wrote when it went cold.
|
|
63
|
+
*
|
|
64
|
+
* Nothing else is attempted. Folding a title from a log costs the whole
|
|
65
|
+
* log, and this call sits under every keystroke of `@` completion. A
|
|
66
|
+
* session that no projection can answer for — one persisted before the
|
|
67
|
+
* cache was composed, or seeded straight to disk — is labeled by its id
|
|
68
|
+
* and cannot be found by its title until it is opened once, which
|
|
69
|
+
* checkpoints it.
|
|
70
|
+
* @param record - the listed session, live or cold.
|
|
71
|
+
* @returns the projected title, or undefined when no projection holds one.
|
|
72
|
+
*/
|
|
73
|
+
private projectedTitle;
|
|
47
74
|
/**
|
|
48
75
|
* Remote face of {@link listCandidates}: the configured candidate limit
|
|
49
76
|
* applies, and every candidate carries the canonical mention a host inserts
|
package/lib/types/index.js
CHANGED
|
@@ -96,7 +96,7 @@ let SessionReferenceResolver = (() => {
|
|
|
96
96
|
if (decision.kind === 'reject')
|
|
97
97
|
return decision;
|
|
98
98
|
return {
|
|
99
|
-
|
|
99
|
+
...decision,
|
|
100
100
|
messages: await this.prepareDirectMessages(agent, decision.messages, signal),
|
|
101
101
|
};
|
|
102
102
|
}, { prepend: true });
|
|
@@ -135,6 +135,10 @@ let SessionReferenceResolver = (() => {
|
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* List reference candidates, ranked by working-directory affinity.
|
|
138
|
+
*
|
|
139
|
+
* Discovery runs at keystroke rate, so a title only ever comes from a
|
|
140
|
+
* projection read: see {@link SessionReferenceResolver.projectedTitle} for
|
|
141
|
+
* which sessions can answer one and which fall back to their id.
|
|
138
142
|
* @param agent - target agent; self is excluded and its cwd drives ranking.
|
|
139
143
|
* @param query - optional case-insensitive session-id/cwd/title substring.
|
|
140
144
|
* @param limit - optional positive result cap.
|
|
@@ -151,23 +155,12 @@ let SessionReferenceResolver = (() => {
|
|
|
151
155
|
const records = (await settleWithCancellation(this.ctx.sessionQuery.listSessions(signal), signal))
|
|
152
156
|
.filter(record => record.header.id !== agent.id)
|
|
153
157
|
.map((record, index) => ({ record, index }));
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const observations = await settleWithCancellation(this.ctx.sessionQuery.readTitleSnapshots(inspected.map(({ record }) => record.header.id), signal), signal);
|
|
161
|
-
return inspected.map(({ record, index }, observationIndex) => {
|
|
162
|
-
const observation = observations[observationIndex];
|
|
163
|
-
return {
|
|
164
|
-
record,
|
|
165
|
-
index,
|
|
166
|
-
label: observation.status === 'fulfilled'
|
|
167
|
-
? observation.value.title?.title ?? record.header.id
|
|
168
|
-
: record.header.id,
|
|
169
|
-
};
|
|
170
|
-
}).filter(({ record, label }) => {
|
|
158
|
+
const labelled = records.map(({ record, index }) => ({
|
|
159
|
+
record,
|
|
160
|
+
index,
|
|
161
|
+
label: this.projectedTitle(record) ?? record.header.id,
|
|
162
|
+
}));
|
|
163
|
+
return labelled.filter(({ record, label }) => {
|
|
171
164
|
if (needle === '')
|
|
172
165
|
return true;
|
|
173
166
|
return record.header.id.toLocaleLowerCase().includes(needle)
|
|
@@ -180,9 +173,40 @@ let SessionReferenceResolver = (() => {
|
|
|
180
173
|
sessionId: record.header.id,
|
|
181
174
|
label,
|
|
182
175
|
...record.header.cwd === undefined ? {} : { cwd: record.header.cwd },
|
|
176
|
+
sameWorkspace: record.header.cwd !== undefined && record.header.cwd === targetCwd,
|
|
183
177
|
createdAt: record.header.createdAt,
|
|
184
178
|
}));
|
|
185
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* The title a session's projections can answer without reading its log.
|
|
182
|
+
*
|
|
183
|
+
* Attachment is decided by the store at read time, not by the listing:
|
|
184
|
+
* a session that attached in between would otherwise be answered from a
|
|
185
|
+
* checkpoint its live log has already moved past.
|
|
186
|
+
*
|
|
187
|
+
* An attached session answers from its live registry cut, which advances
|
|
188
|
+
* with every committed event, so a rename or a just-generated title is
|
|
189
|
+
* visible immediately; its events are already in memory, so the lazy fold
|
|
190
|
+
* costs no I/O. A cold session answers from the durable checkpoint the
|
|
191
|
+
* projection cache wrote when it went cold.
|
|
192
|
+
*
|
|
193
|
+
* Nothing else is attempted. Folding a title from a log costs the whole
|
|
194
|
+
* log, and this call sits under every keystroke of `@` completion. A
|
|
195
|
+
* session that no projection can answer for — one persisted before the
|
|
196
|
+
* cache was composed, or seeded straight to disk — is labeled by its id
|
|
197
|
+
* and cannot be found by its title until it is opened once, which
|
|
198
|
+
* checkpoints it.
|
|
199
|
+
* @param record - the listed session, live or cold.
|
|
200
|
+
* @returns the projected title, or undefined when no projection holds one.
|
|
201
|
+
*/
|
|
202
|
+
projectedTitle(record) {
|
|
203
|
+
const attached = this.ctx.get('sessions')?.get(record.header.id);
|
|
204
|
+
const projections = this.ctx.get('sessionProjections');
|
|
205
|
+
if (attached !== undefined && projections !== undefined) {
|
|
206
|
+
return titleOf(projections.snapshot(attached, ['title']));
|
|
207
|
+
}
|
|
208
|
+
return titleOf(this.ctx.get('sessionProjectionCache')?.cachedSnapshot(record.header, ['title']));
|
|
209
|
+
}
|
|
186
210
|
/**
|
|
187
211
|
* Remote face of {@link listCandidates}: the configured candidate limit
|
|
188
212
|
* applies, and every candidate carries the canonical mention a host inserts
|
|
@@ -287,6 +311,11 @@ function normalizeReferences(targetId, references, maxReferences) {
|
|
|
287
311
|
function renderPrompt(data) {
|
|
288
312
|
return `${PROMPT_PREFIX}${stringifyTagSafeJson(data)}${PROMPT_SUFFIX}`;
|
|
289
313
|
}
|
|
314
|
+
/** The title in one projection snapshot; undefined when the unit is absent or still untitled. */
|
|
315
|
+
function titleOf(snapshot) {
|
|
316
|
+
const title = snapshot?.values.title;
|
|
317
|
+
return title === undefined || title === null ? undefined : title;
|
|
318
|
+
}
|
|
290
319
|
function candidateRank(candidateCwd, targetCwd) {
|
|
291
320
|
if (candidateCwd !== undefined && targetCwd !== undefined && candidateCwd === targetCwd)
|
|
292
321
|
return 0;
|
package/lib/types/projection.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Current-surface projection and byte-bounded rendering. */
|
|
2
2
|
import { isCompactCheckpointSource } from '@deepseek-ai/dsh-compaction';
|
|
3
|
-
import { assertNever } from '@deepseek-ai/dsh-llm';
|
|
4
3
|
import { TextRetainer } from '@deepseek-ai/dsh-output-retention';
|
|
4
|
+
import { assertNever } from '@deepseek-ai/dsh-util-values';
|
|
5
5
|
import { stringifyTagSafeJson } from "./serialization.js";
|
|
6
6
|
/** Project current user/assistant conversation while excluding tools, reasoning, and injected context. */
|
|
7
7
|
function projectSessionConversation(snapshot) {
|
package/lib/types/types.d.ts
CHANGED
|
@@ -46,6 +46,12 @@ export interface SessionReferenceCandidate {
|
|
|
46
46
|
label: string;
|
|
47
47
|
/** Source session working directory, when recorded. */
|
|
48
48
|
cwd?: string;
|
|
49
|
+
/**
|
|
50
|
+
* True when {@link SessionReferenceCandidate.cwd} is recorded and equals the
|
|
51
|
+
* requesting agent's. Hosts that only surface a distinguishing location
|
|
52
|
+
* read this instead of comparing paths they never received.
|
|
53
|
+
*/
|
|
54
|
+
sameWorkspace: boolean;
|
|
49
55
|
/** Source session creation time in Unix epoch milliseconds. */
|
|
50
56
|
createdAt: number;
|
|
51
57
|
}
|
package/lib/types/uri.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Canonical session URI and inline mention encoding. */
|
|
2
|
-
import {
|
|
2
|
+
import type { SessionId as SessionIdType } from '@deepseek-ai/dsh-session';
|
|
3
3
|
import type { SessionReferenceInput } from './types.ts';
|
|
4
4
|
/** URI scheme reserved for DeepSeek Harness session snapshots. */
|
|
5
5
|
export declare const SESSION_REFERENCE_SCHEME = "dsh-session:";
|
package/lib/types/uri.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Canonical session URI and inline mention encoding. */
|
|
2
|
-
import {
|
|
2
|
+
import { brandString } from '@deepseek-ai/dsh-brand';
|
|
3
3
|
import { SessionReferenceError } from "./config.js";
|
|
4
4
|
/** URI scheme reserved for DeepSeek Harness session snapshots. */
|
|
5
5
|
export const SESSION_REFERENCE_SCHEME = 'dsh-session:';
|
|
@@ -28,7 +28,7 @@ export function decodeSessionReferenceUri(uri) {
|
|
|
28
28
|
const parsed = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
|
|
29
29
|
if (typeof parsed !== 'string')
|
|
30
30
|
throw new TypeError('decoded session id is not a string');
|
|
31
|
-
const sessionId =
|
|
31
|
+
const sessionId = brandString(parsed);
|
|
32
32
|
if (encodeSessionReferenceUri(sessionId) !== uri)
|
|
33
33
|
throw new TypeError('URI is not canonical');
|
|
34
34
|
return sessionId;
|
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.
|
|
4
|
+
"version": "0.1.2-alpha.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -50,28 +50,41 @@
|
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"zod": "^4.4.3",
|
|
53
|
-
"@deepseek-ai/
|
|
53
|
+
"@deepseek-ai/dsh-brand": "^0.1.2-alpha.3",
|
|
54
|
+
"@deepseek-ai/dsh-util-values": "^0.1.2-alpha.3",
|
|
55
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
|
-
"@deepseek-ai/
|
|
57
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
58
|
-
"@deepseek-ai/dsh-
|
|
59
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
60
|
-
"@deepseek-ai/dsh-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-session
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/
|
|
58
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
59
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-alpha.3",
|
|
60
|
+
"@deepseek-ai/dsh-compaction": "^0.1.2-alpha.3",
|
|
61
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.3",
|
|
62
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.3",
|
|
63
|
+
"@deepseek-ai/dsh-output-retention": "^0.1.2-alpha.3",
|
|
64
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.3",
|
|
65
|
+
"@deepseek-ai/dsh-session-projection": "^0.1.2-alpha.3",
|
|
66
|
+
"@deepseek-ai/dsh-session-projection-cache": "^0.1.2-alpha.3",
|
|
67
|
+
"@deepseek-ai/dsh-session-query": "^0.1.2-alpha.3",
|
|
68
|
+
"@deepseek-ai/dsh-session-title": "^0.1.2-alpha.3",
|
|
69
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.3"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"@deepseek-ai/dsh-session-projection-cache": {
|
|
73
|
+
"optional": true
|
|
74
|
+
}
|
|
65
75
|
},
|
|
66
76
|
"devDependencies": {
|
|
67
|
-
"@deepseek-ai/
|
|
68
|
-
"@deepseek-ai/dsh-
|
|
69
|
-
"@deepseek-ai/dsh-
|
|
70
|
-
"@deepseek-ai/dsh-
|
|
71
|
-
"@deepseek-ai/dsh-output-retention": "^0.1.
|
|
72
|
-
"@deepseek-ai/dsh-session
|
|
73
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
74
|
-
"@deepseek-ai/dsh-
|
|
75
|
-
"@deepseek-ai/
|
|
77
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
78
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-alpha.3",
|
|
79
|
+
"@deepseek-ai/dsh-compaction": "^0.1.2-alpha.3",
|
|
80
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.3",
|
|
81
|
+
"@deepseek-ai/dsh-output-retention": "^0.1.2-alpha.3",
|
|
82
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.3",
|
|
83
|
+
"@deepseek-ai/dsh-session-projection": "^0.1.2-alpha.3",
|
|
84
|
+
"@deepseek-ai/dsh-session-projection-cache": "^0.1.2-alpha.3",
|
|
85
|
+
"@deepseek-ai/dsh-session-query": "^0.1.2-alpha.3",
|
|
86
|
+
"@deepseek-ai/dsh-session-title": "^0.1.2-alpha.3",
|
|
87
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.3",
|
|
88
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.3"
|
|
76
89
|
}
|
|
77
90
|
}
|