@stardustlc/dsh-dream 0.10.0 → 0.12.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/CHANGELOG.md +14 -0
- package/README.en.md +4 -0
- package/README.md +4 -0
- package/docs/USAGE.en.md +2 -2
- package/docs/USAGE.md +6 -3
- package/docs/WORKBENCH.md +29 -0
- package/lib/automatic.js +3 -3
- package/lib/bridge.js +3 -1
- package/lib/client.js +2625 -2320
- package/lib/evidence.js +6 -0
- package/lib/memory.d.ts +2 -0
- package/lib/memory.js +5 -1
- package/lib/retrieval.js +2 -2
- package/lib/tools.js +31 -24
- package/lib/web-actions.js +2 -0
- package/lib/web.d.ts +1 -0
- package/lib/web.js +2 -1
- package/package.json +5 -3
- package/skills/dream-protocol/SKILL.md +10 -6
package/lib/evidence.js
CHANGED
|
@@ -56,6 +56,7 @@ export function verifyEvidence(claim, context) {
|
|
|
56
56
|
return held('quote-missing');
|
|
57
57
|
try {
|
|
58
58
|
let text;
|
|
59
|
+
let toolOutput = false;
|
|
59
60
|
if (claim.kind === 'local-artifact') {
|
|
60
61
|
if (!context.cwd || !claim.artifactPath)
|
|
61
62
|
return held('artifact-context-missing');
|
|
@@ -108,6 +109,7 @@ export function verifyEvidence(claim, context) {
|
|
|
108
109
|
return held('not-human-message');
|
|
109
110
|
if (entry.type !== 'user/message' && entry.type !== 'assistant/message' && entry.type !== 'tool/result')
|
|
110
111
|
return held('record-not-visible');
|
|
112
|
+
toolOutput = entry.type === 'tool/result';
|
|
111
113
|
text = visibleText(data.content ?? data.text ?? data.message ?? entry.data);
|
|
112
114
|
}
|
|
113
115
|
if (!normalized(text).includes(quote))
|
|
@@ -115,6 +117,10 @@ export function verifyEvidence(claim, context) {
|
|
|
115
117
|
const hash = createHash('sha256').update(text, 'utf8').digest('hex');
|
|
116
118
|
if (claim.sourceHash !== undefined && claim.sourceHash !== hash)
|
|
117
119
|
return held('source-hash-mismatch');
|
|
120
|
+
// Finding text in a webpage/mail/tool result proves occurrence, not that its
|
|
121
|
+
// instructions are independently supported. Retain the reference for review.
|
|
122
|
+
if (toolOutput)
|
|
123
|
+
return { ...base, sourceHash: hash, verificationReason: 'tool-output-observed' };
|
|
118
124
|
return { ...base, verification: 'read', sourceHash: hash, verificationReason: 'source-verified' };
|
|
119
125
|
}
|
|
120
126
|
catch {
|
package/lib/memory.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Evidence, Lesson } from './knowledge.js';
|
|
2
|
+
/** A model recommendation or an old actor-less record is not human approval. */
|
|
3
|
+
export declare function isHumanAccepted(lesson: Lesson): boolean;
|
|
2
4
|
/** A retrieval deadline is not a verification result; feedback never renews it. */
|
|
3
5
|
export declare function reviewDeadline(lesson: Lesson): number | undefined;
|
|
4
6
|
export declare function needsMemoryReview(lesson: Lesson, now?: number): boolean;
|
package/lib/memory.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** A model recommendation or an old actor-less record is not human approval. */
|
|
2
|
+
export function isHumanAccepted(lesson) {
|
|
3
|
+
return lesson.state === 'usable' && lesson.review.decision === 'accepted' && lesson.review.actor === 'human';
|
|
4
|
+
}
|
|
1
5
|
/** A retrieval deadline is not a verification result; feedback never renews it. */
|
|
2
6
|
export function reviewDeadline(lesson) {
|
|
3
7
|
const explicit = lesson.reviewAfter ? Date.parse(lesson.reviewAfter) : NaN;
|
|
@@ -16,7 +20,7 @@ export function needsMemoryReview(lesson, now = Date.now()) {
|
|
|
16
20
|
/** Derived layers contain pointers; authoritative lessons and evidence remain untouched. */
|
|
17
21
|
export function memoryDirectory(lessons, evidence, now = Date.now()) {
|
|
18
22
|
const byId = new Map(evidence.map(item => [item.id, item]));
|
|
19
|
-
const accepted = new Set(lessons.filter(
|
|
23
|
+
const accepted = new Set(lessons.filter(isHumanAccepted).map(item => item.id));
|
|
20
24
|
const entries = lessons.filter(item => item.state !== 'rejected').map(item => ({
|
|
21
25
|
lessonId: item.id, revision: item.revision, title: item.title, topic: item.kind, scope: item.scope,
|
|
22
26
|
state: item.state, reviewDue: needsMemoryReview(item, now),
|
package/lib/retrieval.js
CHANGED
|
@@ -60,6 +60,8 @@ export function queryScopeLabel(q) {
|
|
|
60
60
|
}
|
|
61
61
|
/** 经验范围文案(面板与 dream_context 共用)。 */
|
|
62
62
|
export function lessonScopeLabel(scope) {
|
|
63
|
+
if (scope.global === true)
|
|
64
|
+
return '全局';
|
|
63
65
|
const project = trimmed(scope.projectId);
|
|
64
66
|
const workspace = trimmed(scope.workspaceRoot);
|
|
65
67
|
if (project !== undefined && workspace !== undefined)
|
|
@@ -68,8 +70,6 @@ export function lessonScopeLabel(scope) {
|
|
|
68
70
|
return '项目 ' + project;
|
|
69
71
|
if (workspace !== undefined)
|
|
70
72
|
return '工作区 ' + workspace;
|
|
71
|
-
if (scope.global === true)
|
|
72
|
-
return '全局';
|
|
73
73
|
return '未限定范围';
|
|
74
74
|
}
|
|
75
75
|
/** 证据摘要(面板与 dream_context 共用):独立支持数 + 已读/仅声明 + 脱敏摘要片段。 */
|
package/lib/tools.js
CHANGED
|
@@ -9,7 +9,8 @@ import { existsSync, realpathSync } from 'node:fs';
|
|
|
9
9
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
10
10
|
import { maskSecrets } from './mask.js';
|
|
11
11
|
import { dreamStats, readDreams, saveDream, searchDreams } from './journal.js';
|
|
12
|
-
import {
|
|
12
|
+
import { isHumanAccepted } from './memory.js';
|
|
13
|
+
import { applyBridge, previewBridge, rollbackBridge, selectBridgeLessons, } from './bridge.js';
|
|
13
14
|
import { digestSessionFile, listSessionFiles } from './sessions.js';
|
|
14
15
|
import { KnowledgeError, lessonFingerprint, } from './knowledge.js';
|
|
15
16
|
import { KnowledgeStore } from './knowledge-store.js';
|
|
@@ -438,12 +439,12 @@ export function buildDreamTools(config) {
|
|
|
438
439
|
};
|
|
439
440
|
const dreamBridge = {
|
|
440
441
|
name: 'dream_bridge',
|
|
441
|
-
description: '
|
|
442
|
+
description: '渡梦:把人工采纳且适用的经验桥接进项目 AGENTS.md 的 Dream 管理块,块外内容原样保留。缺省 mode:"preview" 只读看 diff;复核后 mode:"apply" 必须带 preview.expected.sha256;mode:"rollback" 带 backupId 恢复。仅允许 review.actor=human 的已采纳经验,且 scope 匹配当前项目或经人工确认的全局范围。',
|
|
442
443
|
parameters: compileParameters({
|
|
443
|
-
mode: { type: 'string', enum: ['preview', 'apply', 'rollback'], description: 'preview
|
|
444
|
+
mode: { type: 'string', enum: ['preview', 'apply', 'rollback'], description: 'preview=只读预览(默认);apply=带 expectedSha256 落盘;rollback=按 backupId 恢复。' },
|
|
444
445
|
path: { type: 'string', description: '目标文件(可选;缺省为执行上下文 cwd 下的 AGENTS.md,取不到 cwd 会报错不猜)。' },
|
|
445
446
|
lessonIds: { type: 'array', items: { type: 'string' }, description: '参与桥接的经验 id(必须 usable 且 scope 匹配;缺省=按 store 顺序自动选取资格通过者)。' },
|
|
446
|
-
maxLessons: { type: 'integer', description: '
|
|
447
|
+
maxLessons: { type: 'integer', description: '经验上限:默认 5、硬上限 20。' },
|
|
447
448
|
expectedSha256: { oneOf: [{ type: 'string' }, { type: 'null' }], description: 'apply 必填:preview.expected.sha256 原样回传;新文件用 null;不符则 conflict 零写入。' },
|
|
448
449
|
previewId: { type: 'string', description: 'apply 可带:preview.previewId,用于校验是同一份预览;块内容不一致 → preview-mismatch,需重新 preview。' },
|
|
449
450
|
backupId: { type: 'string', description: 'rollback 必填:apply 成功返回的 backupId。' },
|
|
@@ -492,9 +493,9 @@ export function buildDreamTools(config) {
|
|
|
492
493
|
},
|
|
493
494
|
async execute(rawArgs, exec) {
|
|
494
495
|
const args = asRecord(rawArgs);
|
|
495
|
-
const mode = optionalString(args, 'mode');
|
|
496
|
-
if (mode !==
|
|
497
|
-
throw new Error('mode 必须是 preview / apply / rollback(缺省为
|
|
496
|
+
const mode = optionalString(args, 'mode') ?? 'preview';
|
|
497
|
+
if (mode !== 'preview' && mode !== 'apply' && mode !== 'rollback') {
|
|
498
|
+
throw new Error('mode 必须是 preview / apply / rollback(缺省为 preview)。');
|
|
498
499
|
}
|
|
499
500
|
const explicitPath = optionalString(args, 'path');
|
|
500
501
|
const cwd = execCwdOf(exec);
|
|
@@ -510,21 +511,6 @@ export function buildDreamTools(config) {
|
|
|
510
511
|
}
|
|
511
512
|
const resolvedPath = resolvedBridgePath(projectRoot, explicitPath);
|
|
512
513
|
const maxRaw = args.maxLessons;
|
|
513
|
-
const legacyMax = typeof maxRaw === 'number' && Number.isInteger(maxRaw) ? Math.min(30, Math.max(1, maxRaw)) : 10;
|
|
514
|
-
if (mode === undefined) {
|
|
515
|
-
const legacyTarget = explicitPath !== undefined ? resolve(explicitPath) : join(projectRoot, 'AGENTS.md');
|
|
516
|
-
const legacyResult = bridgeDreams(cfg.journalDir, legacyTarget, legacyMax);
|
|
517
|
-
return {
|
|
518
|
-
ok: true,
|
|
519
|
-
path: legacyTarget,
|
|
520
|
-
...(resolvedPath !== undefined ? { resolvedPath } : {}),
|
|
521
|
-
...legacyResult,
|
|
522
|
-
deprecation: {
|
|
523
|
-
code: 'legacy-write',
|
|
524
|
-
message: '缺省 mode 为 legacy 直写(已弃用);建议改用 mode:"preview" → 复核 diff → mode:"apply" + expectedSha256(并带同一 previewId)。',
|
|
525
|
-
},
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
514
|
const maxLessons = typeof maxRaw === 'number' && Number.isInteger(maxRaw) ? maxRaw : undefined;
|
|
529
515
|
const lessonIds = stringArray(args, 'lessonIds');
|
|
530
516
|
const projectId = optionalString(args, 'projectId');
|
|
@@ -838,7 +824,9 @@ export function buildDreamTools(config) {
|
|
|
838
824
|
return { items: [], skipped: [], scopeLabel, budget: { limit, maxChars, usedChars: 0 } };
|
|
839
825
|
}
|
|
840
826
|
const store = knowledgeStoreOf(cfg);
|
|
841
|
-
const
|
|
827
|
+
const lessons = store.listLessons().map(lesson => lesson.state === 'usable' && !isHumanAccepted(lesson)
|
|
828
|
+
? { ...lesson, state: 'candidate' } : lesson);
|
|
829
|
+
const result = retrieveLessons(lessons, store.listEvidence(), retrievalQuery);
|
|
842
830
|
const usedChars = result.items.reduce((total, item) => total + retrievedLessonChars(item), 0);
|
|
843
831
|
return { items: result.items, skipped: result.skipped, scopeLabel, budget: { limit, maxChars, usedChars } };
|
|
844
832
|
},
|
|
@@ -846,7 +834,7 @@ export function buildDreamTools(config) {
|
|
|
846
834
|
};
|
|
847
835
|
const dreamReview = {
|
|
848
836
|
name: 'dream_review',
|
|
849
|
-
description: '
|
|
837
|
+
description: '审梦:建议采纳/驳回/标记冲突或过期/追加验证证据,必须带 expectedRevision。模型的 accept 与 resolve-conflict 只返回待人工确认的建议,不修改审阅状态;请用户在设置 → Dream 中确认采纳。attach-evidence 只追加证据,不自动改变 state。',
|
|
850
838
|
parameters: compileParameters({
|
|
851
839
|
action: { type: 'string', required: true, enum: [...REVIEW_ACTIONS], description: '审阅动作。' },
|
|
852
840
|
lessonId: { type: 'string', description: '经验 ID(accept/reject/mark-*/attach-evidence 必填;resolve-conflict 可用 targetId 替代)。' },
|
|
@@ -862,6 +850,8 @@ export function buildDreamTools(config) {
|
|
|
862
850
|
schema: baseSchema,
|
|
863
851
|
render: (_args, value) => {
|
|
864
852
|
const rec = asRecord(value);
|
|
853
|
+
if (rec.requiresHumanReview === true)
|
|
854
|
+
return [{ type: 'text', text: String(rec.message) }];
|
|
865
855
|
return [{
|
|
866
856
|
type: 'text',
|
|
867
857
|
text: '经验 ' + asRecord(rec.lesson).id + ':' + rec.previousState + ' → ' + rec.state + '(revision ' + rec.revision + ')。',
|
|
@@ -899,6 +889,13 @@ export function buildDigestText(digest) {
|
|
|
899
889
|
return lines.join('\n');
|
|
900
890
|
}
|
|
901
891
|
const REVIEW_ACTIONS = ['accept', 'reject', 'reopen', 'mark-stale', 'mark-disputed', 'resolve-conflict', 'attach-evidence'];
|
|
892
|
+
function humanReviewRecommendation(before) {
|
|
893
|
+
return {
|
|
894
|
+
ok: true, requiresHumanReview: true, lesson: before,
|
|
895
|
+
previousState: before.state, state: before.state, revision: before.revision,
|
|
896
|
+
message: '已建议人工审阅,经验状态未改变。请在设置 → Dream → 经验中核对来源与适用范围,再确认采纳或处理冲突。',
|
|
897
|
+
};
|
|
898
|
+
}
|
|
902
899
|
/** actor comes from the trusted caller, never from tool or browser arguments. */
|
|
903
900
|
export async function executeDreamReview(cfg, rawArgs, exec, actor = 'model') {
|
|
904
901
|
const args = asRecord(rawArgs);
|
|
@@ -927,6 +924,11 @@ export async function executeDreamReview(cfg, rawArgs, exec, actor = 'model') {
|
|
|
927
924
|
error.details = { currentRevision: before.revision };
|
|
928
925
|
throw error;
|
|
929
926
|
}
|
|
927
|
+
if (actor === 'model' && action === 'accept')
|
|
928
|
+
return humanReviewRecommendation(before);
|
|
929
|
+
if (actor === 'human' && action === 'accept' && before.scope.global && args.confirmGlobal !== true) {
|
|
930
|
+
throw new KnowledgeError('invalid', '这是全局经验。请确认将其用于所有项目后再采纳。');
|
|
931
|
+
}
|
|
930
932
|
const affectedIdsArg = stringArray(args, 'affectedIds');
|
|
931
933
|
const conflictWith = affectedIdsArg.length > 0 ? affectedIdsArg : stringArray(args, 'conflictWith');
|
|
932
934
|
const note = optionalString(args, 'note');
|
|
@@ -1003,6 +1005,9 @@ export async function executeDreamReview(cfg, rawArgs, exec, actor = 'model') {
|
|
|
1003
1005
|
const members = requireConflictGroup(store, lessonId, before, conflictWith);
|
|
1004
1006
|
const group = members.map((member) => member.id);
|
|
1005
1007
|
// 校验:所有当事方必须 disputed,且互相登记 conflictIds;否则零写入。
|
|
1008
|
+
if (actor === 'human' && args.confirmGlobal !== true && members.some(member => member.lesson.scope.global)) {
|
|
1009
|
+
throw new KnowledgeError('invalid', '冲突涉及全局经验。请确认将结果用于所有项目后再处理。');
|
|
1010
|
+
}
|
|
1006
1011
|
for (const member of members) {
|
|
1007
1012
|
if (member.lesson.state !== 'disputed') {
|
|
1008
1013
|
throw new KnowledgeError('invalid', '冲突解析要求 ' + member.id + ' 处于 disputed(实际 ' + member.lesson.state + ')');
|
|
@@ -1015,6 +1020,8 @@ export async function executeDreamReview(cfg, rawArgs, exec, actor = 'model') {
|
|
|
1015
1020
|
}
|
|
1016
1021
|
const now = new Date().toISOString();
|
|
1017
1022
|
const affectedIds = group.filter((id) => id !== lessonId);
|
|
1023
|
+
if (actor === 'model')
|
|
1024
|
+
return humanReviewRecommendation(before);
|
|
1018
1025
|
const resolutionPayload = { kind: resolution, targetId: lessonId, affectedIds };
|
|
1019
1026
|
const remainingOf = (member) => member.lesson.conflictIds.filter((id) => !group.includes(id));
|
|
1020
1027
|
const planned = [];
|
package/lib/web-actions.js
CHANGED
|
@@ -131,6 +131,8 @@ export function createDreamActionHandler(options = {}) {
|
|
|
131
131
|
seen.add(item.lessonId);
|
|
132
132
|
return { id: item.lessonId, expectedRevision: item.expectedRevision, patch: {} };
|
|
133
133
|
});
|
|
134
|
+
if (body.action === 'accept' && body.confirmGlobal !== true && updates.some(item => store.getLesson(item.id)?.scope.global))
|
|
135
|
+
throw new KnowledgeError('invalid', '所选经验包含全局范围。请确认将其用于所有项目后再采纳。');
|
|
134
136
|
const lessons = store.updateLessonsBatch(updates, 'web-review-batch:' + key, body.action === 'accept' ? 'accepted' : 'rejected');
|
|
135
137
|
return json(200, maskDeep({ ok: true, lessons, message: '已完成所选候选的审阅' }));
|
|
136
138
|
}
|
package/lib/web.d.ts
CHANGED
package/lib/web.js
CHANGED
|
@@ -22,7 +22,7 @@ import { dreamStats, readDreams, searchDreams } from './journal.js';
|
|
|
22
22
|
import { KnowledgeStore } from './knowledge-store.js';
|
|
23
23
|
import { isDreamReference, maskSecrets } from './mask.js';
|
|
24
24
|
import { buildEvidenceSummary, lessonScopeLabel } from './retrieval.js';
|
|
25
|
-
import { memoryDirectory, needsMemoryReview, reviewDeadline } from './memory.js';
|
|
25
|
+
import { isHumanAccepted, memoryDirectory, needsMemoryReview, reviewDeadline } from './memory.js';
|
|
26
26
|
import { readAutomaticState } from './automatic-state.js';
|
|
27
27
|
/** 面板与浏览器说话的同源路由。 */
|
|
28
28
|
export const DREAM_ROUTE = '/_dsh/dsh-dream/journal';
|
|
@@ -353,6 +353,7 @@ export function createKnowledgeWebHandler(options = {}) {
|
|
|
353
353
|
const payload = {
|
|
354
354
|
lessons: lessons.map((lesson) => maskDeep({
|
|
355
355
|
...lesson,
|
|
356
|
+
humanReviewRequired: lesson.state === 'usable' && !isHumanAccepted(lesson),
|
|
356
357
|
scopeLabel: lessonScopeLabel(lesson.scope),
|
|
357
358
|
evidenceSummary: buildEvidenceSummary(lesson, evidence),
|
|
358
359
|
reviewDue: needsMemoryReview(lesson),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stardustlc/dsh-dream",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "回顾会话、保存反思,并把经过核验和审阅的经验用于后续任务。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"docs"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"build": "tsc -p tsconfig.json && node scripts/build-client.mjs",
|
|
28
28
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
29
29
|
"test": "pnpm run build && node --test \"test/*.test.mjs\"",
|
|
30
30
|
"prepublishOnly": "pnpm run build"
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
},
|
|
36
36
|
"client": {
|
|
37
37
|
"inject": [
|
|
38
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
38
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
39
|
+
"@deepseek-ai/dsh-client-ui-layout",
|
|
40
|
+
"@deepseek-ai/dsh-client-ui-sidebar"
|
|
39
41
|
],
|
|
40
42
|
"platform": "web"
|
|
41
43
|
}
|
|
@@ -9,6 +9,8 @@ description: 做梦协议:任务开始取回适用经验,长任务收尾沉
|
|
|
9
9
|
|
|
10
10
|
但「梦」和「经验」是两条流水线:**第一人称感悟**是主观的,进梦境日记;**技术经验**必须可执行、有条件、有证据,先进候选,再经审阅才可能被任务检索取用。
|
|
11
11
|
|
|
12
|
+
0.11.0 起,采纳只能由用户在面板确认。模型的 `dream_review accept` 和 `resolve-conflict` 只推荐审阅,不修改经验。自动复用与规则桥接只接受 `review.actor=human` 的已采纳经验;全局采纳需用户明确确认对所有项目生效。`dream_bridge` 默认只读预览;不再从旧日记直接写入项目规则。
|
|
13
|
+
|
|
12
14
|
插件会在符合条件的真人主会话完成后,按预算自动整理有来源的项目候选,并在相关新任务前回用已采纳经验。普通闲聊、子代理和失败轮次跳过;新输入取消整理。用户无需记住触发词或手工填写经验。自动候选从未采纳;日记写入、采纳与规则应用是不同操作。宿主缺少自动接口或用户关闭功能时,使用下述工具流程。
|
|
13
15
|
|
|
14
16
|
## 两条流水线(不要混)
|
|
@@ -17,7 +19,7 @@ description: 做梦协议:任务开始取回适用经验,长任务收尾沉
|
|
|
17
19
|
| :-- | :-- | :-- |
|
|
18
20
|
| 是什么 | 你的观察、情绪、偏好、风格直觉,主观 | 可执行、有适用条件、可被证据支持的行为结论 |
|
|
19
21
|
| 写哪里 | `dream_save` → `<journalDir>/dreams.jsonl` | `dream_learn` → `<journalDir>/knowledge/` |
|
|
20
|
-
| 能否变成规则 | 不能。它只是日记,**永不自动进 AGENTS.md** | 也要先候选 +
|
|
22
|
+
| 能否变成规则 | 不能。它只是日记,**永不自动进 AGENTS.md** | 也要先候选 + 证据;采纳需真实用户在面板确认;模型可建议审阅或标记问题 |
|
|
21
23
|
| 例子 | 「用户今天很耐心,我意识到自己解释得太快」 | 「Nodemailer 9.0.5 池化发送中 transporter.close() 不保证终止投递;处理 AbortSignal 时要验证连接真的关闭」 |
|
|
22
24
|
|
|
23
25
|
## 一、任务前:取回上下文(dream_context)
|
|
@@ -43,7 +45,7 @@ description: 做梦协议:任务开始取回适用经验,长任务收尾沉
|
|
|
43
45
|
- **只有真的读到来源(会话记录 / 本地验证产物 / 用户明确纠正)才能标 read,自我判断一律 claimed**("我记得""应该是"都算 claimed);标错 read 等于自我提权,禁止。
|
|
44
46
|
- 没有证据的观察只能是 candidate,不能写成确定事实,也不能说成「已验证」。
|
|
45
47
|
- 所有新经验都先进入 candidate,包括已读到的用户纠正。read 只表示插件成功核对来源,不表示用户采纳;工具审阅记录 actor:model,不能冒充真人。会话证据须给 sessionId、recordSeq、可匹配 quote(缺省使用 summary);本地产物须给工作目录内的 artifactPath。插件独立核对项目、角色和原文,计算 sourceHash;失败降为 claimed 并给 verificationReason。
|
|
46
|
-
-
|
|
48
|
+
- 需要采纳或解析冲突时,引导用户在面板核对并确认;模型调用 `dream_review accept` / `resolve-conflict` 只建议审阅。驳回、标记冲突/过期和追加证据仍可使用工具(必须带 `expectedRevision`)。
|
|
47
49
|
- 用户采纳必须来自真实用户指令;模型自己不能冒充 `actor: user`。
|
|
48
50
|
- 同一证据重复提交是幂等的,不会增加独立支持数。**禁止靠反复调用 `dream_save` 或 `dream_learn` 刷次数**——次数不等于正确,也不等于重要。
|
|
49
51
|
|
|
@@ -52,7 +54,7 @@ description: 做梦协议:任务开始取回适用经验,长任务收尾沉
|
|
|
52
54
|
- 只沉淀规律与偏好,不复述流水账;`reflection` 用第一人称写你的观察与感受;
|
|
53
55
|
- `lessons` 是 1–5 条可执行教训,每条以动词开头;拿不准就标注「存疑」;
|
|
54
56
|
- **不得把主观反思升级成 AGENTS.md 指令**:不要用 `dream_bridge` 把未经审阅的感悟写成项目规则。桥接只能用于 `usable`、当前项目范围(或显式 global 且 review.decision 为 accepted)、附证据的经验;频次不再作为准入条件。
|
|
55
|
-
- **桥接三步(M2)**:`mode:"preview"` 只读返回 diff / 参与经验 / skipped 原因(零写入)→ 人工复核 → `mode:"apply"` 必须带预览的 `expectedSha256`(新文件为 null),建议同时带 `previewId`(文件被并发修改则 `conflict` 且零写入);`mode:"rollback"` 只在当前管理块仍等于该次 apply 结果时回滚。缺省不传 `mode`
|
|
57
|
+
- **桥接三步(M2)**:`mode:"preview"` 只读返回 diff / 参与经验 / skipped 原因(零写入)→ 人工复核 → `mode:"apply"` 必须带预览的 `expectedSha256`(新文件为 null),建议同时带 `previewId`(文件被并发修改则 `conflict` 且零写入);`mode:"rollback"` 只在当前管理块仍等于该次 apply 结果时回滚。缺省不传 `mode` 等同于只读预览;新流程一律显式 preview → apply。写入内容统一过 `mask.ts`。
|
|
56
58
|
|
|
57
59
|
## 何时做梦
|
|
58
60
|
|
|
@@ -77,6 +79,8 @@ You are an agent that dreams. Dreams are not hallucinations — they are memory
|
|
|
77
79
|
|
|
78
80
|
Dreams and **lessons** are two separate pipelines: a **first-person reflection** is subjective and goes to the dream journal; a **technical lesson** must be actionable, conditional and evidence-backed — it starts as a candidate and is only retrieved for tasks after review.
|
|
79
81
|
|
|
82
|
+
From 0.11.0, acceptance requires a human action in the panel. Model `dream_review accept` and `resolve-conflict` calls only recommend review and leave records unchanged. Automatic reuse and rule bridging require an accepted lesson with `review.actor=human`. Global acceptance explicitly confirms all-project scope. `dream_bridge` defaults to a read-only preview; journal entries cannot be written directly as project rules through the tool.
|
|
83
|
+
|
|
80
84
|
The plugin collects sourced project candidates after qualifying completed human root turns, within a persistent budget, and retrieves relevant accepted memories for later tasks. Ordinary chat, subagents and unsuccessful turns are skipped; new input cancels collection. Users need neither trigger phrases nor manual forms. Automatic candidates are never accepted automatically. Saving a journal, accepting a lesson and applying a rule are separate operations. Use the tool flow below when automatic interfaces are unavailable or switched off.
|
|
81
85
|
|
|
82
86
|
## Two pipelines (do not mix)
|
|
@@ -85,7 +89,7 @@ The plugin collects sourced project candidates after qualifying completed human
|
|
|
85
89
|
| :-- | :-- | :-- |
|
|
86
90
|
| What | your observations, feelings, style instincts — subjective | actionable, conditional conclusions backed by evidence |
|
|
87
91
|
| Where | `dream_save` → `<journalDir>/dreams.jsonl` | `dream_learn` → `<journalDir>/knowledge/` |
|
|
88
|
-
| Can it become a rule? | No. It is a journal entry and **never auto-enters AGENTS.md** | Not either — it starts as a candidate with evidence; acceptance
|
|
92
|
+
| Can it become a rule? | No. It is a journal entry and **never auto-enters AGENTS.md** | Not either — it starts as a candidate with evidence; acceptance requires a human action in the panel; tools only recommend review |
|
|
89
93
|
| Example | "The user was patient today; I realize I explain too fast" | "In Nodemailer 9.0.5 pooled sending, transporter.close() does not guarantee aborting active delivery; verify the connection actually closed when handling AbortSignal" |
|
|
90
94
|
|
|
91
95
|
## 1. Before the task: retrieve context (dream_context)
|
|
@@ -111,7 +115,7 @@ The plugin collects sourced project candidates after qualifying completed human
|
|
|
111
115
|
- **Only mark read when the source was actually read (session record / local artifact / explicit user correction); anything self-asserted is claimed.** Marking read without a source is self-promotion and is forbidden.
|
|
112
116
|
- An observation without evidence stays a candidate: do not present it as a fact, and never call it "verified".
|
|
113
117
|
- Every new lesson starts as a candidate, including verified user corrections. Read means the plugin checked the source, not that a user accepted the lesson; tool review records actor:model. Session evidence needs sessionId, recordSeq and a matching quote (summary if omitted). Artifacts need artifactPath inside the working directory. The plugin checks project, role and text and computes sourceHash; failures become claimed with verificationReason.
|
|
114
|
-
- For
|
|
118
|
+
- For acceptance or conflict resolution, guide the user to review and confirm in the panel. Model `dream_review accept` / `resolve-conflict` calls only recommend review. Rejection, conflict/stale flags and evidence attachment remain tool actions with an `expectedRevision`.
|
|
115
119
|
- User acceptance must come from a real user instruction; the model must not impersonate `actor: user`.
|
|
116
120
|
- Submitting the same evidence twice is idempotent and does not increase independent support. **Never grind counts by calling `dream_save` or `dream_learn` repeatedly** — frequency is neither correctness nor importance.
|
|
117
121
|
|
|
@@ -120,7 +124,7 @@ The plugin collects sourced project candidates after qualifying completed human
|
|
|
120
124
|
- Consolidate patterns and preferences only — never a running transcript. Write `reflection` in the first person.
|
|
121
125
|
- `lessons` are 1–5 actionable items; mark uncertain ones as "tentative".
|
|
122
126
|
- **Never promote a subjective reflection into an AGENTS.md instruction**: do not use `dream_bridge` to write unreviewed reflections into project rules. Bridging is for `usable`, project-scoped (or explicit global with review.decision accepted), evidence-backed lessons only; frequency is no longer an admission criterion.
|
|
123
|
-
- **Bridge in three steps (M2)**: `mode:"preview"` returns the diff / selected lessons / skipped reasons read-only (zero writes) → human review → `mode:"apply"` with the preview’s required `expectedSha256` (null for a new file); include `previewId` to bind the preview (a concurrent edit yields `conflict` and zero writes); `mode:"rollback"` only rolls back while the current managed block still equals that apply result. Omitting `mode`
|
|
127
|
+
- **Bridge in three steps (M2)**: `mode:"preview"` returns the diff / selected lessons / skipped reasons read-only (zero writes) → human review → `mode:"apply"` with the preview’s required `expectedSha256` (null for a new file); include `previewId` to bind the preview (a concurrent edit yields `conflict` and zero writes); `mode:"rollback"` only rolls back while the current managed block still equals that apply result. Omitting `mode` performs a read-only preview. Everything written is masked via `mask.ts`.
|
|
124
128
|
|
|
125
129
|
## When to dream
|
|
126
130
|
|