@klarkxy/dsh-current-title 0.1.4 → 0.1.6
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.md +27 -9
- package/docs/README.zh-CN.md +38 -6
- package/icon.svg +15 -0
- package/lib/client.inner.cjs +732 -76
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +732 -76
- package/lib/contracts.d.ts +21 -4
- package/lib/contracts.js +38 -5
- package/lib/contracts.js.map +1 -1
- package/lib/index.d.ts +21 -5
- package/lib/index.js +195 -113
- package/lib/index.js.map +1 -1
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +40 -22
package/lib/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { PLUGIN_NAME,
|
|
2
|
-
import { registerHostRpc } from "@klarkxy/dsh-
|
|
1
|
+
import { PLUGIN_NAME, PROVIDER_ID, RPC_CHANNEL, SETTINGS_KEY, defaultGenerateConfig, defaultModelRoute, isTitleLocaleMode, normalizeCadence, normalizeModelRoute, normalizePrompt } from "./contracts.js";
|
|
2
|
+
import { registerHostRpc } from "@klarkxy/dsh-plugin-kit/host-rpc";
|
|
3
|
+
import { isSubagentSession } from "@klarkxy/dsh-plugin-kit/contracts";
|
|
4
|
+
import { callLlmText, resolveFeatureModel } from "@klarkxy/dsh-plugin-kit";
|
|
3
5
|
import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
|
|
4
6
|
import { z } from "zod";
|
|
5
7
|
//#region src/input.ts
|
|
@@ -135,22 +137,36 @@ function truncateSummary(value, targetWords, targetCjkCharacters) {
|
|
|
135
137
|
if (/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u.test(value)) return Array.from(value.replace(/\s+/gu, "")).slice(0, targetCjkCharacters).join("");
|
|
136
138
|
return value.split(/\s+/u).filter(Boolean).slice(0, targetWords).join(" ");
|
|
137
139
|
}
|
|
138
|
-
function
|
|
139
|
-
|
|
140
|
+
function unwrapModelText(raw) {
|
|
141
|
+
const trimmed = raw.trim();
|
|
142
|
+
return (/^```(?:json)?\s*([\s\S]*?)\s*```$/iu.exec(trimmed)?.[1] ?? trimmed).trim();
|
|
143
|
+
}
|
|
144
|
+
function readJsonObject(raw) {
|
|
145
|
+
const text = unwrapModelText(raw);
|
|
146
|
+
const start = text.indexOf("{");
|
|
147
|
+
const end = text.lastIndexOf("}");
|
|
148
|
+
if (start === -1 || end <= start) return void 0;
|
|
140
149
|
try {
|
|
141
|
-
value = JSON.parse(
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
const value = JSON.parse(text.slice(start, end + 1));
|
|
151
|
+
if (value && typeof value === "object" && !Array.isArray(value)) return value;
|
|
152
|
+
} catch {
|
|
153
|
+
return;
|
|
144
154
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Accept the required JSON shape, including a code fence or a short preface.
|
|
158
|
+
* Extra keys are ignored. A plain one-line title still becomes a title so a
|
|
159
|
+
* chatty model does not leave the session on the built-in fallback.
|
|
160
|
+
*/
|
|
161
|
+
function parseModelTitle(raw, targetWords, targetCjkCharacters) {
|
|
162
|
+
const candidate = readJsonObject(raw);
|
|
163
|
+
const typeValue = typeof candidate?.type === "string" ? candidate.type.trim().toLowerCase() : "";
|
|
164
|
+
const summaryValue = typeof candidate?.summary === "string" ? candidate.summary : "";
|
|
165
|
+
const type = isTitleType(typeValue) ? typeValue : "discuss";
|
|
166
|
+
const summary = truncateSummary(normalizeSessionTitle(removeTitleSyntax(summaryValue || (candidate ? "" : unwrapModelText(raw).replace(/^["'`]+|["'`]+$/gu, ""))), Number.MAX_SAFE_INTEGER), targetWords, targetCjkCharacters);
|
|
151
167
|
if (summary.length === 0) throw new Error("dsh-current-title: title model returned an empty summary");
|
|
152
168
|
return {
|
|
153
|
-
type
|
|
169
|
+
type,
|
|
154
170
|
summary
|
|
155
171
|
};
|
|
156
172
|
}
|
|
@@ -187,9 +203,9 @@ function sourceVersionOf(sessionId, messages) {
|
|
|
187
203
|
}
|
|
188
204
|
//#endregion
|
|
189
205
|
//#region src/generate.ts
|
|
190
|
-
function systemPrompt(config) {
|
|
206
|
+
function systemPrompt(config, customPrompt = "") {
|
|
191
207
|
return [
|
|
192
|
-
"Name the current task in an AI coding-assistant session.",
|
|
208
|
+
customPrompt.trim() || "Name the current task in an AI coding-assistant session.",
|
|
193
209
|
"Prioritize the newest human messages. Older messages are context only and must not keep a completed task in the title.",
|
|
194
210
|
"Allowed type values: feature, fix, optimize, refactor, test, docs, release, config, explore, discuss.",
|
|
195
211
|
"Return exactly one JSON object: {\"type\":\"<type>\",\"summary\":\"<summary>\"}.",
|
|
@@ -198,68 +214,53 @@ function systemPrompt(config) {
|
|
|
198
214
|
`Aim for at most ${config.targetWords} non-CJK words or ${config.targetCjkCharacters} CJK characters.`
|
|
199
215
|
].join("\n");
|
|
200
216
|
}
|
|
201
|
-
function
|
|
202
|
-
return
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
217
|
+
function titleModelRoute(route) {
|
|
218
|
+
if (!route?.provider || !route.model) return void 0;
|
|
219
|
+
return route.reasoningEffort ? {
|
|
220
|
+
provider: route.provider,
|
|
221
|
+
model: route.model,
|
|
222
|
+
reasoningEffort: route.reasoningEffort
|
|
223
|
+
} : {
|
|
224
|
+
provider: route.provider,
|
|
225
|
+
model: route.model
|
|
226
|
+
};
|
|
211
227
|
}
|
|
212
228
|
async function generateCurrentTitle(options) {
|
|
213
229
|
options.signal.throwIfAborted();
|
|
214
|
-
if (!options.
|
|
230
|
+
if (!options.isCurrent()) throw Object.assign(/* @__PURE__ */ new Error("dsh-current-title: generation is no longer current"), { code: "superseded" });
|
|
215
231
|
const selected = selectRecentMessages(options.messages, options.config.maxRecentMessages, options.config.maxInputBytes);
|
|
216
232
|
if (selected.length === 0) throw new Error("dsh-current-title: at least one source message is required");
|
|
233
|
+
const route = resolveFeatureModel(options.host, titleModelRoute(options.model), options.sessionId);
|
|
234
|
+
if (!route) throw new Error("dsh-current-title: 请在插件页选择模型,或设置宿主默认对话模型。");
|
|
235
|
+
const callRoute = {
|
|
236
|
+
provider: route.provider,
|
|
237
|
+
model: route.model
|
|
238
|
+
};
|
|
217
239
|
const framedInput = frameMessages(selected);
|
|
218
240
|
const locale = resolveTitleLocale(options.localeMode ?? options.config.locale, selected.map((message) => message.text), options.localePreference);
|
|
219
241
|
const sourceVersion = sourceVersionOf(options.sessionId, selected);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
options.signal.addEventListener("abort", fail, { once: true });
|
|
242
|
+
const result = await callLlmText(options.llm, {
|
|
243
|
+
plugin: PLUGIN_NAME,
|
|
244
|
+
route: callRoute,
|
|
245
|
+
system: systemPrompt(options.config, options.prompt),
|
|
246
|
+
text: framedInput,
|
|
247
|
+
maxTokens: options.config.maxOutputTokens,
|
|
248
|
+
purpose: "session-title",
|
|
249
|
+
signal: options.signal,
|
|
250
|
+
sessionId: options.sessionId,
|
|
251
|
+
isCurrent: options.isCurrent
|
|
231
252
|
});
|
|
232
|
-
let result;
|
|
233
|
-
try {
|
|
234
|
-
result = await Promise.race([options.scope.run({
|
|
235
|
-
purpose: PURPOSE_ID,
|
|
236
|
-
sessionId: options.sessionId,
|
|
237
|
-
input: framedInput,
|
|
238
|
-
system: systemPrompt(options.config),
|
|
239
|
-
sourceVersion,
|
|
240
|
-
contractVersion: 1,
|
|
241
|
-
promptVersion: PROMPT_VERSION,
|
|
242
|
-
schemaVersion: SCHEMA_VERSION,
|
|
243
|
-
signal: options.signal,
|
|
244
|
-
isCurrent: () => options.scope.active && options.isCurrent(),
|
|
245
|
-
priority: "background"
|
|
246
|
-
}), aborted]);
|
|
247
|
-
} finally {
|
|
248
|
-
settled = true;
|
|
249
|
-
}
|
|
250
253
|
options.signal.throwIfAborted();
|
|
251
|
-
if (!options.
|
|
252
|
-
if (result.receipt.status === "cancelled" || result.receipt.status === "superseded") throw Object.assign(/* @__PURE__ */ new Error("dsh-current-title: generation did not complete"), { code: result.receipt.status });
|
|
254
|
+
if (!options.isCurrent()) throw Object.assign(/* @__PURE__ */ new Error("dsh-current-title: generation is no longer current"), { code: "superseded" });
|
|
253
255
|
const title = normalizeSessionTitle(formatTitle(parseModelTitle(result.text, options.config.targetWords, options.config.targetCjkCharacters), locale, options.now ?? /* @__PURE__ */ new Date()), options.config.maxTitleBytes);
|
|
254
256
|
if (!title) throw new Error("dsh-current-title: title model returned an empty summary");
|
|
255
|
-
const route = result.receipt.route;
|
|
256
257
|
return {
|
|
257
258
|
title,
|
|
258
259
|
messageSeqs: selected.map((message) => message.seq),
|
|
259
|
-
|
|
260
|
-
provider:
|
|
261
|
-
model:
|
|
262
|
-
}
|
|
260
|
+
model: {
|
|
261
|
+
provider: result.provider,
|
|
262
|
+
model: result.model
|
|
263
|
+
},
|
|
263
264
|
sourceVersion
|
|
264
265
|
};
|
|
265
266
|
}
|
|
@@ -343,7 +344,7 @@ function createNativeTitleSlot(options) {
|
|
|
343
344
|
async occupy(id) {
|
|
344
345
|
const provider = {
|
|
345
346
|
id: PROVIDER_ID,
|
|
346
|
-
automatic:
|
|
347
|
+
automatic: options.automatic(),
|
|
347
348
|
generate: options.generate
|
|
348
349
|
};
|
|
349
350
|
try {
|
|
@@ -381,29 +382,69 @@ function createNativeTitleSlot(options) {
|
|
|
381
382
|
}
|
|
382
383
|
//#endregion
|
|
383
384
|
//#region src/storage.ts
|
|
385
|
+
const localeSchema = z.enum([
|
|
386
|
+
"auto",
|
|
387
|
+
"zh",
|
|
388
|
+
"en"
|
|
389
|
+
]);
|
|
390
|
+
/** Version 1 stored only the locale. Prompt and model are filled as defaults. */
|
|
391
|
+
const legacySettingsSchema = z.object({
|
|
392
|
+
revision: z.number().int().nonnegative(),
|
|
393
|
+
locale: localeSchema
|
|
394
|
+
}).strict();
|
|
395
|
+
const modelRouteSchema = z.object({
|
|
396
|
+
provider: z.string(),
|
|
397
|
+
model: z.string(),
|
|
398
|
+
reasoningEffort: z.string().optional()
|
|
399
|
+
}).strict();
|
|
384
400
|
const titleSettingsSchema = z.object({
|
|
385
401
|
revision: z.number().int().nonnegative(),
|
|
386
|
-
locale:
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
])
|
|
402
|
+
locale: localeSchema,
|
|
403
|
+
prompt: z.string(),
|
|
404
|
+
model: modelRouteSchema,
|
|
405
|
+
/** Defaulted so rows stored before the cadence switch existed still parse. */
|
|
406
|
+
cadence: z.enum(["all-prompts", "first-prompt"]).default("all-prompts")
|
|
391
407
|
}).strict();
|
|
392
408
|
const titleDomain = defineDomain({
|
|
393
409
|
name: "dsh_editor_current_title",
|
|
394
|
-
version:
|
|
410
|
+
version: 2,
|
|
395
411
|
tables: { settings: domainTable(titleSettingsSchema) }
|
|
396
412
|
});
|
|
397
413
|
function parseTitleSettings(value) {
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
414
|
+
const current = titleSettingsSchema.safeParse(value);
|
|
415
|
+
if (current.success) return {
|
|
416
|
+
revision: current.data.revision,
|
|
417
|
+
locale: isTitleLocaleMode(current.data.locale) ? current.data.locale : "auto",
|
|
418
|
+
prompt: normalizePrompt(current.data.prompt),
|
|
419
|
+
model: normalizeModelRoute(current.data.model),
|
|
420
|
+
cadence: normalizeCadence(current.data.cadence)
|
|
421
|
+
};
|
|
422
|
+
const legacy = legacySettingsSchema.safeParse(value);
|
|
423
|
+
if (!legacy.success || !isTitleLocaleMode(legacy.data.locale)) return void 0;
|
|
424
|
+
return {
|
|
425
|
+
revision: legacy.data.revision,
|
|
426
|
+
locale: legacy.data.locale,
|
|
427
|
+
prompt: "",
|
|
428
|
+
model: defaultModelRoute(),
|
|
429
|
+
cadence: "all-prompts"
|
|
430
|
+
};
|
|
402
431
|
}
|
|
403
432
|
function storedSettings(value, _fallbackLocale = "auto") {
|
|
433
|
+
const parsed = parseTitleSettings(value);
|
|
404
434
|
return {
|
|
405
|
-
revision:
|
|
406
|
-
locale: "auto"
|
|
435
|
+
revision: parsed?.revision ?? 0,
|
|
436
|
+
locale: "auto",
|
|
437
|
+
prompt: parsed?.prompt ?? "",
|
|
438
|
+
model: parsed?.model ?? defaultModelRoute(),
|
|
439
|
+
cadence: parsed?.cadence ?? "all-prompts"
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function settingsPatch(current, patch) {
|
|
443
|
+
return {
|
|
444
|
+
locale: "auto",
|
|
445
|
+
prompt: patch.prompt === void 0 ? current.prompt : normalizePrompt(patch.prompt),
|
|
446
|
+
model: patch.model === void 0 ? current.model : normalizeModelRoute(patch.model),
|
|
447
|
+
cadence: patch.cadence === void 0 ? current.cadence : normalizeCadence(patch.cadence)
|
|
407
448
|
};
|
|
408
449
|
}
|
|
409
450
|
//#endregion
|
|
@@ -412,11 +453,11 @@ var CurrentTitleService = class {
|
|
|
412
453
|
options;
|
|
413
454
|
settings;
|
|
414
455
|
config;
|
|
415
|
-
scope;
|
|
416
|
-
unregisterPurpose;
|
|
417
456
|
claim;
|
|
418
457
|
nativeSlot;
|
|
419
458
|
generation = 0;
|
|
459
|
+
settingsPending = Promise.resolve();
|
|
460
|
+
disposed = false;
|
|
420
461
|
inFlight = /* @__PURE__ */ new Map();
|
|
421
462
|
support;
|
|
422
463
|
constructor(options) {
|
|
@@ -430,17 +471,16 @@ var CurrentTitleService = class {
|
|
|
430
471
|
};
|
|
431
472
|
}
|
|
432
473
|
async start() {
|
|
433
|
-
const {
|
|
434
|
-
if (!
|
|
474
|
+
const { llm, sessionTitle, loader, sessions } = this.options;
|
|
475
|
+
if (!llm || !sessionTitle?.register || !sessions || !loader) {
|
|
435
476
|
this.support.weOwn = false;
|
|
436
477
|
this.support.limitation = "required host services are missing";
|
|
437
478
|
return;
|
|
438
479
|
}
|
|
439
|
-
this.scope = ai.activate(this.options.plugin);
|
|
440
|
-
this.unregisterPurpose = registerTitlePurpose(this.scope);
|
|
441
480
|
this.nativeSlot = createNativeTitleSlot({
|
|
442
481
|
sessionTitle,
|
|
443
482
|
loader,
|
|
483
|
+
automatic: () => this.settings.cadence,
|
|
444
484
|
generate: (request) => this.nativeGenerate(request)
|
|
445
485
|
});
|
|
446
486
|
try {
|
|
@@ -455,9 +495,11 @@ var CurrentTitleService = class {
|
|
|
455
495
|
}
|
|
456
496
|
}
|
|
457
497
|
async dispose() {
|
|
498
|
+
this.disposed = true;
|
|
458
499
|
this.generation += 1;
|
|
459
500
|
for (const controller of this.inFlight.values()) controller.abort(/* @__PURE__ */ new Error("current-title disabled"));
|
|
460
501
|
this.inFlight.clear();
|
|
502
|
+
await this.settingsPending;
|
|
461
503
|
const snapshot = this.nativeSlot?.displacement;
|
|
462
504
|
const outcome = await releaseTitleSlot(this.nativeSlot ?? {
|
|
463
505
|
owner: () => void 0,
|
|
@@ -468,16 +510,15 @@ var CurrentTitleService = class {
|
|
|
468
510
|
this.support.weOwn = false;
|
|
469
511
|
this.support.nativeOwner = this.nativeSlot?.owner() ?? null;
|
|
470
512
|
if (outcome === "left-other-owner") this.support.limitation = "another title provider owns the slot; previous owner was not restored";
|
|
471
|
-
this.unregisterPurpose?.();
|
|
472
|
-
this.unregisterPurpose = void 0;
|
|
473
|
-
this.scope?.dispose();
|
|
474
|
-
this.scope = void 0;
|
|
475
513
|
}
|
|
476
514
|
status(sessionId) {
|
|
477
515
|
const session = sessionId && this.options.sessions ? this.options.sessions.get(sessionId) : void 0;
|
|
478
516
|
const snapshot = session ? this.read(session) : void 0;
|
|
479
517
|
return {
|
|
480
|
-
settings: {
|
|
518
|
+
settings: {
|
|
519
|
+
...this.settings,
|
|
520
|
+
model: { ...this.settings.model }
|
|
521
|
+
},
|
|
481
522
|
support: {
|
|
482
523
|
...this.support,
|
|
483
524
|
nativeOwner: this.nativeSlot?.owner() ?? this.support.nativeOwner
|
|
@@ -491,19 +532,54 @@ var CurrentTitleService = class {
|
|
|
491
532
|
} } : {}
|
|
492
533
|
};
|
|
493
534
|
}
|
|
535
|
+
async updateSettings(patch) {
|
|
536
|
+
patch = structuredClone(patch);
|
|
537
|
+
const result = this.settingsPending.then(async () => {
|
|
538
|
+
if (this.disposed) throw Object.assign(/* @__PURE__ */ new Error("current-title disabled"), { code: "unavailable" });
|
|
539
|
+
if (this.settings.revision !== patch.expectedRevision) throw Object.assign(/* @__PURE__ */ new Error("current-title settings changed"), { code: "revision" });
|
|
540
|
+
const previous = this.settings;
|
|
541
|
+
const next = {
|
|
542
|
+
revision: this.settings.revision + 1,
|
|
543
|
+
...settingsPatch(this.settings, patch)
|
|
544
|
+
};
|
|
545
|
+
if (this.options.store) await this.options.store.save(next);
|
|
546
|
+
this.settings = next;
|
|
547
|
+
this.config = {
|
|
548
|
+
...this.config,
|
|
549
|
+
locale: "auto"
|
|
550
|
+
};
|
|
551
|
+
if (!this.disposed && next.cadence !== previous.cadence) await this.reclaimWithCadence();
|
|
552
|
+
return {
|
|
553
|
+
revision: next.revision,
|
|
554
|
+
locale: next.locale,
|
|
555
|
+
prompt: next.prompt,
|
|
556
|
+
model: { ...next.model },
|
|
557
|
+
cadence: next.cadence
|
|
558
|
+
};
|
|
559
|
+
});
|
|
560
|
+
this.settingsPending = result.then(() => {}, () => {});
|
|
561
|
+
return result;
|
|
562
|
+
}
|
|
563
|
+
/** Re-register the provider so a cadence change takes effect without a restart. */
|
|
564
|
+
async reclaimWithCadence() {
|
|
565
|
+
if (!this.claim || !this.nativeSlot) return;
|
|
566
|
+
const stale = this.claim;
|
|
567
|
+
this.claim = void 0;
|
|
568
|
+
await stale.dispose();
|
|
569
|
+
try {
|
|
570
|
+
this.claim = await claimTitleSlot(this.nativeSlot, PROVIDER_ID);
|
|
571
|
+
this.support.weOwn = true;
|
|
572
|
+
this.support.nativeOwner = PROVIDER_ID;
|
|
573
|
+
delete this.support.limitation;
|
|
574
|
+
} catch (error) {
|
|
575
|
+
this.support.weOwn = false;
|
|
576
|
+
this.support.nativeOwner = this.nativeSlot.owner() ?? null;
|
|
577
|
+
this.support.limitation = error instanceof Error ? error.message : "native title provider slot is occupied";
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/** @deprecated Locale is always auto. Kept so older clients still save a revision. */
|
|
494
581
|
async updateLocale(_locale, expectedRevision) {
|
|
495
|
-
|
|
496
|
-
const next = {
|
|
497
|
-
revision: this.settings.revision + 1,
|
|
498
|
-
locale: "auto"
|
|
499
|
-
};
|
|
500
|
-
if (this.options.store) await this.options.store.save(next);
|
|
501
|
-
this.settings = next;
|
|
502
|
-
this.config = {
|
|
503
|
-
...this.config,
|
|
504
|
-
locale: "auto"
|
|
505
|
-
};
|
|
506
|
-
return { ...this.settings };
|
|
582
|
+
return this.updateSettings({ expectedRevision });
|
|
507
583
|
}
|
|
508
584
|
async regenerate(sessionId, signal) {
|
|
509
585
|
if (!this.support.weOwn) throw Object.assign(/* @__PURE__ */ new Error("title provider is inactive"), { code: "unavailable" });
|
|
@@ -528,19 +604,16 @@ var CurrentTitleService = class {
|
|
|
528
604
|
};
|
|
529
605
|
}
|
|
530
606
|
async nativeGenerate(request) {
|
|
531
|
-
const
|
|
532
|
-
if (!
|
|
607
|
+
const llm = this.options.llm;
|
|
608
|
+
if (!llm) throw new Error("dsh-current-title: llm is not available");
|
|
533
609
|
const generation = this.generation;
|
|
534
610
|
const controller = new AbortController();
|
|
535
611
|
this.inFlight.get(request.session.id)?.abort(/* @__PURE__ */ new Error("newer title generation superseded older work"));
|
|
536
612
|
this.inFlight.set(request.session.id, controller);
|
|
537
613
|
try {
|
|
538
|
-
const combined = AbortSignal.any([
|
|
539
|
-
request.signal,
|
|
540
|
-
controller.signal,
|
|
541
|
-
scope.signal
|
|
542
|
-
]);
|
|
614
|
+
const combined = AbortSignal.any([request.signal, controller.signal]);
|
|
543
615
|
const session = this.options.sessions?.get(request.session.id);
|
|
616
|
+
if (isSubagentSession(session)) throw Object.assign(/* @__PURE__ */ new Error("dsh-current-title: delegated child thread keeps the host fallback title"), { code: "subagent-session" });
|
|
544
617
|
const messages = collectHumanMessages(request.messages.map((message) => ({
|
|
545
618
|
type: "user/message",
|
|
546
619
|
seq: message.seq,
|
|
@@ -553,13 +626,16 @@ var CurrentTitleService = class {
|
|
|
553
626
|
}
|
|
554
627
|
})));
|
|
555
628
|
const generated = await generateCurrentTitle({
|
|
556
|
-
|
|
629
|
+
llm,
|
|
630
|
+
host: this.options.host ?? {},
|
|
557
631
|
config: this.config,
|
|
558
632
|
sessionId: request.session.id,
|
|
559
633
|
messages: messages.length > 0 ? messages : [...request.messages],
|
|
634
|
+
prompt: this.settings.prompt,
|
|
635
|
+
model: this.settings.model,
|
|
560
636
|
localePreference: this.options.localePreference?.(),
|
|
561
637
|
signal: combined,
|
|
562
|
-
isCurrent: () => this.generation === generation &&
|
|
638
|
+
isCurrent: () => this.generation === generation && this.support.weOwn && (!session || this.options.sessions?.get(request.session.id) === session),
|
|
563
639
|
now: this.options.now?.()
|
|
564
640
|
});
|
|
565
641
|
return {
|
|
@@ -590,17 +666,22 @@ async function handleRpc(service, endpoint, payload, signal) {
|
|
|
590
666
|
value: service.status(typeof body.sessionId === "string" ? body.sessionId : void 0)
|
|
591
667
|
};
|
|
592
668
|
if (endpoint === "settings") {
|
|
593
|
-
if (
|
|
669
|
+
if (typeof body.expectedRevision !== "number") return {
|
|
594
670
|
ok: false,
|
|
595
671
|
error: {
|
|
596
672
|
code: "bad-request",
|
|
597
|
-
message: "
|
|
673
|
+
message: "标题设置无效。"
|
|
598
674
|
}
|
|
599
675
|
};
|
|
600
676
|
try {
|
|
601
677
|
return {
|
|
602
678
|
ok: true,
|
|
603
|
-
value: await service.
|
|
679
|
+
value: await service.updateSettings({
|
|
680
|
+
...body.prompt !== void 0 ? { prompt: body.prompt } : {},
|
|
681
|
+
...body.model !== void 0 ? { model: body.model } : {},
|
|
682
|
+
...body.cadence !== void 0 ? { cadence: body.cadence } : {},
|
|
683
|
+
expectedRevision: body.expectedRevision
|
|
684
|
+
})
|
|
604
685
|
};
|
|
605
686
|
} catch (error) {
|
|
606
687
|
const code = error instanceof Error && "code" in error ? String(error.code) : "failed";
|
|
@@ -678,7 +759,7 @@ async function handleRpc(service, endpoint, payload, signal) {
|
|
|
678
759
|
const name = PLUGIN_NAME;
|
|
679
760
|
const inject = [
|
|
680
761
|
"sessionTitle",
|
|
681
|
-
"
|
|
762
|
+
"llm",
|
|
682
763
|
"sessions",
|
|
683
764
|
"loader",
|
|
684
765
|
"storageDomain",
|
|
@@ -692,7 +773,8 @@ async function apply(ctx, config = {}) {
|
|
|
692
773
|
const locale = isTitleLocaleMode(config.locale) ? config.locale : "auto";
|
|
693
774
|
const service = new CurrentTitleService({
|
|
694
775
|
plugin: PLUGIN_NAME,
|
|
695
|
-
|
|
776
|
+
llm: host.llm,
|
|
777
|
+
host,
|
|
696
778
|
sessionTitle: host.sessionTitle,
|
|
697
779
|
loader: host.loader,
|
|
698
780
|
sessions: host.sessions,
|