dsh-tacit 0.2.1 → 0.2.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.md +15 -2
- package/client/client.js +11 -10
- package/docs/README.zh.md +2 -2
- package/lib/analyze.js +2 -2
- package/lib/service.js +7 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -25,13 +25,21 @@ Tacit: learns → "The user often omits which app they mean — check apps/web
|
|
|
25
25
|
You never have to say it again.
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
<p align="center">
|
|
29
|
+
<img alt="Install Tacit, open its conversation tab, review learning controls, and edit the directive it gives the agent" src="https://raw.githubusercontent.com/hackernotfound/dsh-tacit/main/docs/assets/tacit-demo.gif" width="960">
|
|
30
|
+
</p>
|
|
31
|
+
|
|
28
32
|
## Install — 30 seconds
|
|
29
33
|
|
|
30
34
|
```bash
|
|
31
|
-
dsh plugin --profile web add dsh-tacit
|
|
35
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-tacit
|
|
32
36
|
```
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
If `dsh` is already installed globally, `dsh plugin --profile web add dsh-tacit`
|
|
39
|
+
is the equivalent shorthand.
|
|
40
|
+
|
|
41
|
+
Start (or restart) with `npx @deepseek-ai/dsh web`, then refresh the page.
|
|
42
|
+
Optional kick-start: **Settings → Tacit →
|
|
35
43
|
*Learn from my last 20 turns*** (≈ $0.02–0.05, once).
|
|
36
44
|
|
|
37
45
|
Requires DeepSeek Harness `>= 0.1.1-rc.1`, Node `>= 22`, and a DeepSeek API key
|
|
@@ -46,6 +54,11 @@ already configured in the harness (Tacit never reads it).
|
|
|
46
54
|
| **✨ Improve** | a composer button that rewrites your current draft using what Tacit has learned, with a before/after preview and 👍/👎 | $0.001–0.002 per click |
|
|
47
55
|
| **Measured, not guessed** | Settings shows your real trend — messy-turn rate and tokens per turn, first 20 turns vs. latest 20 | free |
|
|
48
56
|
|
|
57
|
+
<p align="center">
|
|
58
|
+
<img alt="Tacit settings with automatic learning controls and an editable active directive" src="https://raw.githubusercontent.com/hackernotfound/dsh-tacit/main/docs/assets/tacit-settings.png" width="960">
|
|
59
|
+
</p>
|
|
60
|
+
<p align="center"><sub>Settings → Tacit, captured from a clean local profile with a synthetic example directive.</sub></p>
|
|
61
|
+
|
|
49
62
|
## How it works
|
|
50
63
|
|
|
51
64
|
1. Tacit keeps a small, bounded digest of every turn: the prompt, what tools ran,
|
package/client/client.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* slot, beside Chat/Trajectory) listing every turn's digest with an
|
|
13
13
|
* Analyze button and the analysis report;
|
|
14
14
|
* - a small ✨ Improve button in the composer tool row
|
|
15
|
-
* (`conversation.input.left`)
|
|
15
|
+
* (`conversation.input.left`) while it is enabled in Settings;
|
|
16
16
|
* - a before/after preview popup in `conversation.input.overlay` whose
|
|
17
17
|
* Apply action replaces the composer draft via `inputActions.setDraft`.
|
|
18
18
|
*
|
|
@@ -59,7 +59,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
59
59
|
'trigger.bootstrap': '引导',
|
|
60
60
|
'bootstrap.btn': '从我最近 20 轮中学习',
|
|
61
61
|
'bootstrap.running': '学习中… {done}/{total}',
|
|
62
|
-
'bootstrap.hint': '
|
|
62
|
+
'bootstrap.hint': '约 $0.02–0.05,一次性。已顺利完成的提示词会被跳过。',
|
|
63
63
|
'steer.enrich': '发送前补充学到的上下文(实验性,每次发送一次小调用)',
|
|
64
64
|
'steer.title': '智能体被告知的关于你的信息',
|
|
65
65
|
'steer.desc': '这些指令会注入每个新会话的系统提示词,让智能体替你补上你通常没说的内容。',
|
|
@@ -166,7 +166,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
166
166
|
'trigger.bootstrap': 'bootstrap',
|
|
167
167
|
'bootstrap.btn': 'Learn from my last 20 turns',
|
|
168
168
|
'bootstrap.running': 'Learning… {done}/{total}',
|
|
169
|
-
'bootstrap.hint': '≈ $0.02, one time. Skips prompts that already went fine on their own.',
|
|
169
|
+
'bootstrap.hint': '≈ $0.02–0.05, one time. Skips prompts that already went fine on their own.',
|
|
170
170
|
'steer.enrich': 'Add learned context before each send (experimental — one small call per send)',
|
|
171
171
|
'steer.title': 'What the agent is told about you',
|
|
172
172
|
'steer.desc': 'These directives ride every new session\'s system prompt so the agent fills in what you usually leave unsaid.',
|
|
@@ -1220,8 +1220,9 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
1220
1220
|
function PreviewOverlay(kit) {
|
|
1221
1221
|
const { t } = kit
|
|
1222
1222
|
return function PreviewOverlayView(props) {
|
|
1223
|
-
const
|
|
1224
|
-
|
|
1223
|
+
const store = props.tacitStore !== null && typeof props.tacitStore === 'object'
|
|
1224
|
+
? props.tacitStore
|
|
1225
|
+
: null
|
|
1225
1226
|
useStoreVersion(store)
|
|
1226
1227
|
if (store === null || !store.preview.open) return null
|
|
1227
1228
|
|
|
@@ -1258,7 +1259,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
1258
1259
|
}
|
|
1259
1260
|
}
|
|
1260
1261
|
|
|
1261
|
-
// ── Feedback strip (under the composer,
|
|
1262
|
+
// ── Feedback strip (under the composer, Improve enabled only) ───────────
|
|
1262
1263
|
|
|
1263
1264
|
function FeedbackStrip(kit) {
|
|
1264
1265
|
const { t } = kit
|
|
@@ -1646,11 +1647,11 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
1646
1647
|
id: 'tacit-preview',
|
|
1647
1648
|
order: 10,
|
|
1648
1649
|
locale: NS,
|
|
1649
|
-
inject: (sessionId) => ({
|
|
1650
|
+
inject: (sessionId) => ({ tacitStore: storeFor(sessionId) }),
|
|
1650
1651
|
}, (props) => h(PreviewOverlayView, props)))
|
|
1651
1652
|
|
|
1652
1653
|
// The post-apply 👍/👎 strip lives in the band UNDER the composer card
|
|
1653
|
-
// (composer.dock), only
|
|
1654
|
+
// (composer.dock), only while the Improve button is enabled.
|
|
1654
1655
|
const FeedbackStripView = FeedbackStrip(kit)
|
|
1655
1656
|
ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register({
|
|
1656
1657
|
name: 'conversation.composer.dock',
|
|
@@ -1661,8 +1662,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
1661
1662
|
}, (props) => h(FeedbackStripView, props)))
|
|
1662
1663
|
|
|
1663
1664
|
// Own Settings page under "Cost": a nav section in the Settings panel,
|
|
1664
|
-
// on its own. Reuses the coach panel
|
|
1665
|
-
// clear reports, coached prompts). Order 32 places it right after
|
|
1665
|
+
// on its own. Reuses the coach panel. Order 32 places it right after
|
|
1666
1666
|
// cost-meter's "Cost" section (order 30/31).
|
|
1667
1667
|
const SettingsSectionView = SettingsSection(kit)
|
|
1668
1668
|
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
@@ -1682,6 +1682,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
|
|
|
1682
1682
|
__test: {
|
|
1683
1683
|
css,
|
|
1684
1684
|
applyImproved,
|
|
1685
|
+
closePreview,
|
|
1685
1686
|
closeFeedback,
|
|
1686
1687
|
fadeFeedback,
|
|
1687
1688
|
rootStore,
|
package/docs/README.zh.md
CHANGED
|
@@ -29,10 +29,10 @@ Tacit: 学到 → "用户常常不说明是哪个应用——先查 apps/web。
|
|
|
29
29
|
## 安装——30 秒
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
dsh plugin --profile web add dsh-tacit
|
|
32
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-tacit
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
用 `npx @deepseek-ai/dsh web` 启动(或重启),然后刷新页面。可选的快速起步:**设置 → Tacit → *从我最近 20 轮中学习***
|
|
36
36
|
(约 $0.02–0.05,一次性)。
|
|
37
37
|
|
|
38
38
|
需要 DeepSeek Harness `>= 0.1.1-rc.1`、Node `>= 22`,以及已在 harness 里配置好的
|
package/lib/analyze.js
CHANGED
|
@@ -314,8 +314,8 @@ export const IMPROVE_REPAIR_SYSTEM_PROMPT = [
|
|
|
314
314
|
].join('\n')
|
|
315
315
|
|
|
316
316
|
/**
|
|
317
|
-
* Style-rule distillation:
|
|
318
|
-
*
|
|
317
|
+
* Style-rule distillation: fired rarely (every 3+ unreviewed 👎 reasons),
|
|
318
|
+
* capped at DISTILL_MAX_TOKENS output tokens.
|
|
319
319
|
*/
|
|
320
320
|
export const DISTILL_SYSTEM_PROMPT = [
|
|
321
321
|
'You distill user feedback into durable prompt-writing style rules for a',
|
package/lib/service.js
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* an `ok` flag and a stable error `code` the client localizes. Expected
|
|
9
9
|
* failures never throw; unexpected ones are mapped by the route layer.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Model calls are either user-triggered (analyzeTurn / improveDraft /
|
|
12
|
+
* bootstrap) or automatic analyses of messy and corrected turns, the latter
|
|
13
|
+
* capped by `autoDailyBudget`. There is no polling and no telemetry.
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
import {
|
|
@@ -285,7 +286,7 @@ export function createCoachService(ctx, store, effectiveConfig) {
|
|
|
285
286
|
* Returns the profile with fresh rules on success, the input profile on a
|
|
286
287
|
* soft no-op/failure.
|
|
287
288
|
*/
|
|
288
|
-
const maybeDistill = async (profile, provider) => {
|
|
289
|
+
const maybeDistill = async (profile, provider, sessionId) => {
|
|
289
290
|
if (profile.pendingDistill < 3 || distillInFlight) return profile
|
|
290
291
|
distillInFlight = true
|
|
291
292
|
try {
|
|
@@ -299,6 +300,7 @@ export function createCoachService(ctx, store, effectiveConfig) {
|
|
|
299
300
|
maxTokens: DISTILL_MAX_TOKENS,
|
|
300
301
|
timeoutMs: DISTILL_TIMEOUT_MS,
|
|
301
302
|
tool: DISTILL_TOOL,
|
|
303
|
+
sessionId,
|
|
302
304
|
})
|
|
303
305
|
const rules = normalizeDistillRules(text)
|
|
304
306
|
if (rules.length === 0) return profile
|
|
@@ -843,7 +845,7 @@ export function createCoachService(ctx, store, effectiveConfig) {
|
|
|
843
845
|
// Distillation also fires on user-triggered improve calls (soft, in-flight
|
|
844
846
|
// deduped, never awaited: an improve call is never blocked by it).
|
|
845
847
|
if (profile.pendingDistill >= 3) {
|
|
846
|
-
maybeDistill(profile, providerForSession(sessionId)).catch(() => {})
|
|
848
|
+
maybeDistill(profile, providerForSession(sessionId), sessionId).catch(() => {})
|
|
847
849
|
}
|
|
848
850
|
// Only trusted (or still-inexperienced) patterns reach the prompt;
|
|
849
851
|
// style rules + the last 3 verbatim down-reasons ride along for free
|
|
@@ -948,7 +950,7 @@ export function createCoachService(ctx, store, effectiveConfig) {
|
|
|
948
950
|
// user action. Awaited so the returned profile already carries the
|
|
949
951
|
// fresh style rules; a failure is soft-silent and retries later.
|
|
950
952
|
if (profile.pendingDistill >= 3) {
|
|
951
|
-
profile = await maybeDistill(profile, providerForSession(record.sessionId))
|
|
953
|
+
profile = await maybeDistill(profile, providerForSession(record.sessionId), record.sessionId)
|
|
952
954
|
}
|
|
953
955
|
return { ok: true, profile, code: '', detail: '' }
|
|
954
956
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-tacit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Tacit learns what you leave unsaid in your prompts — from messy turns and your own corrections, with zero clicks — and tells the agent how to compensate, on every turn, via a system-prompt section you can read and edit.",
|
|
5
5
|
"author": "hackernotfound",
|
|
6
6
|
"license": "MIT",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"zod": "^4.4.3"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
|
-
"react": "^
|
|
95
|
-
"react-dom": "^
|
|
94
|
+
"react": "^19.2.8",
|
|
95
|
+
"react-dom": "^19.2.8"
|
|
96
96
|
},
|
|
97
97
|
"keywords": [
|
|
98
98
|
"deepseek",
|