@istarry/dsh-assistant-profile 0.7.1 → 0.7.2

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.en.md ADDED
@@ -0,0 +1,124 @@
1
+ # Assistant Profile · dsh-assistant-profile
2
+
3
+ One **global persona** and one **long-term memory** for DeepSeek Harness: name, language, persona prompt, and a memory that rides right behind the persona in every system prompt. Install it once and every new session opens with it at the very top of the system prompt. The sidebar shows the assistant's name above New Session.
4
+
5
+ One profile, all four modes (standard / PTC / minimal / creator). No preset duplication, no mode-picker override.
6
+
7
+ ## What it does
8
+
9
+ The host half does exactly one thing: when a chat agent is created (and when a blank session is re-bound to another preset), it registers a `deployment:persona-prefix` section in that agent's **own scope**. The nearest same-named section wins, so the preset's identity line is replaced while tools, flow, and mode semantics stay untouched.
10
+
11
+ That is the same path the official subagent runtime uses for per-child personas (`dsh-subagent`'s `applyChildComposition`), which is why it works for all four presets.
12
+
13
+ The injected text looks like this (blank-line separated, each part optional):
14
+
15
+ ```
16
+ Your name is 大肥鱼.
17
+
18
+ Reply in 简体中文 throughout.
19
+
20
+ <your persona prompt…>
21
+ ```
22
+
23
+ - **Minimal mode** treats the persona as the complete system prompt (`complete: true`). The shadowing section mirrors that flag, so minimal mode's prompt becomes *only* your persona — still no tool instructions, exactly as that mode is designed.
24
+ - With all four fields empty it falls back to the preset's own text, i.e. native behaviour.
25
+ - **Subagents are left alone**: a delegated child keeps its own persona.
26
+
27
+ ## Assistant memory
28
+
29
+ One profile means one memory: a markdown document (one `- [YYYY-MM-DD HH:mm] content` line per fact) stored with the profile alongside the persona, shared by every session.
30
+
31
+ **Where it lands**: section `memory:assistant`, order 500 — after the persona (0), before the tool catalog (1000). Memory states who the user and the assistant are, which the tool descriptions then assume.
32
+
33
+ **Three ways in**:
34
+
35
+ - **The Remember button in chat**: every assistant message's action strip (beside the official like/dislike pair) gains a ✨. It opens a picker listing the session's user/assistant messages; submit and the host runs **that session's own model** once to condense the selection into a few stable facts, appending each (an identical fact only refreshes its stamp instead of piling up).
36
+ - **Settings → Agent memory**: two switches (memory / auto memory) and an editor. Hand-written edits land on save.
37
+ - **The `memory_add` tool**: registered only while both switches are on, letting the model decide what to remember mid-conversation.
38
+
39
+ Extraction is fail-closed: an offline session, a missing model configuration, or a model that returns nothing writable leaves the store untouched and reports the reason in the dialog.
40
+
41
+ ### Three pitfalls worth knowing before touching this
42
+
43
+ 1. **A plugin cannot write its own config.** `Volatile` exposes `get()` only; writes must go through the settings service (`settings.update(ns, patch)`), which persists to the profile patch and lets the loader commit the new value back into the runtime reference.
44
+ 2. **Write-backs must escape the HMR transaction.** A settings write runs inside `hmr.runExclusive`, and writing the result back opens another transaction — calling it inline throws `HMR transactions cannot be nested`. Every trigger therefore goes through `setTimeout(0)`.
45
+ 3. **Settings writes do not emit `loader/volatile-update`** (measured: the value commits into the reference, the event never fires). The mailbox is polled every 700 ms instead — one string read, one JSON check when idle.
46
+
47
+ Because `@deepseek-ai/dsh-tools` / `dsh-llm` / `dsh-session` do not resolve from the plugin directory (only `cordis` is host-provided), the tool definition and the extraction messages are hand-built to the official wire shapes rather than imported.
48
+
49
+ ## Editing the persona does not recompute history
50
+
51
+ DeepSeek context caching is prefix caching: the system prompt sits at the front, so rewriting the leading system message invalidates everything after it.
52
+
53
+ The persona text is **evaluated at every assembly**, so saving a new one changes the next request's prompt while **not touching a single byte of history**. The rest is the host's call: on a model route declaring `systemPromptUpdate: 'in-history'` (the default `deepseek-flash` entry does), the changed prompt is **appended after the cached history**, so the prefix through that history stays reusable and only the new snippet is billed as ordinary input.
54
+
55
+ The session log states the mode in `request/context`:
56
+
57
+ ```json
58
+ {"provider":"deepseek-official","model":"deepseek-flash","systemPromptUpdate":"in-history"}
59
+ ```
60
+
61
+ On a route without it (the default `deepseek-v4-pro` entry, for example) a mid-session edit costs one full cache miss from the first token. That is a route capability, not a plugin choice; if it matters, make the edit between sessions.
62
+
63
+ ## UI
64
+
65
+ - A new **Assistant Profile** row in the sidebar, right below Plugins (order 5).
66
+ - It opens a main-area page: name, language, persona prompt, a live character counter (turns warning-coloured past 2000).
67
+ - Left of Save sits the persona row: **Default 1 / 2 / 3** (a click only fills the three fields; Save still decides what sticks) plus "Save as" copies (named after the Name field, each with a small delete button); a fresh install starts on Default 3, and the row scrolls horizontally when it overflows.
68
+ - Above the New Session button: a quiet name row (first-character chip + name). It hides when the sidebar collapses to the 56px rail and updates as soon as a new name is saved.
69
+ - Defaults: name `大肥鱼`, language `中文`.
70
+
71
+ ## Where the data lives
72
+
73
+ The four fields are this plugin's profile config, read and written through the official settings channel, persisted into the profile's `cordis.patch.yml`:
74
+
75
+ ```yaml
76
+ - id: assistant-profile
77
+ name: '@istarry/dsh-assistant-profile'
78
+ config:
79
+ name: 小星
80
+ language: 简体中文
81
+ persona: 你是一个只讲证据的助理。不确定就说不确定。
82
+ ```
83
+
84
+ It travels with the profile: another profile is another persona; backing up the profile backs up the persona.
85
+
86
+ ## Install
87
+
88
+ ```bash
89
+ dsh plugin --profile <profile> add @istarry/dsh-assistant-profile
90
+ # local tarball:
91
+ dsh plugin --profile <profile> add E:/Plugin/发布版/dsh-assistant-profile/dist/istarry-dsh-assistant-profile-0.2.1.tgz
92
+ ```
93
+
94
+ Restart DSH. To remove:
95
+
96
+ ```bash
97
+ dsh plugin --profile <profile> remove @istarry/dsh-assistant-profile
98
+ ```
99
+
100
+ Leftover config lines are harmless (nothing reads them), but deleting them is tidier.
101
+
102
+ ## Relationship to dsh-agent-suite
103
+
104
+ Both shadow the same section (`deployment:persona-prefix`); **do not enable both** — the later load wins and the personas fight. Use agent-suite when you need several agents with their own personas; use this one for a single persona you carry everywhere.
105
+
106
+ ## Build
107
+
108
+ ```bash
109
+ cd tooling && pnpm install # once: tsdown + lightningcss + typescript + js-yaml
110
+ cd .. && node build.mjs # src/ → dist/ (manifest and static files included)
111
+ node build.mjs --staging # build to .build/out only
112
+ node build.mjs --check # build + dependency-contract check, no dist/ writes
113
+ ```
114
+
115
+ The host bundle inlines `js-yaml`; at runtime it only depends on `@deepseek-ai/schemastery` (declared in `dependencies`, installed into the plugin's own node_modules by pnpm). The browser bundle only `require`s module-table entries (react / ui-primitives).
116
+
117
+ Edit `src/` only; artifacts are generated.
118
+
119
+ ## Known edges
120
+
121
+ - Top-level sessions only; subagents are never injected.
122
+ - When the preset registry cannot be read, injection degrades to a plain section (no `complete` mirroring) and logs nothing.
123
+ - Saving with all three fields cleared injects nothing (native identity); a fresh install carries the Default 3 content.
124
+ - The nameplate is a DOM node inserted before the New Session button (the shell exposes no slot there); a MutationObserver puts it back if a re-render drops it.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@istarry/dsh-assistant-profile",
3
3
  "description": "助理档案:给 DSH 一份全局人格(名称 / 语言 / 人格提示词)与一份长期记忆,每个新会话的系统提示最前面都带着它;聊天里点一下就能把选中的对话提炼进记忆;侧栏「新会话」上方显示助理名;会话行菜单里可以直接删除一个会话(日志、索引、工作区登记一起)",
4
- "version": "0.7.1",
4
+ "version": "0.7.2",
5
5
  "icon": "./icon.svg",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",
@@ -44,14 +44,23 @@
44
44
  "platform": "web"
45
45
  }
46
46
  },
47
+ "scripts": {
48
+ "build": "node build.mjs",
49
+ "check": "node build.mjs --check",
50
+ "staging": "node build.mjs --staging",
51
+ "tooling": "cd tooling && pnpm install"
52
+ },
47
53
  "dependencies": {
48
54
  "@deepseek-ai/schemastery": "^3.18.1"
49
55
  },
56
+ "devDependencies": {
57
+ "js-yaml": "4.2.0"
58
+ },
50
59
  "peerDependencies": {
51
60
  "@deepseek-ai/cordis": "^4.0.1",
52
- "@deepseek-ai/dsh-agent": "^0.2.1-rc.2",
53
- "@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-rc.2",
54
- "@deepseek-ai/dsh-settings": "^0.2.1-rc.2",
55
- "@deepseek-ai/dsh-system-prompt": "^0.2.1-rc.2"
61
+ "@deepseek-ai/dsh-agent": ">=0.2.1-rc.2",
62
+ "@deepseek-ai/dsh-agent-preset-registry": ">=0.2.1-rc.2",
63
+ "@deepseek-ai/dsh-settings": ">=0.2.1-rc.2",
64
+ "@deepseek-ai/dsh-system-prompt": ">=0.2.1-rc.2"
56
65
  }
57
66
  }