Merge remote-tracking branch 'origin/master' into worktree/tui-session-title-search

# Conflicts:
#	.agents/notes/implemented/feature/2026-07-21-cross-session-references.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-21-cross-session-references.md
#	.agents/notes/implemented/feature/2026-07-21-cross-session-references.zh.md
#	packages/context/session-reference/README.i18n.yaml
#	packages/context/session-reference/README.md
#	packages/context/session-reference/README.zh.md
#	packages/context/session-reference/src/index.ts
This commit is contained in:
Yichen Jiang
2026-07-28 11:11:57 +08:00
1323 changed files with 41028 additions and 20842 deletions

View File

@@ -7,9 +7,9 @@
import { Context, Service } from 'cordis'
import z from 'schemastery'
import type { Agent, HookContext } from '@deepseek-ai/dsh-agent'
import type { Agent } from '@deepseek-ai/dsh-agent'
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
import type { JsonValue, SessionId } from '@deepseek-ai/dsh-session'
import type { SessionId, UserMessageData } from '@deepseek-ai/dsh-session'
import type { SessionSurfaceSnapshot, SessionTitleObservationResult } from '@deepseek-ai/dsh-session-query'
import {
DEFAULT_CANDIDATE_LIMIT,
@@ -20,7 +20,7 @@ import {
} from './config.ts'
import { retainReferencedSession, type ReferenceRetentionStats, type ReferencedSessionData } from './projection.ts'
import { stringifyTagSafeJson } from './serialization.ts'
import type { PreparedReferencedMessage, SessionReferenceCandidate, SessionReferenceInput } from './types.ts'
import type { PreparedReferencedMessage, SessionReferenceCandidate, SessionReferenceInput, SessionReferenceSource } from './types.ts'
export type * from './types.ts'
export type { Config, SessionReferenceErrorCode } from './config.ts'
@@ -163,7 +163,7 @@ export class SessionReferenceService extends Service {
* @param content - already host-normalized readable message content.
* @param references - structured source sessions in mention order.
* @param signal - optional cancellation boundary for host request teardown.
* @returns detached content and zero or one prepared contexts.
* @returns detached content and optional referenced-session context.
*/
async prepare(
agent: Agent,
@@ -173,7 +173,7 @@ export class SessionReferenceService extends Service {
): Promise<PreparedReferencedMessage> {
const acceptedContent = structuredClone(content)
const inputs = normalizeReferences(agent.id, references, this.config.maxReferences)
if (inputs.length === 0) return { content: acceptedContent, contexts: [] }
if (inputs.length === 0) return { content: acceptedContent }
assertNotCancelled(signal)
let prepared: PreparedSource[]
try {
@@ -196,7 +196,7 @@ export class SessionReferenceService extends Service {
const rendered = this.renderSources(prepared)
const prompt = renderPrompt(rendered.map(source => source.data))
const meta = {
const source: SessionReferenceSource = {
kind: 'session-reference',
version: 1,
references: rendered.map((source, index) => ({
@@ -206,14 +206,12 @@ export class SessionReferenceService extends Service {
...source.stats,
inputIndex: index,
})),
} satisfies JsonValue
const context: HookContext = {
source: { kind: 'plugin', plugin: 'session-reference' },
content: [{ type: 'text', text: prompt }],
placement: 'prompt-prefix',
meta,
}
return { content: acceptedContent, contexts: [context] }
const additionalContext: UserMessageData = {
source,
content: [{ type: 'text', text: prompt }],
}
return { content: acceptedContent, additionalContext }
}
private renderSources(sources: readonly PreparedSource[]): RenderedSource[] {

View File

@@ -1,7 +1,6 @@
/** Current-surface projection and byte-bounded rendering. */
import { isCompactCheckpointSource } from '@deepseek-ai/dsh-compact'
import { displayPromptContent } from '@deepseek-ai/dsh-session'
import type { SessionSurfaceSnapshot } from '@deepseek-ai/dsh-session-query'
import { assertNever } from '@deepseek-ai/dsh-llm'
import { TextRetainer } from '@deepseek-ai/dsh-retention'
@@ -41,13 +40,13 @@ function projectSessionConversation(snapshot: SessionSurfaceSnapshot): Projected
case 'user/message': {
const checkpoint = isCompactCheckpointSource(event.data.source)
if (!checkpoint && event.data.source.kind !== 'user') break
const text = textContent(displayPromptContent(event.data))
const text = textContent(event.data.content)
if (text !== '') conversation.push({ role: 'user', text, checkpoint, originalText: text, omittedBytes: 0 })
break
}
case 'steering/message': {
if (event.data.source.kind !== 'user') break
const text = textContent(displayPromptContent(event.data))
const text = textContent(event.data.content)
if (text !== '') conversation.push({ role: 'user', text, checkpoint: false, originalText: text, omittedBytes: 0 })
break
}

View File

@@ -1,8 +1,31 @@
/** Public session-reference request, candidate, and preparation records. */
import type { HookContext } from '@deepseek-ai/dsh-agent'
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
import type { SessionId } from '@deepseek-ai/dsh-session'
import type { SessionId, UserMessageData } from '@deepseek-ai/dsh-session'
/** Durable provenance for one prepared cross-session context. */
export interface SessionReferenceSource {
kind: 'session-reference'
version: 1
references: {
sessionId: string
label: string
capturedThroughSeq: number | null
compacted: boolean
originalMessages: number
retainedMessages: number
omittedMessages: number
omittedBytes: number
truncated: boolean
inputIndex: number
}[]
}
declare module '@deepseek-ai/dsh-llm' {
interface MessageSourceMap {
'session-reference': SessionReferenceSource
}
}
/** One source session selected by a host. */
export interface SessionReferenceInput {
@@ -24,12 +47,12 @@ export interface SessionReferenceCandidate {
createdAt: number
}
/** Message payload and the zero-or-one durable snapshot contexts bound to it. */
/** Direct message content and optional referenced-session context. */
export interface PreparedReferencedMessage {
/** Readable message content after host mention tokens are removed. */
content: ContentBlock[]
/** Empty without references; otherwise one aggregated untrusted context. */
contexts: HookContext[]
/** Aggregated untrusted snapshot, absent when the message has no references. */
additionalContext?: UserMessageData
}
/** Text-only projected conversation item. */