dsh-more 0.0.2 → 0.0.4

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.
Files changed (34) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +16 -3
  3. package/README.zh-CN.md +16 -3
  4. package/dist/client.js +1112 -152
  5. package/dist/index.js +262 -55
  6. package/dist/types/client/index.d.ts +5 -1
  7. package/dist/types/generated/host-settings-schema.d.ts +4 -0
  8. package/dist/types/generated/patch-catalog.d.ts +16 -0
  9. package/dist/types/kernel/client/activation.d.ts +2 -1
  10. package/dist/types/kernel/client/config-card.d.ts +2 -2
  11. package/dist/types/kernel/client/message-actions.d.ts +4 -0
  12. package/dist/types/kernel/client/patch.d.ts +1 -1
  13. package/dist/types/kernel/host/settings.d.ts +1 -1
  14. package/dist/types/patches/conversation-quick-navigation/client/index.d.ts +27 -0
  15. package/dist/types/patches/conversation-quick-navigation/client/navigation.d.ts +26 -0
  16. package/dist/types/patches/conversation-quick-navigation/host/index.d.ts +2 -0
  17. package/dist/types/patches/conversation-quick-navigation/shared.d.ts +1 -0
  18. package/dist/types/patches/message-delete/client/index.d.ts +1 -1
  19. package/dist/types/patches/message-delete/host/message-selection.d.ts +3 -3
  20. package/dist/types/patches/message-delete/host/projection.d.ts +26 -3
  21. package/dist/types/patches/message-edit/client/index.d.ts +1 -1
  22. package/dist/types/patches/message-edit/host/edit-continuation.d.ts +3 -3
  23. package/dist/types/patches/model-reasoning-efforts/client/index.d.ts +54 -0
  24. package/dist/types/patches/model-reasoning-efforts/host/index.d.ts +2 -0
  25. package/dist/types/patches/model-reasoning-efforts/host/validate.d.ts +13 -0
  26. package/dist/types/patches/model-reasoning-efforts/shared.d.ts +51 -0
  27. package/dist/types/platform/dsh/client/api.d.ts +2 -0
  28. package/dist/types/platform/dsh/client/message-targets.d.ts +14 -1
  29. package/dist/types/platform/dsh/client/runtime.d.ts +2 -1
  30. package/dist/types/platform/dsh/client/session-sync.d.ts +4 -2
  31. package/dist/types/platform/dsh/host/session-history.d.ts +3 -3
  32. package/dist/types/platform/dsh/host/wire.d.ts +6 -0
  33. package/dsh.plugin.json +1 -1
  34. package/package.json +64 -47
