dsh-session-recall 0.5.1 → 0.6.0
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/lib/index.d.ts +10 -1
- package/lib/index.js +34 -2
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ToolDefinition, ToolRunContext } from "@deepseek-ai/dsh-tools";
|
|
2
|
-
import { SessionEventResultFilter, SessionEventSearchDocument, SessionEventSearchPage, SessionEventSearchRequest, SessionRecord, SessionSearchExecContext, SessionSearchHit, SessionSearchPage, SessionSearchRequest, SessionTitleObservationResult } from "@deepseek-ai/dsh-session-query";
|
|
2
|
+
import { SessionEventResultFilter, SessionEventSearchDocument, SessionEventSearchPage, SessionEventSearchRequest, SessionLineageTrace, SessionRecord, SessionSearchExecContext, SessionSearchHit, SessionSearchPage, SessionSearchRequest, SessionTitleObservationResult } from "@deepseek-ai/dsh-session-query";
|
|
3
3
|
import { JsonValue, SessionId } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
import { ContentBlock } from "@deepseek-ai/dsh-llm";
|
|
@@ -50,6 +50,12 @@ interface RecallConfig {
|
|
|
50
50
|
recencyHalfLifeDays?: number;
|
|
51
51
|
/** Sessions started in these project directories rank first. Default: none. */
|
|
52
52
|
pinnedCwds?: readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* Restrict recall results to sessions in the calling agent's own lineage
|
|
55
|
+
* (ancestors + self + descendants). Default `true` — other agents in the
|
|
56
|
+
* same project are invisible unless this is set to `false`.
|
|
57
|
+
*/
|
|
58
|
+
callerTreeOnly?: boolean;
|
|
53
59
|
}
|
|
54
60
|
/** Validated, fully defaulted configuration. */
|
|
55
61
|
interface NormalizedRecallConfig {
|
|
@@ -65,6 +71,7 @@ interface NormalizedRecallConfig {
|
|
|
65
71
|
readonly allProjectsPolicy: AllProjectsPolicy;
|
|
66
72
|
readonly recencyHalfLifeDays: number | undefined;
|
|
67
73
|
readonly pinnedCwds: readonly string[];
|
|
74
|
+
readonly callerTreeOnly: boolean;
|
|
68
75
|
}
|
|
69
76
|
/** Default, clamp, and cross-check every optional field. */
|
|
70
77
|
declare function normalizeRecallConfig(config?: RecallConfig): NormalizedRecallConfig;
|
|
@@ -186,6 +193,8 @@ interface RecallQueryEngine {
|
|
|
186
193
|
readTitleSnapshots(sessionIds: readonly string[], signal?: AbortSignal): Promise<SessionTitleObservationResult[]>;
|
|
187
194
|
listSessions(signal?: AbortSignal): Promise<SessionRecord[]>;
|
|
188
195
|
filterEvents(sessionId: SessionId, filters: readonly SessionEventResultFilter[]): Promise<SessionEventSearchDocument[]>;
|
|
196
|
+
/** Trace the caller's session lineage for caller-authorization gating. */
|
|
197
|
+
traceSession(sessionId: SessionId, signal?: AbortSignal): Promise<SessionLineageTrace>;
|
|
189
198
|
}
|
|
190
199
|
declare const RECALL_TOOL_DESCRIPTION: string;
|
|
191
200
|
/** The approval verdict vocabulary mirrored from `@deepseek-ai/dsh-user-approval`. */
|
package/lib/index.js
CHANGED
|
@@ -97,7 +97,8 @@ function normalizeRecallConfig(config) {
|
|
|
97
97
|
cwdDenylist: stringList(config?.cwdDenylist),
|
|
98
98
|
allProjectsPolicy: normalizePolicy(config?.allProjectsPolicy),
|
|
99
99
|
recencyHalfLifeDays: typeof config?.recencyHalfLifeDays === "number" && Number.isFinite(config.recencyHalfLifeDays) && config.recencyHalfLifeDays > 0 ? Math.min(3650, Math.trunc(config.recencyHalfLifeDays)) : void 0,
|
|
100
|
-
pinnedCwds: stringList(config?.pinnedCwds)
|
|
100
|
+
pinnedCwds: stringList(config?.pinnedCwds),
|
|
101
|
+
callerTreeOnly: config?.callerTreeOnly !== false
|
|
101
102
|
};
|
|
102
103
|
}
|
|
103
104
|
/** Whether a session cwd is searchable under the allowlist/denylist policy. */
|
|
@@ -296,6 +297,20 @@ function cjkZeroHitHint(query, zeroHits, enabled) {
|
|
|
296
297
|
* calling agent's own project cwd unless the model explicitly widens the
|
|
297
298
|
* scope and the deployment allows it.
|
|
298
299
|
*/
|
|
300
|
+
/** Walk a lineage trace and collect every session id in the tree. */
|
|
301
|
+
function collectLineageIds(trace) {
|
|
302
|
+
const ids = /* @__PURE__ */ new Set();
|
|
303
|
+
ids.add(trace.target.header.id);
|
|
304
|
+
for (const ancestor of trace.ancestors) ids.add(ancestor.header.id);
|
|
305
|
+
const walk = (nodes) => {
|
|
306
|
+
for (const node of nodes) {
|
|
307
|
+
ids.add(node.session.header.id);
|
|
308
|
+
walk(node.descendants);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
walk(trace.descendants);
|
|
312
|
+
return ids;
|
|
313
|
+
}
|
|
299
314
|
const RECALL_TOOL_DESCRIPTION = [
|
|
300
315
|
"Search the FULL TEXT of past and current session transcripts on this machine (your own conversation history with this user).",
|
|
301
316
|
"Use it when the user refers to earlier work (\"that bug we fixed last week\", \"the font we chose for my resume\") or when prior context was compacted away.",
|
|
@@ -598,6 +613,11 @@ function createRecallTool(config, engine, approver) {
|
|
|
598
613
|
if (query === "") return recallError(query, Object.assign(/* @__PURE__ */ new Error("empty query"), { code: "SESSION_QUERY_INVALID_QUERY" }));
|
|
599
614
|
const limit = clamp(Math.trunc(args.limit ?? cfg.defaultLimit), 1, cfg.maxLimit);
|
|
600
615
|
const agentCwd = exec.agent?.session.header?.cwd ?? null;
|
|
616
|
+
const callerSessionId = exec.agent?.session?.id;
|
|
617
|
+
let allowedIds = null;
|
|
618
|
+
if (cfg.callerTreeOnly && callerSessionId != null) try {
|
|
619
|
+
allowedIds = collectLineageIds(await engine.traceSession(SessionId(callerSessionId), exec.signal));
|
|
620
|
+
} catch {}
|
|
601
621
|
const scopeHints = [];
|
|
602
622
|
let wantAll = false;
|
|
603
623
|
if (args.session_id == null && args.all_projects === true) {
|
|
@@ -633,6 +653,17 @@ function createRecallTool(config, engine, approver) {
|
|
|
633
653
|
limit,
|
|
634
654
|
cursor: brand(args.cursor)
|
|
635
655
|
}, { signal: exec.signal });
|
|
656
|
+
if (allowedIds != null && !allowedIds.has(args.session_id)) return {
|
|
657
|
+
query,
|
|
658
|
+
scope,
|
|
659
|
+
count: 0,
|
|
660
|
+
hasMore: false,
|
|
661
|
+
items: [],
|
|
662
|
+
nextCursor: null,
|
|
663
|
+
hint: "that session is outside your conversation lineage. Search without session_id to find sessions in your own tree, or ask the user to disable callerTreeOnly.",
|
|
664
|
+
redacted: 0,
|
|
665
|
+
diagnostics: null
|
|
666
|
+
};
|
|
636
667
|
if (!cwdAllowed(page.session.cwd ?? null, cfg)) return {
|
|
637
668
|
query,
|
|
638
669
|
scope,
|
|
@@ -706,6 +737,7 @@ function createRecallTool(config, engine, approver) {
|
|
|
706
737
|
};
|
|
707
738
|
const ranked = rankingActive(rankingOptions);
|
|
708
739
|
let items = rankItems(toItems(page.items, titles).filter((item) => cwdAllowed(item.cwd, cfg)), rankingOptions);
|
|
740
|
+
if (allowedIds != null) items = items.filter((item) => allowedIds.has(item.sessionId));
|
|
709
741
|
let hint = null;
|
|
710
742
|
let fallbackRan = false;
|
|
711
743
|
let diagnostics = {
|
|
@@ -716,7 +748,7 @@ function createRecallTool(config, engine, approver) {
|
|
|
716
748
|
fallbackRan = true;
|
|
717
749
|
const scan = await cjkScanSessions(engine, query, agentCwd, wantAll, cfg, cfg.cjkFallbackScanMax, limit, exec.signal);
|
|
718
750
|
const scanTitles = await titlesFor(engine, scan.items.map((item) => item.sessionId), exec.signal);
|
|
719
|
-
items = rankItems(scan.items.map((item) => ({
|
|
751
|
+
items = rankItems(scan.items.filter((item) => allowedIds == null || allowedIds.has(item.sessionId)).map((item) => ({
|
|
720
752
|
...item,
|
|
721
753
|
title: scanTitles.get(item.sessionId) ?? null
|
|
722
754
|
})), rankingOptions);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-recall",
|
|
3
3
|
"description": "Deterministic cross-session transcript retrieval for DeepSeek Harness: the model-facing `recall` tool searches past session logs with explicit scope control",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|