@deepseek-ai/dsh-session-title 0.0.1-rc.1
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/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +55 -0
- package/README.zh.md +55 -0
- package/lib/index.js +580 -0
- package/lib/invariant.js +38 -0
- package/lib/types/client.d.ts +10 -0
- package/lib/types/client.js +10 -0
- package/lib/types/index.d.ts +230 -0
- package/lib/types/index.js +601 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/invariant.js +41 -0
- package/lib/types/normalize.d.ts +24 -0
- package/lib/types/normalize.js +71 -0
- package/lib/types/types.d.ts +21 -0
- package/lib/types/types.js +11 -0
- package/package.json +65 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log-backed session title service, deterministic fallback, and provider contract.
|
|
3
|
+
* @module @deepseek-ai/dsh-session-title
|
|
4
|
+
*/
|
|
5
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
6
|
+
import z from '@deepseek-ai/schemastery';
|
|
7
|
+
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
8
|
+
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session';
|
|
9
|
+
export type * from './types.ts';
|
|
10
|
+
export { fallbackSessionTitle, normalizeSessionTitle, truncateTitleUtf8 } from './normalize.ts';
|
|
11
|
+
/** Identifies one session-title provider registration. */
|
|
12
|
+
export type SessionTitleProviderId = Branded<'SessionTitleProviderId'>;
|
|
13
|
+
/**
|
|
14
|
+
* Brand a raw provider id.
|
|
15
|
+
* @param id - stable non-empty provider identifier supplied by a plugin.
|
|
16
|
+
* @returns the same string with the session-title provider brand.
|
|
17
|
+
*/
|
|
18
|
+
export declare function SessionTitleProviderId(id: string): SessionTitleProviderId;
|
|
19
|
+
/** Exact auxiliary model route that produced a title. */
|
|
20
|
+
export interface SessionTitleModelProvenance {
|
|
21
|
+
/** Registered LLM provider route. */
|
|
22
|
+
readonly provider: string;
|
|
23
|
+
/** Provider model id. */
|
|
24
|
+
readonly model: string;
|
|
25
|
+
}
|
|
26
|
+
/** Durable ownership record for an accepted session title. */
|
|
27
|
+
export type SessionTitleSource = {
|
|
28
|
+
readonly kind: 'fallback';
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: 'provider';
|
|
31
|
+
readonly provider: SessionTitleProviderId;
|
|
32
|
+
readonly model?: SessionTitleModelProvenance;
|
|
33
|
+
} | {
|
|
34
|
+
/** Explicit user rename: pins the title — automatic generation stops scheduling. */
|
|
35
|
+
readonly kind: 'user';
|
|
36
|
+
};
|
|
37
|
+
/** Payload of the log-only `session/title` event. */
|
|
38
|
+
export interface SessionTitleEventData {
|
|
39
|
+
/** Normalized non-empty title text. */
|
|
40
|
+
readonly title: string;
|
|
41
|
+
/** Exact human `user/message` seqs used to derive this title; empty for an explicit user rename. */
|
|
42
|
+
readonly messageSeqs: number[];
|
|
43
|
+
/** Whether the built-in fallback, a registered provider, or the user supplied the title. */
|
|
44
|
+
readonly source: SessionTitleSource;
|
|
45
|
+
}
|
|
46
|
+
/** Latest folded title plus the title event's durable envelope facts. */
|
|
47
|
+
export interface SessionTitleSnapshot extends SessionTitleEventData {
|
|
48
|
+
/** Seq of the latest `session/title` event. */
|
|
49
|
+
readonly eventSeq: number;
|
|
50
|
+
/** Timestamp of the latest `session/title` event. */
|
|
51
|
+
readonly updatedAt: number;
|
|
52
|
+
}
|
|
53
|
+
/** Required deterministic fallback and accepted-title limits. */
|
|
54
|
+
export interface Config {
|
|
55
|
+
/** Maximum whitespace-delimited words in the built-in fallback. */
|
|
56
|
+
readonly fallbackMaxWords: number;
|
|
57
|
+
/** Maximum UTF-8 bytes in the built-in fallback. */
|
|
58
|
+
readonly fallbackMaxBytes: number;
|
|
59
|
+
/** Maximum UTF-8 bytes in any accepted title. */
|
|
60
|
+
readonly maxTitleBytes: number;
|
|
61
|
+
}
|
|
62
|
+
declare module '@deepseek-ai/cordis' {
|
|
63
|
+
interface Context {
|
|
64
|
+
sessionTitle: SessionTitleService;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
declare module '@deepseek-ai/dsh-session/types' {
|
|
68
|
+
interface SessionEventMap {
|
|
69
|
+
/**
|
|
70
|
+
* Latest-wins session title snapshot. Log-only: it never enters the model
|
|
71
|
+
* surface or derived history.
|
|
72
|
+
*/
|
|
73
|
+
'session/title': SessionTitleEventData;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Rejection of an explicit user title whose text normalizes to empty — the
|
|
78
|
+
* one {@link SessionTitleService.rename} failure that blames the input.
|
|
79
|
+
* Callers translating rename failures onto a wire (`title-invalid`) narrow on
|
|
80
|
+
* this class; liveness and disposal failures stay plain `Error`s.
|
|
81
|
+
*/
|
|
82
|
+
export declare class SessionTitleInvalidError extends Error {
|
|
83
|
+
readonly name = "SessionTitleInvalidError";
|
|
84
|
+
}
|
|
85
|
+
/** One eligible human text message exposed to title providers. */
|
|
86
|
+
export interface SessionTitleUserMessage {
|
|
87
|
+
/** Source `user/message` event seq. */
|
|
88
|
+
readonly seq: number;
|
|
89
|
+
/** Exact concatenated text-block content. */
|
|
90
|
+
readonly text: string;
|
|
91
|
+
}
|
|
92
|
+
/** Automatic generation cadence owned by a registered provider. */
|
|
93
|
+
export type SessionTitleAutomaticMode = 'first-message' | 'all-user-messages';
|
|
94
|
+
/** Immutable input supplied to one title-provider call. */
|
|
95
|
+
export interface SessionTitleProviderRequest {
|
|
96
|
+
/** Live session being titled. */
|
|
97
|
+
readonly session: Session;
|
|
98
|
+
/** All eligible human messages through this generation revision. */
|
|
99
|
+
readonly messages: readonly SessionTitleUserMessage[];
|
|
100
|
+
/** Exact current logged main-request route, when one has been recorded. */
|
|
101
|
+
readonly route?: SessionTitleModelProvenance;
|
|
102
|
+
/** Cancellation for supersession, disposal, timeout composition, or the explicit caller. */
|
|
103
|
+
readonly signal: AbortSignal;
|
|
104
|
+
}
|
|
105
|
+
/** Provider output before service-owned normalization and log acceptance. */
|
|
106
|
+
export interface SessionTitleProviderResult {
|
|
107
|
+
/** Proposed title text. */
|
|
108
|
+
readonly title: string;
|
|
109
|
+
/** Exact seqs from `request.messages` used by this result. */
|
|
110
|
+
readonly messageSeqs: readonly number[];
|
|
111
|
+
/** Auxiliary LLM route, when generation used a model. */
|
|
112
|
+
readonly model?: SessionTitleModelProvenance;
|
|
113
|
+
}
|
|
114
|
+
/** One optional asynchronous title implementation registered with the service. */
|
|
115
|
+
export interface SessionTitleProvider {
|
|
116
|
+
/** Stable id of the provider recorded with the title. */
|
|
117
|
+
readonly id: SessionTitleProviderId;
|
|
118
|
+
/** When new human prompts start automatic generation. */
|
|
119
|
+
readonly automatic: SessionTitleAutomaticMode;
|
|
120
|
+
/**
|
|
121
|
+
* Produce one title revision.
|
|
122
|
+
* @param request - message snapshot, current route, session, and cancellation.
|
|
123
|
+
* @returns proposed title plus exact input seqs and the optional provider/model route used to generate it.
|
|
124
|
+
*/
|
|
125
|
+
generate(request: SessionTitleProviderRequest): Promise<SessionTitleProviderResult>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Collect human text-bearing user messages in log order.
|
|
129
|
+
* @param events - session log or persisted replay.
|
|
130
|
+
* @param throughSeq - optional inclusive event boundary.
|
|
131
|
+
* @returns eligible messages with exact source seqs.
|
|
132
|
+
*/
|
|
133
|
+
export declare function collectSessionTitleMessages(events: readonly SessionEvent[], throughSeq?: number): SessionTitleUserMessage[];
|
|
134
|
+
/**
|
|
135
|
+
* Fold the latest logged title without consulting mutable metadata.
|
|
136
|
+
* @param events - live or persisted session log.
|
|
137
|
+
* @returns the latest immutable title snapshot, or `undefined`.
|
|
138
|
+
*/
|
|
139
|
+
export declare function foldSessionTitle(events: readonly SessionEvent[]): SessionTitleSnapshot | undefined;
|
|
140
|
+
/** Log-backed title fold plus asynchronous fallback generation. */
|
|
141
|
+
export declare class SessionTitleService extends Service {
|
|
142
|
+
static inject: string[];
|
|
143
|
+
static Config: z<Config>;
|
|
144
|
+
private readonly config;
|
|
145
|
+
private readonly ownerFiber;
|
|
146
|
+
private registration;
|
|
147
|
+
private readonly work;
|
|
148
|
+
private readonly lifetime;
|
|
149
|
+
private readonly inFlight;
|
|
150
|
+
constructor(ctx: Context, config: Config);
|
|
151
|
+
/**
|
|
152
|
+
* Read the latest folded title from one live or replayed session.
|
|
153
|
+
* @param session - session whose log is the title source of truth.
|
|
154
|
+
* @returns latest title snapshot, or `undefined` before eligible input.
|
|
155
|
+
*/
|
|
156
|
+
get(session: Session): SessionTitleSnapshot | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* Accept an explicit user title. Appends a `session/title` event with the
|
|
159
|
+
* `user` source, which pins the title: in-flight automatic generation is
|
|
160
|
+
* superseded and later user messages schedule none (an explicit
|
|
161
|
+
* {@link SessionTitleService.refresh} remains the deliberate unpin).
|
|
162
|
+
* @param session - exact live session to rename.
|
|
163
|
+
* @param title - raw user input; normalized before acceptance.
|
|
164
|
+
* @returns the accepted title snapshot.
|
|
165
|
+
* @throws {SessionTitleInvalidError} when the title normalizes to empty.
|
|
166
|
+
* @throws {Error} when the session is not live or the service is disposed.
|
|
167
|
+
*/
|
|
168
|
+
rename(session: Session, title: string): SessionTitleSnapshot;
|
|
169
|
+
/**
|
|
170
|
+
* Explicitly retry the registered provider, or materialize the built-in
|
|
171
|
+
* fallback when no provider is registered.
|
|
172
|
+
* @param session - exact live session to refresh.
|
|
173
|
+
* @param signal - optional caller cancellation.
|
|
174
|
+
* @returns latest accepted title, or `undefined` when no eligible text exists.
|
|
175
|
+
*/
|
|
176
|
+
refresh(session: Session, signal?: AbortSignal): Promise<SessionTitleSnapshot | undefined>;
|
|
177
|
+
/**
|
|
178
|
+
* Register the sole optional title provider. Disposal aborts its pending and
|
|
179
|
+
* active work before another provider may register.
|
|
180
|
+
* @param provider - provider identity, cadence, and generation function.
|
|
181
|
+
* @returns exact Cordis effect disposer, which settles after active calls quiesce.
|
|
182
|
+
*/
|
|
183
|
+
register(provider: SessionTitleProvider): () => Promise<void>;
|
|
184
|
+
/** Schedule fallback creation and any provider cadence for one eligible event. */
|
|
185
|
+
private onUserMessage;
|
|
186
|
+
/** Start pending automatic work only after its exact main-request route is logged. */
|
|
187
|
+
private onRequestHeader;
|
|
188
|
+
/** Start unchanged-route work from the marked loop request after its header fold is current. */
|
|
189
|
+
private onMainRequest;
|
|
190
|
+
/** Consume one pending revision and schedule its non-blocking provider call. */
|
|
191
|
+
private startPending;
|
|
192
|
+
/** Start one tracked provider call after publishing its active revision. */
|
|
193
|
+
private startProvider;
|
|
194
|
+
/** Execute and accept one current provider revision. */
|
|
195
|
+
private runProvider;
|
|
196
|
+
/** Validate and normalize provider output against the supplied message snapshot. */
|
|
197
|
+
private validateResult;
|
|
198
|
+
/** Fail a completion whose provider, revision, session, or signal is stale. */
|
|
199
|
+
private assertCurrent;
|
|
200
|
+
/** Create and publish an active provider call from one fixed revision. */
|
|
201
|
+
private activate;
|
|
202
|
+
/** Abort older active work and reserve the next session-local revision. */
|
|
203
|
+
private supersede;
|
|
204
|
+
/** Return mutable work state for one session. */
|
|
205
|
+
private stateFor;
|
|
206
|
+
/** Queue detached service work and retain it through service disposal. */
|
|
207
|
+
private defer;
|
|
208
|
+
/** Retain one promise until settlement for service and optional provider teardown. */
|
|
209
|
+
private track;
|
|
210
|
+
/** Await every current and settling promise in one lifecycle registry. */
|
|
211
|
+
private drain;
|
|
212
|
+
/** Whether the owning plugin fiber can still start or commit title work. */
|
|
213
|
+
private serviceActive;
|
|
214
|
+
/** Reject work once the owning plugin fiber has begun unloading. */
|
|
215
|
+
private assertServiceActive;
|
|
216
|
+
/** Reject malformed provider registrations before publishing an effect. */
|
|
217
|
+
private validateProvider;
|
|
218
|
+
/**
|
|
219
|
+
* Derive and append the deterministic fallback title over whatever stands
|
|
220
|
+
* (the refresh unpin path: overwriting a pinned user title is the point).
|
|
221
|
+
* Synchronous on purpose — no await may separate derivation from append, so
|
|
222
|
+
* it needs neither ensureFallback's in-flight dedup nor its liveness
|
|
223
|
+
* re-check. An underivable fallback (empty after the caps) appends nothing.
|
|
224
|
+
*/
|
|
225
|
+
private appendFallback;
|
|
226
|
+
/** Create the first deterministic fallback if the session still lacks a title. */
|
|
227
|
+
private ensureFallback;
|
|
228
|
+
}
|
|
229
|
+
export default SessionTitleService;
|
|
230
|
+
//# sourceMappingURL=index.d.ts.map
|