package/dist/index.js CHANGED
@@ -78,6 +78,14 @@ function verifyConfirmationToken(secret, token, expected, now = Date.now()) {
78
78
 
79
79
  // src/platform/dsh/host/wire.ts
80
80
  var MAX_BODY_BYTES = 64 * 1024;
81
+ var RawPatchResponse = class {
82
+ constructor(body, contentType) {
83
+ this.body = body;
84
+ this.contentType = contentType;
85
+ }
86
+ body;
87
+ contentType;
88
+ };
81
89
  function requireJsonContentType(req) {
82
90
  const value = req.headers["content-type"];
83
91
  const contentType = (Array.isArray(value) ? value[0] : value)?.split(";", 1)[0]?.trim().toLowerCase();
@@ -121,6 +129,15 @@ function write(res, status, body) {
121
129
  res.end(JSON.stringify(body));
122
130
  }
123
131
  function writeOk(res, value) {
132
+ if (value instanceof RawPatchResponse) {
133
+ res.writeHead(200, {
134
+ "content-type": value.contentType,
135
+ "cache-control": "no-store",
136
+ "x-content-type-options": "nosniff"
137
+ });
138
+ res.end(value.body);
139
+ return;
140
+ }
124
141
  write(res, 200, { ok: true, value });
125
142
  }
126
143
  function writeError(res, error) {
@@ -136,9 +153,8 @@ var MESSAGE_EDIT_PATCH_ID = "message-edit";
136
153
 
137
154
  // src/patches/message-edit/host/edit-continuation.ts
138
155
  import { createHash, randomUUID } from "node:crypto";
139
- import { resolveSessionPreset } from "@deepseek-ai/dsh-agent-presets";
140
156
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
141
- import { SessionId as SessionId2 } from "@deepseek-ai/dsh-session";
157
+ import { SessionId as SessionId2, SessionLogOffset, SessionSeq } from "@deepseek-ai/dsh-session";
142
158
 
143
159
  // src/platform/dsh/host/session-history.ts
144
160
  function completedTurns(events) {
@@ -216,18 +232,19 @@ function editedContent(original, text) {
216
232
  return [{ type: "text", text }, ...kept];
217
233
  }
218
234
  function inspectEditCut(session, targetSeq, editedText) {
235
+ if (!Number.isSafeInteger(targetSeq) || targetSeq < 0) throw new DshMoreError("bad-request", "\u6D88\u606F\u5E8F\u53F7\u65E0\u6548\u3002");
219
236
  const text = editedText.trim();
220
237
  if (text === "") throw new DshMoreError("bad-request", "\u7F16\u8F91\u540E\u7684\u6D88\u606F\u4E0D\u80FD\u4E3A\u7A7A\u3002");
221
238
  if (text.length > 1e5) throw new DshMoreError("bad-request", "\u7F16\u8F91\u540E\u7684\u6D88\u606F\u8FC7\u957F\u3002");
222
- const event = session.events[targetSeq];
239
+ const event = session.eventAt(SessionSeq(targetSeq));
223
240
  if (event?.type !== "user/message" || event.data.source.kind !== "user" || event.surfaceOp !== "append") {
224
241
  throw new DshMoreError("bad-request", "\u53EA\u80FD\u7F16\u8F91\u666E\u901A\u7528\u6237\u6D88\u606F\u3002");
225
242
  }
226
- const turns = completedTurns(session.events);
243
+ const turns = completedTurns(session.snapshotEvents());
227
244
  const owning = turns.find((turn) => targetSeq >= turn.startSeq && targetSeq <= turn.endSeq);
228
245
  if (owning === void 0) throw new DshMoreError("invalid-turn-range", "\u8FD9\u6761\u6D88\u606F\u6240\u5C5E\u8F6E\u6B21\u5C1A\u672A\u5B8C\u6210\u3002", 409);
229
246
  return {
230
- targetSeq,
247
+ targetSeq: event.seq,
231
248
  turn: owning.turn,
232
249
  turnStartSeq: owning.startSeq,
233
250
  laterTurnCount: turns.filter((turn) => turn.turn >= owning.turn).length,
@@ -235,17 +252,17 @@ function inspectEditCut(session, targetSeq, editedText) {
235
252
  };
236
253
  }
237
254
  function sourceMessage(session, targetSeq) {
238
- const event = session.events[targetSeq];
255
+ const event = session.eventAt(targetSeq);
239
256
  if (event?.type !== "user/message") throw new DshMoreError("bad-request", "\u7528\u6237\u6D88\u606F\u4E0D\u5B58\u5728\u3002");
240
257
  return event;
241
258
  }
242
259
  async function createEditedContinuation(ctx, sourceAgent, cut, editedText, childId = SessionId2(`session-${randomUUID()}`)) {
243
260
  const source = sourceAgent.session;
244
261
  const original = sourceMessage(source, cut.targetSeq);
245
- const presetId = resolveSessionPreset(source);
262
+ const presetId = ctx.sessionProjections.stateOf(source, "agentPreset") ?? void 0;
246
263
  const roster = ctx.get("agentPresets");
247
264
  const request = source.requestHeader()?.config;
248
- const seed = source.events.slice(0, cut.turnStartSeq);
265
+ const seed = source.snapshotEvents(SessionLogOffset(0), SessionLogOffset(cut.turnStartSeq));
249
266
  let releaseRuntimeContextReplay;
250
267
  const releaseReplay = () => {
251
268
  const release = releaseRuntimeContextReplay;
@@ -255,10 +272,11 @@ async function createEditedContinuation(ctx, sourceAgent, cut, editedText, child
255
272
  const child = await ctx.agents.create({
256
273
  sessionId: childId,
257
274
  seed,
275
+ inheritedEventCount: SessionLogOffset(seed.length),
258
276
  meta: {
259
277
  ...source.header.cwd === void 0 ? {} : { cwd: source.header.cwd },
260
278
  parentSession: source.id,
261
- seedLength: cut.turnStartSeq,
279
+ isSeeded: true,
262
280
  ...presetId === void 0 ? {} : { agentPreset: presetId }
263
281
  },
264
282
  agentOptions: {
@@ -350,9 +368,9 @@ var MESSAGE_DELETE_PATCH_ID = "message-delete";
350
368
 
351
369
  // src/patches/message-delete/host/message-selection.ts
352
370
  import { toolPairingBalancedAfter, toolPairingBalancedBefore } from "@deepseek-ai/dsh-compaction";
353
- import { isAppendSurfaceEvent } from "@deepseek-ai/dsh-session";
371
+ import { isAppendSurfaceEvent, SessionSeq as SessionSeq2 } from "@deepseek-ai/dsh-session";
354
372
  function assertDeletableTarget(session, seq) {
355
- const event = session.events[seq];
373
+ const event = session.eventAt(SessionSeq2(seq));
356
374
  if (event?.type === "user/message" && isAppendSurfaceEvent(event) && event.data.source.kind === "user") return;
357
375
  if (event?.type === "assistant/message" && isAppendSurfaceEvent(event)) return;
358
376
  throw new DshMoreError("bad-request", "\u53EA\u80FD\u5220\u9664\u4ECD\u5728\u5F53\u524D\u4E0A\u4E0B\u6587\u4E2D\u7684\u7528\u6237\u6D88\u606F\u6216\u52A9\u624B\u6D88\u606F\u3002");
@@ -360,7 +378,7 @@ function assertDeletableTarget(session, seq) {
360
378
  function selectMessageDeletion(session, targetSeq) {
361
379
  if (!Number.isSafeInteger(targetSeq) || targetSeq < 0) throw new DshMoreError("bad-request", "\u6D88\u606F\u5E8F\u53F7\u65E0\u6548\u3002");
362
380
  const nodes = [...session.surface.nodes];
363
- const targetIndex = nodes.indexOf(targetSeq);
381
+ const targetIndex = nodes.indexOf(SessionSeq2(targetSeq));
364
382
  if (targetIndex < 0) throw new DshMoreError("selection-empty", "\u8FD9\u6761\u6D88\u606F\u5DF2\u7ECF\u4E0D\u5728\u5F53\u524D\u6A21\u578B\u4E0A\u4E0B\u6587\u4E2D\u3002");
365
383
  assertDeletableTarget(session, targetSeq);
366
384
  let startIndex = targetIndex;
@@ -375,7 +393,7 @@ function selectMessageDeletion(session, targetSeq) {
375
393
  }
376
394
  const shadowedSeqs = nodes.slice(startIndex, endIndex + 1);
377
395
  if (shadowedSeqs.length === 0) throw new DshMoreError("selection-empty", "\u6CA1\u6709\u53EF\u5220\u9664\u7684\u4E0A\u4E0B\u6587\u8282\u70B9\u3002");
378
- return { targetSeq, shadowedSeqs };
396
+ return { targetSeq: SessionSeq2(targetSeq), shadowedSeqs };
379
397
  }
380
398
 
381
399
  // src/patches/message-delete/host/projection.ts
@@ -415,7 +433,7 @@ function deletionUpdate(event) {
415
433
  }
416
434
  var messageDeleteProjection = {
417
435
  key: MESSAGE_VISIBILITY_PROJECTION_KEY,
418
- schema,
436
+ stateSchema: schema,
419
437
  stateVersion: 3,
420
438
  init: () => ({ deletedSeqs: [], hiddenTrajectoryKeys: [] }),
421
439
  apply: (state, event) => {
@@ -426,14 +444,15 @@ var messageDeleteProjection = {
426
444
  if (nextSeqs.length === state.deletedSeqs.length && nextKeys.length === state.hiddenTrajectoryKeys.length) return state;
427
445
  return { deletedSeqs: nextSeqs, hiddenTrajectoryKeys: nextKeys };
428
446
  },
429
- view: (state) => state
447
+ wire: {
448
+ viewSchema: schema,
449
+ view: (state) => state
450
+ }
430
451
  };
431
452
 
432
453
  // src/patches/message-delete/host/rebuild.ts
433
454
  import { randomUUID as randomUUID3 } from "node:crypto";
434
- import { resolveSessionPreset as resolveSessionPreset2 } from "@deepseek-ai/dsh-agent-presets";
435
- import { CallId } from "@deepseek-ai/dsh-llm";
436
- import { Session, SessionId as SessionId4 } from "@deepseek-ai/dsh-session";
455
+ import { Session, SessionId as SessionId4, SessionLogOffset as SessionLogOffset2 } from "@deepseek-ai/dsh-session";
437
456
  function recordedDeletionSeqs(events) {
438
457
  const deleted = /* @__PURE__ */ new Set();
439
458
  for (const event of events) {
@@ -453,21 +472,10 @@ function recordedDeletionSeqs(events) {
453
472
  }
454
473
  return deleted;
455
474
  }
456
- function toolCalls(message) {
457
- const calls = [];
458
- for (const block of message.content) {
459
- const value = block;
460
- if (value.type !== "tool-call" || typeof value.name !== "string") continue;
461
- const callId = typeof value.id === "string" ? value.id : typeof value.callId === "string" ? value.callId : void 0;
462
- if (callId === void 0) continue;
463
- calls.push({ callId, name: value.name, arguments: typeof value.arguments === "string" ? value.arguments : "{}" });
464
- }
465
- return calls;
466
- }
467
475
  function buildCleanSeed(source, selection) {
468
- const deleted = recordedDeletionSeqs(source.events);
476
+ const deleted = recordedDeletionSeqs(source.snapshotEvents());
469
477
  for (const seq of selection.shadowedSeqs) deleted.add(seq);
470
- const survivors = source.surface.nodes.filter((seq) => !deleted.has(seq)).map((seq) => source.events[seq]).filter((event) => event !== void 0 && source.deriveEventMessage(event) !== null);
478
+ const survivors = source.surface.nodes.filter((seq) => !deleted.has(seq)).map((seq) => source.eventAt(seq)).filter((event) => event !== void 0 && source.deriveEventMessage(event) !== null);
471
479
  const rebuilt = Session.create(SessionId4(`session-rebuild-${randomUUID3()}`));
472
480
  let turn = 0;
473
481
  let step = 0;
@@ -517,14 +525,15 @@ function buildCleanSeed(source, selection) {
517
525
  ...event.data.usage === void 0 ? {} : { usage: event.data.usage }
518
526
  }, { surfaceOp: "append" });
519
527
  assistantSeen = true;
520
- for (const call of toolCalls(event.data.message)) {
521
- rebuilt.append("tool/call", { turn, step, callId: CallId(call.callId), name: call.name, arguments: call.arguments });
522
- loggedCalls.add(call.callId);
528
+ for (const call of event.data.message.content) {
529
+ if (call.type !== "tool-call") continue;
530
+ rebuilt.append("tool/call", { turn, step, callId: call.id, name: call.name, arguments: call.arguments });
531
+ loggedCalls.add(call.id);
523
532
  }
524
533
  continue;
525
534
  }
526
535
  if (event.type === "tool/result") {
527
- const callId = String(event.data.message.source.callId);
536
+ const callId = event.data.message.source.callId;
528
537
  if (!loggedCalls.has(callId)) {
529
538
  rebuilt.append("tool/call", { turn, step, callId: event.data.message.source.callId, name: "restored-tool", arguments: "{}" });
530
539
  loggedCalls.add(callId);
@@ -533,11 +542,11 @@ function buildCleanSeed(source, selection) {
533
542
  }
534
543
  }
535
544
  closeTurn();
536
- return rebuilt.events;
545
+ return rebuilt.snapshotEvents();
537
546
  }
538
547
  async function createDeletedContinuation(ctx, sourceAgent, selection, childId = SessionId4(`session-${randomUUID3()}`)) {
539
548
  const source = sourceAgent.session;
540
- const presetId = resolveSessionPreset2(source);
549
+ const presetId = ctx.sessionProjections.stateOf(source, "agentPreset") ?? void 0;
541
550
  const roster = ctx.get("agentPresets");
542
551
  const request = source.requestHeader()?.config;
543
552
  const provider = request?.provider ?? sourceAgent.options.provider;
@@ -557,10 +566,12 @@ async function createDeletedContinuation(ctx, sourceAgent, selection, childId =
557
566
  const child = await ctx.agents.create({
558
567
  sessionId: childId,
559
568
  seed,
569
+ // Rebuilt events are renumbered child-owned history, not a verbatim parent prefix.
570
+ inheritedEventCount: SessionLogOffset2(0),
560
571
  meta: {
561
572
  ...source.header.cwd === void 0 ? {} : { cwd: source.header.cwd },
562
573
  parentSession: source.id,
563
- seedLength: seed.length,
574
+ isSeeded: false,
564
575
  ...presetId === void 0 ? {} : { agentPreset: presetId }
565
576
  },
566
577
  agentOptions: {
@@ -594,7 +605,7 @@ async function createDeletedContinuation(ctx, sourceAgent, selection, childId =
594
605
 
595
606
  // src/patches/message-delete/host/index.ts
596
607
  function targetTurn(session, seq) {
597
- return completedTurns(session.events).find((turn) => seq >= turn.startSeq && seq <= turn.endSeq)?.turn ?? 0;
608
+ return completedTurns(session.snapshotEvents()).find((turn) => seq >= turn.startSeq && seq <= turn.endSeq)?.turn ?? 0;
598
609
  }
599
610
  function facts2(sessionId, session, selection, continuationSessionId) {
600
611
  const turn = targetTurn(session, selection.targetSeq);
@@ -802,7 +813,16 @@ function isoTime(value) {
802
813
  return Number.isFinite(date.getTime()) ? date.toISOString() : "\u672A\u77E5\u65F6\u95F4";
803
814
  }
804
815
  function codeFence(value, language = "") {
805
- const longest = Math.max(0, ...[...value.matchAll(/`+/g)].map((match) => match[0].length));
816
+ let longest = 0;
817
+ let current = 0;
818
+ for (let index = 0; index < value.length; index += 1) {
819
+ if (value.charCodeAt(index) === 96) {
820
+ current += 1;
821
+ if (current > longest) longest = current;
822
+ } else {
823
+ current = 0;
824
+ }
825
+ }
806
826
  const fence = "`".repeat(Math.max(3, longest + 1));
807
827
  return `${fence}${language}
808
828
  ${value}
@@ -855,7 +875,12 @@ ${jsonBlock(block)}`;
855
875
  }
856
876
  function contentMarkdown(content) {
857
877
  if (content.length === 0) return "\uFF08\u7A7A\u6D88\u606F\uFF09";
858
- return content.map(contentBlockMarkdown).filter((part) => part !== "").join("\n\n") || "\uFF08\u7A7A\u6D88\u606F\uFF09";
878
+ const parts = [];
879
+ for (const block of content) {
880
+ const part = contentBlockMarkdown(block);
881
+ if (part !== "") parts.push(part);
882
+ }
883
+ return parts.join("\n\n") || "\uFF08\u7A7A\u6D88\u606F\uFF09";
859
884
  }
860
885
  function messageSection(label, time, body) {
861
886
  return `## ${singleLine(label)}
@@ -870,9 +895,6 @@ function sourceLabel(event) {
870
895
  if (source.kind === "plugin") return `\u4E0A\u4E0B\u6587 \xB7 ${singleLine(source.plugin) || "\u63D2\u4EF6"}`;
871
896
  return "\u4E0A\u4E0B\u6587";
872
897
  }
873
- function toolCallIds(content) {
874
- return content.filter((block) => block.type === "tool-call").map((block) => String(block.id));
875
- }
876
898
  function conversationMarkdown(events, options) {
877
899
  const sections = [];
878
900
  const renderedCalls = /* @__PURE__ */ new Set();
@@ -883,7 +905,9 @@ function conversationMarkdown(events, options) {
883
905
  continue;
884
906
  }
885
907
  if (event.type === "assistant/message") {
886
- for (const callId of toolCallIds(event.data.message.content)) renderedCalls.add(callId);
908
+ for (const block of event.data.message.content) {
909
+ if (block.type === "tool-call") renderedCalls.add(String(block.id));
910
+ }
887
911
  sections.push(messageSection("\u52A9\u624B", event.time, contentMarkdown(event.data.message.content)));
888
912
  continue;
889
913
  }
@@ -943,7 +967,8 @@ function render(ctx, payload) {
943
967
  if ([...title].length > MAX_TITLE_LENGTH) throw new DshMoreError("bad-request", "\u4F1A\u8BDD\u6807\u9898\u8FC7\u957F\u3002");
944
968
  const session = requireLiveSession(ctx, sessionId);
945
969
  requireIdleAgent(ctx, sessionId, session);
946
- return conversationMarkdown(session.events, { title, sessionId });
970
+ const transcript = conversationMarkdown(session.snapshotEvents(), { title, sessionId });
971
+ return new RawPatchResponse(transcript.markdown, "text/markdown; charset=utf-8");
947
972
  }
948
973
  var hostPatch4 = {
949
974
  id: CONVERSATION_MARKDOWN_EXPORT_PATCH_ID,
@@ -952,15 +977,199 @@ var hostPatch4 = {
952
977
  })
953
978
  };
954
979
 
980
+ // src/patches/model-reasoning-efforts/shared.ts
981
+ var MODEL_REASONING_EFFORTS_PATCH_ID = "model-reasoning-efforts";
982
+ var LLM_PI_AI_SETTINGS_NAMESPACE = "llm-pi-ai";
983
+ var THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
984
+ var DEFAULT_REASONING_EFFORTS = {
985
+ low: "low",
986
+ medium: "medium",
987
+ high: "high"
988
+ };
989
+
990
+ // src/patches/model-reasoning-efforts/host/validate.ts
991
+ var LEVEL_SET = new Set(THINKING_LEVELS);
992
+ function validateReasoningEfforts(raw) {
993
+ if (raw === null || raw === void 0) return null;
994
+ if (raw === false) return false;
995
+ if (typeof raw !== "object" || Array.isArray(raw)) {
996
+ throw new DshMoreError("bad-request", "reasoningEfforts \u5FC5\u987B\u662F false\u3001\u601D\u8003\u7EA7\u522B\u5B57\u5178\u6216 null\u3002");
997
+ }
998
+ const dict = raw;
999
+ const keys = Object.keys(dict);
1000
+ if (keys.length === 0) throw new DshMoreError("bad-request", "\u81F3\u5C11\u9700\u8981\u58F0\u660E\u4E00\u4E2A\u601D\u8003\u7EA7\u522B\u3002");
1001
+ const result = {};
1002
+ let offersThinking = false;
1003
+ for (const key of keys) {
1004
+ if (!LEVEL_SET.has(key)) throw new DshMoreError("bad-request", `\u672A\u77E5\u7684\u601D\u8003\u7EA7\u522B\uFF1A${key}`);
1005
+ const value = dict[key];
1006
+ if (value === null) {
1007
+ if (key !== "off") throw new DshMoreError("bad-request", `\u601D\u8003\u7EA7\u522B ${key} \u5FC5\u987B\u586B\u5199\u7EBF\u4E0A\u503C\uFF0C\u53EA\u6709 off \u53EF\u4EE5\u4E3A\u7A7A\u3002`);
1008
+ result[key] = null;
1009
+ continue;
1010
+ }
1011
+ if (typeof value !== "string" || value.trim() === "") {
1012
+ throw new DshMoreError("bad-request", `\u601D\u8003\u7EA7\u522B ${key} \u7684\u7EBF\u4E0A\u503C\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u3002`);
1013
+ }
1014
+ result[key] = value;
1015
+ if (key !== "off") offersThinking = true;
1016
+ }
1017
+ if (!offersThinking) throw new DshMoreError("bad-request", "\u9700\u8981\u81F3\u5C11\u58F0\u660E\u4E00\u4E2A\u975E off \u7684\u601D\u8003\u7EA7\u522B\u3002");
1018
+ return result;
1019
+ }
1020
+
1021
+ // src/patches/model-reasoning-efforts/host/index.ts
1022
+ var LLM_PI_AI_NS = LLM_PI_AI_SETTINGS_NAMESPACE;
1023
+ function piAiSection(ctx) {
1024
+ const value = ctx.settings.get(LLM_PI_AI_NS);
1025
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
1026
+ const providers = value.providers;
1027
+ if (typeof providers !== "object" || providers === null || Array.isArray(providers)) return void 0;
1028
+ return { providers };
1029
+ }
1030
+ function normalizeEfforts(value) {
1031
+ if (value === false) return false;
1032
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
1033
+ return value;
1034
+ }
1035
+ function read(ctx) {
1036
+ const section = piAiSection(ctx);
1037
+ const rows = [];
1038
+ if (section !== void 0) {
1039
+ for (const [provider, profile] of Object.entries(section.providers)) {
1040
+ if (typeof profile !== "object" || profile === null || Array.isArray(profile)) continue;
1041
+ const models = profile.models;
1042
+ if (!Array.isArray(models)) continue;
1043
+ const displayName = profile.displayName;
1044
+ const providerName = typeof displayName === "string" && displayName.trim() !== "" ? displayName : provider;
1045
+ for (const model of models) {
1046
+ if (typeof model !== "object" || model === null || Array.isArray(model)) continue;
1047
+ const modelId = model.id;
1048
+ if (typeof modelId !== "string" || modelId === "") continue;
1049
+ rows.push({
1050
+ provider,
1051
+ providerName,
1052
+ modelId,
1053
+ reasoningEfforts: normalizeEfforts(model.reasoningEfforts)
1054
+ });
1055
+ }
1056
+ }
1057
+ }
1058
+ return {
1059
+ rows,
1060
+ writable: ctx.settings.writable,
1061
+ documentPath: ctx.settings.documentPath
1062
+ };
1063
+ }
1064
+ async function save(ctx, payload) {
1065
+ const provider = requireString(payload, "provider");
1066
+ const modelId = requireString(payload, "modelId");
1067
+ const reasoningEfforts = validateReasoningEfforts(payload.reasoningEfforts);
1068
+ const section = piAiSection(ctx);
1069
+ if (section === void 0) throw new DshMoreError("bad-request", "llm-pi-ai \u914D\u7F6E\u5C1A\u672A\u6CE8\u518C\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u601D\u8003\u5F3A\u5EA6\u3002");
1070
+ const profile = section.providers[provider];
1071
+ if (typeof profile !== "object" || profile === null || Array.isArray(profile)) {
1072
+ throw new DshMoreError("bad-request", `\u672A\u627E\u5230\u63D0\u4F9B\u65B9 ${provider} \u7684\u914D\u7F6E\u3002`);
1073
+ }
1074
+ const models = profile.models;
1075
+ if (!Array.isArray(models)) throw new DshMoreError("bad-request", `\u63D0\u4F9B\u65B9 ${provider} \u672A\u914D\u7F6E\u4EFB\u4F55\u6A21\u578B\u3002`);
1076
+ const index = models.findIndex((model) => {
1077
+ if (typeof model !== "object" || model === null) return false;
1078
+ return model.id === modelId;
1079
+ });
1080
+ if (index === -1) throw new DshMoreError("bad-request", `\u63D0\u4F9B\u65B9 ${provider} \u4E0B\u672A\u627E\u5230\u6A21\u578B ${modelId}\u3002`);
1081
+ const descriptor = ctx.settings.describe().find((entry) => entry.ns === LLM_PI_AI_NS);
1082
+ if (descriptor === void 0) throw new DshMoreError("bad-request", "llm-pi-ai \u914D\u7F6E\u5C1A\u672A\u6CE8\u518C\uFF0C\u65E0\u6CD5\u4FDD\u5B58\u601D\u8003\u5F3A\u5EA6\u3002");
1083
+ const user = descriptor.user;
1084
+ const userProviders = typeof user === "object" && user !== null && !Array.isArray(user) ? user.providers : void 0;
1085
+ const providers = typeof userProviders === "object" && userProviders !== null && !Array.isArray(userProviders) ? { ...userProviders } : {};
1086
+ const userProfile = providers[provider];
1087
+ const userModels = typeof userProfile === "object" && userProfile !== null && !Array.isArray(userProfile) ? userProfile.models : void 0;
1088
+ const storedModels = Array.isArray(userModels) ? [...userModels] : [];
1089
+ const storedIndex = storedModels.findIndex((model) => {
1090
+ if (typeof model !== "object" || model === null) return false;
1091
+ return model.id === modelId;
1092
+ });
1093
+ if (storedIndex === -1 && reasoningEfforts === null) {
1094
+ return { provider, modelId, reasoningEfforts };
1095
+ }
1096
+ const stored = storedIndex === -1 ? { id: modelId } : storedModels[storedIndex];
1097
+ let nextModel;
1098
+ if (reasoningEfforts === null) {
1099
+ const { reasoningEfforts: _dropped, ...rest } = stored;
1100
+ nextModel = rest;
1101
+ } else {
1102
+ nextModel = { ...stored, reasoningEfforts };
1103
+ }
1104
+ const nextModels = storedIndex === -1 ? [...storedModels, nextModel] : storedModels.map((model, modelIndex) => modelIndex === storedIndex ? nextModel : model);
1105
+ const nextProfile = {
1106
+ ...typeof userProfile === "object" && userProfile !== null && !Array.isArray(userProfile) ? userProfile : {},
1107
+ models: nextModels
1108
+ };
1109
+ const ops = [{ op: "set", path: ["providers"], value: { ...providers, [provider]: nextProfile } }];
1110
+ await ctx.settings.mutate(LLM_PI_AI_NS, ops, descriptor.revision);
1111
+ return { provider, modelId, reasoningEfforts };
1112
+ }
1113
+ async function fillDefaults(ctx) {
1114
+ const descriptor = ctx.settings.describe().find((entry) => entry.ns === LLM_PI_AI_NS);
1115
+ if (descriptor === void 0) return { filled: 0 };
1116
+ const user = descriptor.user;
1117
+ const userProviders = typeof user === "object" && user !== null && !Array.isArray(user) ? user.providers : void 0;
1118
+ const providers = typeof userProviders === "object" && userProviders !== null && !Array.isArray(userProviders) ? { ...userProviders } : {};
1119
+ let filled = 0;
1120
+ const nextProviders = { ...providers };
1121
+ for (const [route, profile] of Object.entries(providers)) {
1122
+ if (typeof profile !== "object" || profile === null || Array.isArray(profile)) continue;
1123
+ const models = profile.models;
1124
+ if (!Array.isArray(models)) continue;
1125
+ let changed = false;
1126
+ const nextModels = models.map((model) => {
1127
+ if (typeof model !== "object" || model === null) return model;
1128
+ const entry = model;
1129
+ if ("reasoningEfforts" in entry) return model;
1130
+ changed = true;
1131
+ filled += 1;
1132
+ return { ...entry, reasoningEfforts: { ...DEFAULT_REASONING_EFFORTS } };
1133
+ });
1134
+ if (!changed) continue;
1135
+ nextProviders[route] = { ...profile, models: nextModels };
1136
+ }
1137
+ if (filled === 0) return { filled: 0 };
1138
+ const ops = [{ op: "set", path: ["providers"], value: nextProviders }];
1139
+ await ctx.settings.mutate(LLM_PI_AI_NS, ops, descriptor.revision);
1140
+ return { filled };
1141
+ }
1142
+ var hostPatch5 = {
1143
+ id: MODEL_REASONING_EFFORTS_PATCH_ID,
1144
+ routes: ({ ctx }) => ({
1145
+ read: () => read(ctx),
1146
+ save: (payload) => save(ctx, payload),
1147
+ fillDefaults: () => fillDefaults(ctx)
1148
+ })
1149
+ };
1150
+
1151
+ // src/patches/conversation-quick-navigation/shared.ts
1152
+ var CONVERSATION_QUICK_NAVIGATION_PATCH_ID = "conversation-quick-navigation";
1153
+
1154
+ // src/patches/conversation-quick-navigation/host/index.ts
1155
+ var hostPatch6 = {
1156
+ id: CONVERSATION_QUICK_NAVIGATION_PATCH_ID,
1157
+ routes: () => ({
1158
+ status: () => ({ available: true })
1159
+ })
1160
+ };
1161
+
955
1162
  // src/generated/host-registry.ts
956
- var HOST_PATCHES = [hostPatch, hostPatch2, hostPatch3, hostPatch4];
1163
+ var HOST_PATCHES = [hostPatch, hostPatch2, hostPatch3, hostPatch4, hostPatch5, hostPatch6];
957
1164
 
958
1165
  // src/generated/patch-catalog.ts
959
1166
  var DEFAULT_PATCH_SETTINGS = {
960
1167
  "message-edit": true,
961
1168
  "message-delete": true,
962
1169
  "session-delete": true,
963
- "conversation-markdown-export": true
1170
+ "conversation-markdown-export": true,
1171
+ "model-reasoning-efforts": true,
1172
+ "conversation-quick-navigation": true
964
1173
  };
965
1174
 
966
1175
  // src/kernel/host/activation.ts
@@ -996,24 +1205,22 @@ var HostPatchActivation = class {
996
1205
  }
997
1206
  };
998
1207
 
999
- // src/kernel/host/settings.ts
1000
- import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
1001
-
1002
1208
  // src/generated/host-settings-schema.ts
1003
1209
  import z2 from "@deepseek-ai/schemastery";
1004
1210
  var PatchSettingsSchema = z2.object({
1005
1211
  "message-edit": z2.boolean().default(true),
1006
1212
  "message-delete": z2.boolean().default(true),
1007
1213
  "session-delete": z2.boolean().default(true),
1008
- "conversation-markdown-export": z2.boolean().default(true)
1214
+ "conversation-markdown-export": z2.boolean().default(true),
1215
+ "model-reasoning-efforts": z2.boolean().default(true),
1216
+ "conversation-quick-navigation": z2.boolean().default(true)
1009
1217
  });
1010
1218
 
1011
1219
  // src/kernel/host/settings.ts
1012
- var PATCH_SETTINGS_NAMESPACE2 = settingsNamespace(PATCH_SETTINGS_NAMESPACE);
1220
+ var PATCH_SETTINGS_NAMESPACE2 = PATCH_SETTINGS_NAMESPACE;
1013
1221
  function installPatchSettings(ctx, activation) {
1014
1222
  let source = () => DEFAULT_PATCH_SETTINGS;
1015
- activation.apply(source());
1016
- installSettingsSection(ctx, PATCH_SETTINGS_NAMESPACE2, PatchSettingsSchema, DEFAULT_PATCH_SETTINGS, {
1223
+ ctx.settings.installSection(ctx, PATCH_SETTINGS_NAMESPACE2, PatchSettingsSchema, DEFAULT_PATCH_SETTINGS, {
1017
1224
  setSource: (next) => {
1018
1225
  source = next;
1019
1226
  },
@@ -1,3 +1,7 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
+ export type {} from '@deepseek-ai/dsh-client-ui-conversation/client';
3
+ export type {} from '@deepseek-ai/dsh-client-ui-layout/client';
4
+ export type {} from '@deepseek-ai/dsh-client-ui-settings/client';
5
+ export type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client';
2
6
  export declare const inject: string[];
3
7
  export declare function apply(ctx: ClientContext): void;
@@ -4,9 +4,13 @@ export declare const PatchSettingsSchema: z<Schemastery.ObjectS<{
4
4
  "message-delete": z<boolean, boolean>;
5
5
  "session-delete": z<boolean, boolean>;
6
6
  "conversation-markdown-export": z<boolean, boolean>;
7
+ "model-reasoning-efforts": z<boolean, boolean>;
8
+ "conversation-quick-navigation": z<boolean, boolean>;
7
9
  }>, Schemastery.ObjectT<{
8
10
  "message-edit": z<boolean, boolean>;
9
11
  "message-delete": z<boolean, boolean>;
10
12
  "session-delete": z<boolean, boolean>;
11
13
  "conversation-markdown-export": z<boolean, boolean>;
14
+ "model-reasoning-efforts": z<boolean, boolean>;
15
+ "conversation-quick-navigation": z<boolean, boolean>;
12
16
  }>>;
@@ -26,6 +26,20 @@ export declare const PATCH_CATALOG: readonly [{
26
26
  readonly defaultEnabled: true;
27
27
  readonly order: 400;
28
28
  readonly clientKind: "standalone";
29
+ }, {
30
+ readonly id: "model-reasoning-efforts";
31
+ readonly name: "模型思考强度";
32
+ readonly description: "在模型配置界面为每个模型配置支持的思考强度并写入 settings.yaml 的 reasoningEfforts";
33
+ readonly defaultEnabled: true;
34
+ readonly order: 500;
35
+ readonly clientKind: "standalone";
36
+ }, {
37
+ readonly id: "conversation-quick-navigation";
38
+ readonly name: "对话快速导航";
39
+ readonly description: "自动加载完整记录,并用常驻目录快速定位当前会话中的每一轮提问";
40
+ readonly defaultEnabled: true;
41
+ readonly order: 600;
42
+ readonly clientKind: "standalone";
29
43
  }];
30
44
  export type PatchId = typeof PATCH_CATALOG[number]['id'];
31
45
  export interface PatchSettings {
@@ -33,6 +47,8 @@ export interface PatchSettings {
33
47
  "message-delete": boolean;
34
48
  "session-delete": boolean;
35
49
  "conversation-markdown-export": boolean;
50
+ "model-reasoning-efforts": boolean;
51
+ "conversation-quick-navigation": boolean;
36
52
  }
37
53
  export declare const DEFAULT_PATCH_SETTINGS: PatchSettings;
38
54
  export declare function decodePatchSettings(value: unknown): PatchSettings | undefined;
@@ -1,4 +1,5 @@
1
- import type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
2
+ import type { SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client';
2
3
  import { type PatchId, type PatchSettings } from '../../generated/patch-catalog.js';
3
4
  export interface PatchActivationSource {
4
5
  getSnapshot(): PatchSettings;
@@ -1,5 +1,6 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
2
  import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
3
+ export type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client';
3
4
  import type { PatchActivationSource } from './activation.js';
4
5
  type CardProps = PropsRuntime<'settings.plugin.item'>;
5
6
  export interface PatchConfigCardProps extends CardProps {
@@ -8,4 +9,3 @@ export interface PatchConfigCardProps extends CardProps {
8
9
  }
9
10
  export declare function PatchConfigCard({ activation, initiallyOpen }: PatchConfigCardProps): JSX.Element | null;
10
11
  export declare function installPatchConfigCard(ctx: ClientContext, activation: PatchActivationSource): void;
11
- export {};
@@ -1,3 +1,7 @@
1
+ export type {} from '@deepseek-ai/dsh-client-ui-renderer/client';
2
+ export type {} from '@deepseek-ai/dsh-client-ui-session/client';
3
+ export type {} from '@deepseek-ai/dsh-client-ui-chat/client';
4
+ export type {} from '@deepseek-ai/dsh-client-ui-conversation/client';
1
5
  import type { ReactNode } from 'react';
2
6
  import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
3
7
  export type ConversationHeaderProps = PropsRuntime<'conversation.session.header.utilities'>;
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
2
  import type { PatchActivationSource } from './activation.js';
3
3
  import type { ConversationHeaderProps, MessageActions } from './message-actions.js';
4
4
  /** A self-contained client-side patch contributed to the umbrella plugin. */
@@ -1,5 +1,5 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import type { HostPatchActivation } from './activation.js';
3
- export declare const PATCH_SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace;
3
+ export declare const PATCH_SETTINGS_NAMESPACE = "dsh-more";
4
4
  /** Bind persisted DSH settings to live Host patch activation. */
5
5
  export declare function installPatchSettings(ctx: Context, activation: HostPatchActivation): void;
@@ -0,0 +1,27 @@
1
+ import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { PatchActivationSource } from '../../../kernel/client/activation.js';
3
+ import type { ClientPatch } from '../../../kernel/client/patch.js';
4
+ import { type ConversationTurnSummary } from './navigation.js';
5
+ type HeaderUtilityProps = PropsRuntime<'conversation.session.header.utilities'>;
6
+ export declare function conversationRow(root: HTMLElement, key: string): HTMLElement | null;
7
+ export declare function sessionRoot(marker: HTMLElement | null): HTMLElement | null;
8
+ export declare function conversationScrollport(marker: HTMLElement | null): HTMLElement | null;
9
+ /** The native pre-row paging control owns DSH's reader-position anchoring. */
10
+ export declare function nativeLoadOlderButton(scrollport: HTMLElement): HTMLButtonElement | null;
11
+ export declare function ConversationNavigationMenu({ turns, activeKey, hasMore, loadingOlder, autoLoadPaused, collapsed, onRetry, onToggleCollapsed, onJump, listRef, }: {
12
+ turns: readonly ConversationTurnSummary[];
13
+ activeKey: string | null;
14
+ hasMore: boolean;
15
+ loadingOlder: boolean;
16
+ autoLoadPaused: boolean;
17
+ collapsed: boolean;
18
+ onRetry: () => void;
19
+ onToggleCollapsed: () => void;
20
+ onJump: (key: string) => void;
21
+ listRef: React.RefObject<HTMLDivElement>;
22
+ }): JSX.Element;
23
+ export declare function ConversationQuickNavigation(props: HeaderUtilityProps & {
24
+ activation: PatchActivationSource;
25
+ }): JSX.Element | null;
26
+ export declare const clientPatch: ClientPatch;
27
+ export {};