dsh-selfnote 0.13.3 → 0.14.0
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 +129 -32
- package/lib/capture-run.js +17 -1
- package/lib/client.js +285 -8
- package/lib/corrections.js +353 -0
- package/lib/index-store.js +14 -5
- package/lib/index.js +561 -75
- package/lib/persona-tx.js +308 -0
- package/lib/persona.js +248 -0
- package/lib/transfer.js +40 -2
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -160,6 +160,24 @@ window.__ModuleLoader__.load({
|
|
|
160
160
|
var draftTierTuple = useState('stable')
|
|
161
161
|
var draftTier = draftTierTuple[0]
|
|
162
162
|
var setDraftTier = draftTierTuple[1]
|
|
163
|
+
// 临时自述的保质期(天)。只对 temp 型生效,核心与稳定永不过期
|
|
164
|
+
// 同样放最后:新增 useState 只能往后加,别插在中间
|
|
165
|
+
var tempTtlTuple = useState('')
|
|
166
|
+
var tempTtl = tempTtlTuple[0]
|
|
167
|
+
var setTempTtl = tempTtlTuple[1]
|
|
168
|
+
// 人格三段的草稿:null = 直接显示磁盘上的,动过之后才是草稿。
|
|
169
|
+
// 依旧放最后:新增 useState 只能往后加,插在中间会让测试的调用序号错位
|
|
170
|
+
var personaDraftTuple = useState(null)
|
|
171
|
+
var personaDraft = personaDraftTuple[0]
|
|
172
|
+
var setPersonaDraft = personaDraftTuple[1]
|
|
173
|
+
// 纠偏候选里勾了哪几条:只存 id,不存整条(刷新后按 id 找得到才算数)
|
|
174
|
+
var pickedEvidenceTuple = useState([])
|
|
175
|
+
var pickedEvidence = pickedEvidenceTuple[0]
|
|
176
|
+
var setPickedEvidence = pickedEvidenceTuple[1]
|
|
177
|
+
// 用选中的证据写规则时的那段草稿:预填证据原文,要人改写成规则
|
|
178
|
+
var ruleDraftTuple = useState('')
|
|
179
|
+
var ruleDraft = ruleDraftTuple[0]
|
|
180
|
+
var setRuleDraft = ruleDraftTuple[1]
|
|
163
181
|
|
|
164
182
|
function apply(data) {
|
|
165
183
|
setState(data)
|
|
@@ -170,6 +188,7 @@ window.__ModuleLoader__.load({
|
|
|
170
188
|
setMaxEntries(String(data.maxEntries))
|
|
171
189
|
setNoteGuide(typeof data.noteGuide === 'string' ? data.noteGuide : '')
|
|
172
190
|
setHeading(typeof data.heading === 'string' ? data.heading : '')
|
|
191
|
+
setTempTtl(String(data.tempTtlDays === undefined ? 14 : data.tempTtlDays))
|
|
173
192
|
// 每次拿到新状态,列表下标都可能整体挪位:正在改/正等确认的那条已经没意义了
|
|
174
193
|
setEditing(null)
|
|
175
194
|
setPendingDelete(null)
|
|
@@ -282,6 +301,139 @@ window.__ModuleLoader__.load({
|
|
|
282
301
|
})
|
|
283
302
|
}
|
|
284
303
|
|
|
304
|
+
function saveTempTtl() {
|
|
305
|
+
var value = Number(tempTtl)
|
|
306
|
+
if (!Number.isFinite(value) || value < 1 || value > 90) {
|
|
307
|
+
setNotice({ tone: 'warn', text: '保质期要在 1–90 天之间。' })
|
|
308
|
+
return
|
|
309
|
+
}
|
|
310
|
+
setBusy('ttl')
|
|
311
|
+
apiPost('/config', { tempTtlDays: value })
|
|
312
|
+
.then(function (data) {
|
|
313
|
+
apply(data)
|
|
314
|
+
setNotice({ tone: 'ok', text: '保质期改成 ' + Math.round(value) + ' 天,下一回合生效。' })
|
|
315
|
+
})
|
|
316
|
+
.catch(function (error) {
|
|
317
|
+
setNotice({ tone: 'warn', text: '保存失败:' + error.message })
|
|
318
|
+
})
|
|
319
|
+
.then(function () {
|
|
320
|
+
setBusy('')
|
|
321
|
+
})
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ---- 人格三段 ----
|
|
325
|
+
// 字数按 Unicode 码点算,和服务端、注入预算同一把尺子。
|
|
326
|
+
// 注意:视觉上的一个 emoji 可能由多个码点组成(ZWJ 序列),这里如实算多个。
|
|
327
|
+
function pinCount(text) {
|
|
328
|
+
return Array.from(String(text === undefined || text === null ? '' : text)).length
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function personaValues() { var persona = state.persona || {}
|
|
332
|
+
if (personaDraft === null) {
|
|
333
|
+
return { l0: persona.l0 || '', l1: persona.l1 || '', l2: persona.l2 || '' }
|
|
334
|
+
}
|
|
335
|
+
return personaDraft
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function editPersona(key, value) {
|
|
339
|
+
var next = { l0: personaValues().l0, l1: personaValues().l1, l2: personaValues().l2 }
|
|
340
|
+
next[key] = value
|
|
341
|
+
setPersonaDraft(next)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function sectionlessHint(info) {
|
|
345
|
+
if (!info) return ''
|
|
346
|
+
if (info.error === 'missing') return 'persona.md 还没建,保存一次就有了。'
|
|
347
|
+
if (info.error === 'not-text') return 'persona.md 不像文本(或超过 1MB),先看一眼再改。'
|
|
348
|
+
if (info.sectionless) return '整篇没写标题,暂时全部当作 L1。'
|
|
349
|
+
return 'persona.md · 上次取用 ' + (info.lastReadAt ? String(info.lastReadAt).slice(0, 10) : '从没取过')
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function personaField(key, label, hint, value, max, rows) {
|
|
353
|
+
var used = pinCount(value)
|
|
354
|
+
var over = max > 0 && used > max
|
|
355
|
+
return h(
|
|
356
|
+
'div',
|
|
357
|
+
{ className: 'sn-field sn-field-wide', key: key },
|
|
358
|
+
h(
|
|
359
|
+
'span',
|
|
360
|
+
{ className: 'sn-field-label' },
|
|
361
|
+
label,
|
|
362
|
+
h('span', { className: 'sn-count' + (over ? ' sn-count-over' : '') }, ' ' + used + ' / ' + max + ' 字'),
|
|
363
|
+
),
|
|
364
|
+
h('textarea', {
|
|
365
|
+
className: 'sn-input',
|
|
366
|
+
rows: rows,
|
|
367
|
+
// 上限就是校验线的软提示;真拦住的是保存时那一次整份校验
|
|
368
|
+
maxLength: max > 0 ? max : undefined,
|
|
369
|
+
value: value,
|
|
370
|
+
'data-field': key,
|
|
371
|
+
onChange: function (e) { editPersona(key, e.target.value) },
|
|
372
|
+
}),
|
|
373
|
+
h('div', { className: 'sn-hint' }, hint),
|
|
374
|
+
)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function savePersona() {
|
|
378
|
+
var values = personaValues()
|
|
379
|
+
setBusy('persona')
|
|
380
|
+
apiPost('/persona', {
|
|
381
|
+
l0: values.l0,
|
|
382
|
+
l1: values.l1,
|
|
383
|
+
l2: values.l2,
|
|
384
|
+
consume: pickedEvidence,
|
|
385
|
+
})
|
|
386
|
+
.then(function (data) {
|
|
387
|
+
apply(data)
|
|
388
|
+
setPersonaDraft(null)
|
|
389
|
+
setPickedEvidence([])
|
|
390
|
+
setRuleDraft('')
|
|
391
|
+
if (data.pending === true) {
|
|
392
|
+
setNotice({ tone: 'warn', text: '人格已保存,但证据记账没写完:' + (data.error || '') + '(下次启动会自动补)' })
|
|
393
|
+
} else {
|
|
394
|
+
setNotice({ tone: 'ok', text: '人格已保存,下一回合生效。' })
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
.catch(function (error) {
|
|
398
|
+
setNotice({ tone: 'warn', text: '保存失败:' + error.message })
|
|
399
|
+
})
|
|
400
|
+
.then(function () {
|
|
401
|
+
setBusy('')
|
|
402
|
+
})
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function importPersona() {
|
|
406
|
+
setBusy('import')
|
|
407
|
+
apiPost('/persona/import', {})
|
|
408
|
+
.then(function (data) {
|
|
409
|
+
// 导入≠采纳:只把结果填进三个框,人自己看、自己改、自己点保存
|
|
410
|
+
setPersonaDraft({ l0: data.l0 || '', l1: data.l1 || '', l2: data.l2 || '' })
|
|
411
|
+
if (!data.exists) setNotice({ tone: 'warn', text: '没找到可导入的 AGENT.md。' })
|
|
412
|
+
else setNotice({ tone: 'ok', text: '已从 AGENT.md 填进来(还没保存,改完再点「保存人格」)。' })
|
|
413
|
+
})
|
|
414
|
+
.catch(function (error) {
|
|
415
|
+
setNotice({ tone: 'warn', text: '导入失败:' + error.message })
|
|
416
|
+
})
|
|
417
|
+
.then(function () {
|
|
418
|
+
setBusy('')
|
|
419
|
+
})
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function toggleEvidence(id) {
|
|
423
|
+
var next = pickedEvidence.slice()
|
|
424
|
+
var at = next.indexOf(id)
|
|
425
|
+
if (at >= 0) next.splice(at, 1)
|
|
426
|
+
else next.push(id)
|
|
427
|
+
setPickedEvidence(next)
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function draftRuleFromPicked() {
|
|
431
|
+
var picked = (correctionItems || []).filter(function (item) { return pickedEvidence.indexOf(item.id) >= 0 })
|
|
432
|
+
var lines = picked.map(function (item) { return '· ' + item.quote })
|
|
433
|
+
setRuleDraft(lines.length > 0 ? lines.join('\n') : '')
|
|
434
|
+
setNotice({ tone: 'ok', text: '把上面几句改写成一条规则,再点「保存人格」。' })
|
|
435
|
+
}
|
|
436
|
+
|
|
285
437
|
function toggleEnabled() {
|
|
286
438
|
setBusy('toggle')
|
|
287
439
|
apiPost('/config', { enabled: !state.enabled })
|
|
@@ -543,6 +695,7 @@ window.__ModuleLoader__.load({
|
|
|
543
695
|
var tabs = [
|
|
544
696
|
{ key: 'overview', label: '概览' },
|
|
545
697
|
{ key: 'notes', label: '自述', badge: notes.length + ' 条' },
|
|
698
|
+
{ key: 'persona', label: '人格', badge: ((state.persona && state.persona.chars) || 0) + ' 字' },
|
|
546
699
|
{ key: 'memory', label: '记忆', badge: candidates.length > 0 ? '待审 ' + candidates.length : approvedFacts.length + ' 条' },
|
|
547
700
|
{ key: 'profile', label: '画像', badge: (state.profile ? state.profile.chars : 0) + ' 字' },
|
|
548
701
|
{ key: 'injection', label: '注入', badge: ((state.injection && state.injection.chars) || 0) + ' 字' },
|
|
@@ -567,9 +720,10 @@ window.__ModuleLoader__.load({
|
|
|
567
720
|
}
|
|
568
721
|
|
|
569
722
|
var budget = state.budget || {}
|
|
570
|
-
var limit = budget.limit ||
|
|
571
|
-
var caps = budget.caps || { notes: 200, profile:
|
|
723
|
+
var limit = budget.limit || 1000
|
|
724
|
+
var caps = budget.caps || { persona: 320, notes: 200, profile: 120, env: 230, facts: 90, habits: 40 }
|
|
572
725
|
var segments = [
|
|
726
|
+
{ key: 'persona', label: '人格', value: budget.persona || 0, color: '#f97316' },
|
|
573
727
|
{ key: 'notes', label: '自述', value: budget.notes || 0, color: '#60a5fa' },
|
|
574
728
|
{ key: 'profile', label: '画像', value: budget.profile || 0, color: '#a78bfa' },
|
|
575
729
|
// 环境段是最大的一块(上限 320 字),漏了它进度条就画不满:
|
|
@@ -676,7 +830,7 @@ window.__ModuleLoader__.load({
|
|
|
676
830
|
type: 'text',
|
|
677
831
|
maxLength: 24,
|
|
678
832
|
value: heading,
|
|
679
|
-
placeholder: '
|
|
833
|
+
placeholder: '例:AI记忆',
|
|
680
834
|
onChange: function (e) { setHeading(e.target.value) },
|
|
681
835
|
}),
|
|
682
836
|
),
|
|
@@ -688,6 +842,13 @@ window.__ModuleLoader__.load({
|
|
|
688
842
|
h('button', { className: 'sn-btn sn-btn-ghost', onClick: saveHeading, disabled: busy !== '' }, '保存抬头'),
|
|
689
843
|
),
|
|
690
844
|
h('div', { className: 'sn-hint' }, '上次写入:' + lastWriteText(state.notesLastWrite)),
|
|
845
|
+
h(
|
|
846
|
+
'div',
|
|
847
|
+
{ className: 'sn-limits' },
|
|
848
|
+
h('label', { className: 'sn-field' }, h('span', null, '临时自述保质期(天)'), h('input', { type: 'number', min: 1, max: 90, value: tempTtl, onChange: function (e) { setTempTtl(e.target.value) } })),
|
|
849
|
+
h('button', { className: 'sn-btn', onClick: saveTempTtl, disabled: busy !== '' }, '保存保质期'),
|
|
850
|
+
),
|
|
851
|
+
h('div', { className: 'sn-hint' }, '只对「临时」型自述生效(1–90 天,默认 14)。过了期不再自动进上下文,内容一个字都没删 —— 改成「稳定」或重写一条就回来。'),
|
|
691
852
|
h(
|
|
692
853
|
'div',
|
|
693
854
|
{ className: 'sn-field sn-field-wide' },
|
|
@@ -1076,7 +1237,7 @@ window.__ModuleLoader__.load({
|
|
|
1076
1237
|
{
|
|
1077
1238
|
className: 'sn-tier',
|
|
1078
1239
|
value: draftTier,
|
|
1079
|
-
title: '
|
|
1240
|
+
title: '核心=身份素材(不进每回合注入,只作提炼人格的原料);稳定=表达习惯与工作偏好(先装,★ 优先);临时=当前阶段在做什么',
|
|
1080
1241
|
onChange: function (e) { setDraftTier(e.target.value) },
|
|
1081
1242
|
},
|
|
1082
1243
|
h('option', { value: 'core' }, '核心身份'),
|
|
@@ -1103,7 +1264,7 @@ window.__ModuleLoader__.load({
|
|
|
1103
1264
|
h(
|
|
1104
1265
|
'div',
|
|
1105
1266
|
{ className: 'sn-hint' },
|
|
1106
|
-
'
|
|
1267
|
+
'只装「稳定(★ 钉住的先装)」和「临时」,合计 ≤ ' + caps.notes + ' 字。放不下的整条跳过、不截半句,注入里会留一句「另有 N 条」当门牌。改完/删完下一回合生效。',
|
|
1107
1268
|
),
|
|
1108
1269
|
h(
|
|
1109
1270
|
'div',
|
|
@@ -1147,6 +1308,13 @@ window.__ModuleLoader__.load({
|
|
|
1147
1308
|
'span',
|
|
1148
1309
|
{ className: 'sn-text' },
|
|
1149
1310
|
entry.text,
|
|
1311
|
+
entry.tier === 'core'
|
|
1312
|
+
? h(
|
|
1313
|
+
'span',
|
|
1314
|
+
{ className: 'sn-material', title: '核心身份现在是提炼人格的素材:它不再进每回合注入。要去「人格」页把要点写进 L0 / L1 才生效' },
|
|
1315
|
+
'素材(不注入)',
|
|
1316
|
+
)
|
|
1317
|
+
: null,
|
|
1150
1318
|
entry.expired === true
|
|
1151
1319
|
? h(
|
|
1152
1320
|
'span',
|
|
@@ -1245,6 +1413,106 @@ window.__ModuleLoader__.load({
|
|
|
1245
1413
|
: null,
|
|
1246
1414
|
)
|
|
1247
1415
|
|
|
1416
|
+
var persona = state.persona || {}
|
|
1417
|
+
var personaValuesNow = personaValues()
|
|
1418
|
+
var p0Chars = pinCount(personaValuesNow.l0)
|
|
1419
|
+
var p1Chars = pinCount(personaValuesNow.l1)
|
|
1420
|
+
// L0 与 L1 之间那一个换行也占 320 里的字数(与保存校验同一把尺子),
|
|
1421
|
+
// 否则界面会绿着「320 / 320」,点保存却被拒。
|
|
1422
|
+
var pGap = p0Chars > 0 && p1Chars > 0 ? 1 : 0
|
|
1423
|
+
var pTotalChars = p0Chars + p1Chars + pGap
|
|
1424
|
+
var pRestChars = Math.max(0, 320 - pTotalChars)
|
|
1425
|
+
var pL1Max = Math.max(0, 320 - Math.min(p0Chars, 80) - (p0Chars > 0 ? 1 : 0))
|
|
1426
|
+
var correctionItems = (state.corrections && state.corrections.items) || []
|
|
1427
|
+
var pickedCount = pickedEvidence.length
|
|
1428
|
+
|
|
1429
|
+
var personaCard = h(
|
|
1430
|
+
'div',
|
|
1431
|
+
{ className: 'sn-card', key: 'persona' },
|
|
1432
|
+
h('div', { className: 'sn-card-title' }, '人格三段(L0 / L1 每回合进,L2 按需取)'),
|
|
1433
|
+
h('div', { className: 'sn-hint' }, '这里只放「要是没人提醒,我就会忘」的那些。L0 和 L1 每回合都进上下文;L2 不进,只在 self_note 去取的时候出现。'),
|
|
1434
|
+
personaField('l0', 'L0 核心身份', '我是谁、和谁说话、怎么称呼。最先装;超过 80 字会被截断(并在这里标出来)。', personaValuesNow.l0, 80, 2),
|
|
1435
|
+
personaField('l1', 'L1 行为规则', '语气、回答骨架、情境优先级、禁忌边界。一行一条;装不下的整行跳过,不截半句。', personaValuesNow.l1, pL1Max, 6),
|
|
1436
|
+
h(
|
|
1437
|
+
'div',
|
|
1438
|
+
{ className: 'sn-hint' },
|
|
1439
|
+
'L0 ' + p0Chars + ' + L1 ' + p1Chars + (pGap ? ' + 换行 1' : '') + ' = ' + pTotalChars + ' / 320 字(余 ' + pRestChars + ')',
|
|
1440
|
+
),
|
|
1441
|
+
personaField('l2', 'L2 扩展设定', '外貌、服饰、世界观、兴趣。这一层不进每回合上下文;保存在同一个 persona.md 里,不占注入预算。', personaValuesNow.l2, Math.max(0, 8000 - pTotalChars), 6),
|
|
1442
|
+
h(
|
|
1443
|
+
'div',
|
|
1444
|
+
{ className: 'sn-actions' },
|
|
1445
|
+
h('button', { className: 'sn-btn', onClick: savePersona, disabled: busy !== '' }, '保存人格'),
|
|
1446
|
+
h('button', { className: 'sn-btn sn-btn-ghost', onClick: importPersona, disabled: busy !== '' }, '从 AGENT.md 导入'),
|
|
1447
|
+
h('span', { className: 'sn-grow' }),
|
|
1448
|
+
h('span', { className: 'sn-muted' }, '保存是整份校验:任一段不合格就一个字都不写。'),
|
|
1449
|
+
),
|
|
1450
|
+
|
|
1451
|
+
h('div', { className: 'sn-sub' }, '纠偏候选(' + correctionItems.length + ' 条,这些只是证据)'),
|
|
1452
|
+
h(
|
|
1453
|
+
'div',
|
|
1454
|
+
{ className: 'sn-hint' },
|
|
1455
|
+
'模型能读到它们,但你没有写入权限 —— 采纳必须由人在这儿点。勾几条 → 改写成一条规则 → 保存人格时才算用过这些证据。',
|
|
1456
|
+
),
|
|
1457
|
+
correctionItems.length === 0
|
|
1458
|
+
? h('div', { className: 'sn-empty' }, '还没攒到纠偏证据。你纠正我之后,这里会慢慢出现原话。')
|
|
1459
|
+
: h(
|
|
1460
|
+
'ul',
|
|
1461
|
+
{ className: 'sn-list' },
|
|
1462
|
+
correctionItems.map(function (item) {
|
|
1463
|
+
var picked = pickedEvidence.indexOf(item.id) >= 0
|
|
1464
|
+
return h(
|
|
1465
|
+
'li',
|
|
1466
|
+
{ key: item.id, className: 'sn-item' },
|
|
1467
|
+
h(
|
|
1468
|
+
'label',
|
|
1469
|
+
{ className: 'sn-toggle sn-evidence' },
|
|
1470
|
+
h('input', {
|
|
1471
|
+
type: 'checkbox',
|
|
1472
|
+
checked: picked,
|
|
1473
|
+
onChange: function () { toggleEvidence(item.id) },
|
|
1474
|
+
}),
|
|
1475
|
+
h('span', { className: 'sn-evidence-quote' }, item.quote),
|
|
1476
|
+
),
|
|
1477
|
+
h('span', { className: 'sn-evidence-meta' }, (item.at || '').slice(0, 10) + ' · ' + (item.session || '')),
|
|
1478
|
+
)
|
|
1479
|
+
}),
|
|
1480
|
+
),
|
|
1481
|
+
h(
|
|
1482
|
+
'div',
|
|
1483
|
+
{ className: 'sn-actions' },
|
|
1484
|
+
h('button', { className: 'sn-btn sn-btn-ghost', onClick: draftRuleFromPicked, disabled: busy !== '' }, '用选中的 ' + pickedCount + ' 条写一条规则'),
|
|
1485
|
+
),
|
|
1486
|
+
h('textarea', {
|
|
1487
|
+
className: 'sn-input',
|
|
1488
|
+
rows: 3,
|
|
1489
|
+
placeholder: '把上面几句改写成一条能照着做的规则,例如「回答时先举例,再给结论」。',
|
|
1490
|
+
value: ruleDraft,
|
|
1491
|
+
onChange: function (e) { setRuleDraft(e.target.value) },
|
|
1492
|
+
}),
|
|
1493
|
+
h(
|
|
1494
|
+
'div',
|
|
1495
|
+
{ className: 'sn-actions' },
|
|
1496
|
+
h(
|
|
1497
|
+
'button',
|
|
1498
|
+
{
|
|
1499
|
+
className: 'sn-btn',
|
|
1500
|
+
disabled: busy !== '' || ruleDraft.trim() === '',
|
|
1501
|
+
onClick: function () {
|
|
1502
|
+
var body = ruleDraft.trim()
|
|
1503
|
+
if (body === '') return
|
|
1504
|
+
var nextL1 = (personaValues().l1 + String.fromCharCode(10) + body).trim()
|
|
1505
|
+
editPersona('l1', nextL1)
|
|
1506
|
+
setNotice({ tone: 'ok', text: '规则已加进 L1 草稿,还没保存 —— 确认没问题再点「保存人格」。' })
|
|
1507
|
+
},
|
|
1508
|
+
},
|
|
1509
|
+
'加进 L1(先不进盘)',
|
|
1510
|
+
),
|
|
1511
|
+
h('span', { className: 'sn-grow' }),
|
|
1512
|
+
h('span', { className: 'sn-muted' }, sectionlessHint(persona)),
|
|
1513
|
+
),
|
|
1514
|
+
)
|
|
1515
|
+
|
|
1248
1516
|
var memoryCard = h(
|
|
1249
1517
|
'div',
|
|
1250
1518
|
{ className: 'sn-card', key: 'memory' },
|
|
@@ -1406,8 +1674,8 @@ window.__ModuleLoader__.load({
|
|
|
1406
1674
|
h(
|
|
1407
1675
|
'div',
|
|
1408
1676
|
{ className: 'sn-card-note' },
|
|
1409
|
-
(inj.chars || 0) + ' / ' + (inj.limit ||
|
|
1410
|
-
(inj.overhead > 0 ? '
|
|
1677
|
+
(inj.chars || 0) + ' / ' + (inj.limit || 1000) + ' 字' +
|
|
1678
|
+
(inj.overhead > 0 ? '(固定开销 ' + inj.overhead + ' 字)' : ''),
|
|
1411
1679
|
),
|
|
1412
1680
|
),
|
|
1413
1681
|
h('div', { className: 'sn-hint' }, '下面这段每回合都贴在用户消息前面。它只改变「我」看到的背景,不会出现在你的输入框里。'),
|
|
@@ -1523,6 +1791,7 @@ window.__ModuleLoader__.load({
|
|
|
1523
1791
|
var panels = {
|
|
1524
1792
|
overview: [statusBar, budgetBlock, statsRow, settingsCard, doctorCard, indexCard, filesBlock, transferCard],
|
|
1525
1793
|
notes: [writeCard, notesList],
|
|
1794
|
+
persona: [personaCard],
|
|
1526
1795
|
memory: [memoryCard],
|
|
1527
1796
|
profile: [profileCard],
|
|
1528
1797
|
injection: [injectionCard, attributionCard],
|
|
@@ -1530,6 +1799,7 @@ window.__ModuleLoader__.load({
|
|
|
1530
1799
|
var panelHints = {
|
|
1531
1800
|
overview: '注入开关、容量上限,以及索引与文件位置。',
|
|
1532
1801
|
notes: 'agent 写给自己看的话,攒多了从最旧的往 archive 挪。每一行都能改、能删。',
|
|
1802
|
+
persona: '三段人格:L0/L1 每回合都进上下文,L2 按需取。纠偏证据在这里变成规则,但必须人来拍板。',
|
|
1533
1803
|
memory: '候选、已采纳、可以升成习惯的标签;采纳只能人来点。',
|
|
1534
1804
|
profile: '从已采纳记忆聚合出的「关于你」,一句一出处。',
|
|
1535
1805
|
injection: '这一回合真的会贴进提示词的那段字,逐段拆开看谁进了、谁被挤掉。',
|
|
@@ -1556,7 +1826,7 @@ window.__ModuleLoader__.load({
|
|
|
1556
1826
|
h('li', null, h('b', null, '关于你(画像)'), ' 从「已采纳」的事实里聚合,按标签每组取最新一条,每句都能点回原句;可以手改覆盖。'),
|
|
1557
1827
|
h('li', null, h('b', null, '常驻结论'), ' 已采纳的事实里,画像没吸收到的那些。'),
|
|
1558
1828
|
h('li', null, h('b', null, '习惯'), ' 由人点出来才生效,模型自己升不了。'),
|
|
1559
|
-
h('li', { className: 'sn-intro-note' }, '每回合合计 ≤' + limit + '
|
|
1829
|
+
h('li', { className: 'sn-intro-note' }, '每回合合计 ≤' + limit + ' 字:人格 ' + caps.persona + ' / 自述 ' + caps.notes + ' / 画像 ' + caps.profile + ' / 环境 ' + caps.env + ' / 结论 ' + caps.facts + ' / 习惯 ' + caps.habits + '。放不下的那一条会跳过、不截半句。这几段的上限写死在插件里(不是设置项);检索工具不受这个限制。'),
|
|
1560
1830
|
),
|
|
1561
1831
|
),
|
|
1562
1832
|
|
|
@@ -1660,6 +1930,13 @@ window.__ModuleLoader__.load({
|
|
|
1660
1930
|
'.sn-pin{padding:2px 8px;line-height:1.6}',
|
|
1661
1931
|
'.sn-pin-on{color:#b45309;border-color:#fcd34d}',
|
|
1662
1932
|
'.sn-expired{font-size:11px;color:#9ca3af;border:1px solid #e5e7eb;border-radius:6px;padding:0 6px;margin-left:6px;white-space:nowrap}',
|
|
1933
|
+
'.sn-material{font-size:11px;color:#b45309;border:1px solid #fcd34d;background:#fffbeb;border-radius:6px;padding:0 6px;margin-left:6px;white-space:nowrap}',
|
|
1934
|
+
'.sn-field-label{display:flex;align-items:baseline;gap:4px;font-weight:600}',
|
|
1935
|
+
'.sn-count{font-size:12px;font-weight:400;color:var(--dsw-alias-text-quaternary,#9ca3af);font-variant-numeric:tabular-nums}',
|
|
1936
|
+
'.sn-count-over{color:#dc2626;font-weight:600}',
|
|
1937
|
+
'.sn-evidence{align-items:flex-start;gap:8px}',
|
|
1938
|
+
'.sn-evidence-quote{line-height:1.6}',
|
|
1939
|
+
'.sn-evidence-meta{font-size:11px;color:var(--dsw-alias-text-quaternary,#9ca3af);white-space:nowrap}',
|
|
1663
1940
|
'.sn-fact-edit{display:flex;flex-direction:column;gap:6px}',
|
|
1664
1941
|
'.sn-empty{font-size:12px;color:var(--dsw-alias-text-secondary,#9ca3af)}',
|
|
1665
1942
|
'.sn-sources{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}',
|