@suifei/dsh-ai-team 0.3.17 → 0.3.18
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 +5 -0
- package/index.js +1 -1
- package/lib/host/project-runtime.js +1 -0
- package/lib/host/service.js +56 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/index.js
CHANGED
|
@@ -34,7 +34,7 @@ export const name = 'ai-team';
|
|
|
34
34
|
/** The workbench only makes sense where the Web carrier exists. */
|
|
35
35
|
export const inject = ['webServer', 'permissionPresets', 'sandboxPolicy'];
|
|
36
36
|
|
|
37
|
-
const VERSION = '0.3.
|
|
37
|
+
const VERSION = '0.3.18';
|
|
38
38
|
const PROJECT_ID = 'prj_main';
|
|
39
39
|
const HUMAN_ID = 'mem_human';
|
|
40
40
|
|
package/lib/host/service.js
CHANGED
|
@@ -19,6 +19,11 @@ import { boardView, quadrantsView } from './views.js';
|
|
|
19
19
|
import { applyMemberConfigPatch, normalizeMemberConfig } from '../domain/member-config.js';
|
|
20
20
|
import { isQaMember, unfinishedTasksFor } from '../domain/member-profile.js';
|
|
21
21
|
|
|
22
|
+
function mentionsHuman(body) {
|
|
23
|
+
return typeof body === 'string'
|
|
24
|
+
&& /(^|[^A-Za-z])(human|@你|待你|需要你|请你|等你|你拍板)([^A-Za-z]|$)/i.test(body);
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
/**
|
|
23
28
|
* Team domain service on top of a Project ledger.
|
|
24
29
|
*
|
|
@@ -131,6 +136,56 @@ export class TeamService {
|
|
|
131
136
|
};
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Create missing Human decision items for existing Agent Thread messages
|
|
141
|
+
* that explicitly asked Human to decide. Runs on Project open once; the
|
|
142
|
+
* per-entry dedupe makes it idempotent.
|
|
143
|
+
*/
|
|
144
|
+
async backfillHumanMentions() {
|
|
145
|
+
const humanId = this.state.humanMemberId
|
|
146
|
+
?? Object.values(this.state.members ?? {}).find((member) => member.kind === 'human')?.id
|
|
147
|
+
?? null;
|
|
148
|
+
if (humanId === null) return 0;
|
|
149
|
+
const projectId = Object.keys(this.state.projects ?? {})[0];
|
|
150
|
+
const existing = new Set(
|
|
151
|
+
Object.values(this.state.inbox ?? {})
|
|
152
|
+
.filter((item) => item.memberId === humanId && item.ref?.entrySeq !== undefined)
|
|
153
|
+
.map((item) => `${item.ref?.taskId}:${item.ref?.entrySeq}`),
|
|
154
|
+
);
|
|
155
|
+
let created = 0;
|
|
156
|
+
for (const task of Object.values(this.state.tasks ?? {})) {
|
|
157
|
+
if (task.tombstone === true) continue;
|
|
158
|
+
for (const entry of this.state.threads?.[task.id]?.entries ?? []) {
|
|
159
|
+
const author = this.state.members?.[entry.authorId];
|
|
160
|
+
if (author?.kind !== 'agent' || !mentionsHuman(entry.body)) continue;
|
|
161
|
+
const key = `${task.id}:${entry.seq}`;
|
|
162
|
+
if (existing.has(key)) continue;
|
|
163
|
+
existing.add(key);
|
|
164
|
+
const item = createInboxItem({
|
|
165
|
+
memberId: humanId,
|
|
166
|
+
type: 'decision_required',
|
|
167
|
+
ref: {
|
|
168
|
+
taskId: task.id,
|
|
169
|
+
entrySeq: entry.seq,
|
|
170
|
+
memberId: entry.authorId,
|
|
171
|
+
category: 'thread_mention',
|
|
172
|
+
title: String(entry.body).slice(0, 180),
|
|
173
|
+
},
|
|
174
|
+
requiresDecision: true,
|
|
175
|
+
}, { at: this.now() });
|
|
176
|
+
await this.ledger.append({
|
|
177
|
+
type: 'inbox/item-created',
|
|
178
|
+
payload: { itemId: item.id, ...item },
|
|
179
|
+
actor: { kind: 'system' },
|
|
180
|
+
projectId,
|
|
181
|
+
at: this.now(),
|
|
182
|
+
});
|
|
183
|
+
created += 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return created;
|
|
187
|
+
}
|
|
188
|
+
|
|
134
189
|
/**
|
|
135
190
|
* Dispatch one command. The caller is an exact Team member (or Human) and
|
|
136
191
|
* the ledger serializes commands per Project.
|
|
@@ -800,9 +855,7 @@ export class TeamService {
|
|
|
800
855
|
// Human inbox; otherwise the board looks busy while the Human never sees
|
|
801
856
|
// the question (the exact failure mode behind “对话面板没有反馈”).
|
|
802
857
|
const body = typeof payload.body === 'string' ? payload.body : '';
|
|
803
|
-
|
|
804
|
-
&& /(^|[^A-Za-z])(human|@你|待你|需要你|请你|等你|你拍板)([^A-Za-z]|$)/i.test(body);
|
|
805
|
-
if (mentionsHuman) {
|
|
858
|
+
if (actorKind === 'agent' && mentionsHuman(body)) {
|
|
806
859
|
const humanId = this.state.humanMemberId
|
|
807
860
|
?? Object.values(this.state.members ?? {}).find((candidate) => candidate.kind === 'human')?.id
|
|
808
861
|
?? null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suifei/dsh-ai-team",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "文渊阁 (Wenyuan Pavilion) — AI Team mode for DeepSeek Harness: concurrent projects, owned tasks, threads, inbox and an append-only team ledger",
|
|
6
6
|
"license": "MIT",
|