@nanmicoder/dsh-agent-teams 0.1.22 → 0.1.24-rc.1
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 +35 -13
- package/README_ZH.md +35 -13
- package/compatibility.json +6 -2
- package/lib/artifacts.js +342 -0
- package/lib/capabilities.js +6 -4
- package/lib/client/ActivityPanel.js +5 -2
- package/lib/client/agent-teams-card-definition.js +100 -6
- package/lib/client.js +90 -7
- package/lib/client.js.map +1 -1
- package/lib/command.js +3 -2
- package/lib/git-artifact-stamp.json +2 -2
- package/lib/harness-compat.js +139 -24
- package/lib/index.js +26 -3
- package/lib/lineage.js +198 -0
- package/lib/mailbox.js +59 -34
- package/lib/members.js +355 -82
- package/lib/profiles.js +3 -2
- package/lib/quality-gates.js +850 -65
- package/lib/scheduler.js +22 -3
- package/lib/snapshot.js +22 -1
- package/lib/state.js +282 -13
- package/lib/tool-policies.js +187 -0
- package/lib/tools.js +382 -109
- package/lib/types/artifacts.d.ts +66 -0
- package/lib/types/client/activity-monitor.d.ts +6 -0
- package/lib/types/client/agent-teams-card-definition.d.ts +56 -0
- package/lib/types/harness-compat.d.ts +78 -15
- package/lib/types/index.d.ts +26 -1
- package/lib/types/lineage.d.ts +92 -0
- package/lib/types/members.d.ts +113 -2
- package/lib/types/profiles.d.ts +6 -0
- package/lib/types/quality-gates.d.ts +216 -10
- package/lib/types/scheduler.d.ts +2 -1
- package/lib/types/snapshot.d.ts +20 -0
- package/lib/types/state.d.ts +22 -5
- package/lib/types/tool-policies.d.ts +119 -0
- package/lib/types/tools.d.ts +12 -1
- package/lib/types/types.d.ts +100 -0
- package/lib/types/workspace-audit.d.ts +27 -0
- package/lib/workspace-audit.js +52 -0
- package/package.json +61 -54
- package/pnpm-workspace.yaml +304 -273
- package/release-notes/v0.1.23.md +34 -0
- package/release-notes/v0.1.24-rc.1.md +13 -0
- package/scripts/legacy-session-source-repair.mjs +344 -0
package/lib/mailbox.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { acknowledgeMailbox, CAPTAIN_KEY, discardMailboxMessages, findTeamByCaptain, readMailbox, readUnreadMailbox, readTeam, sanitizeKey, withTeamLock } from "./state.js";
|
|
3
3
|
import { sessionOwnEvents } from "./harness-compat.js";
|
|
4
|
+
import { leadIdentityOfAsync, sessionLeadsTeamAsync } from "./lineage.js";
|
|
4
5
|
const PREFIX = 'AgentTeams inbox receipt: ';
|
|
5
6
|
export function isCurrentMail(team, message) {
|
|
6
7
|
if (message.discardedAt !== undefined)
|
|
@@ -75,26 +76,35 @@ export function installMailboxAdmission(ctx, stateDir) {
|
|
|
75
76
|
}));
|
|
76
77
|
const redundantSettlements = new Set();
|
|
77
78
|
if (successfulSettlements.size > 0) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
await
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
// Narrow containment: only AgentTeams state reads degrade silently.
|
|
80
|
+
try {
|
|
81
|
+
const owned = await findTeamByCaptain(root, payload.agent.id, await leadIdentityOfAsync(ctx, payload.agent.session));
|
|
82
|
+
if (owned !== undefined)
|
|
83
|
+
await withTeamLock(`team:${root}:${owned.id}`, async () => {
|
|
84
|
+
const team = await readTeam(root, owned.id);
|
|
85
|
+
if (team === undefined || !(await sessionLeadsTeamAsync(ctx, team, payload.agent.id)) || team.halted)
|
|
86
|
+
return;
|
|
87
|
+
const reports = await readMailbox(root, team.id, CAPTAIN_KEY);
|
|
88
|
+
for (const member of team.members) {
|
|
89
|
+
if (!successfulSettlements.has(member.id) || member.status === 'removed' || member.stopping)
|
|
90
|
+
continue;
|
|
91
|
+
const tasks = team.tasks.filter(task => task.assignee === member.name);
|
|
92
|
+
if (tasks.some(task => task.status === 'claimed' || task.status === 'in_progress'))
|
|
93
|
+
continue;
|
|
94
|
+
const latest = tasks.filter(task => (task.attempt ?? 0) > 0 || task.status === 'completed').sort((a, b) => b.updatedAt - a.updatedAt)[0];
|
|
95
|
+
if (latest?.status === 'completed' && reports.some(report => report.from === member.name && report.ts >= latest.updatedAt
|
|
96
|
+
&& report.discardedAt === undefined && (report.deliveredAt !== undefined || report.readAt !== undefined))) {
|
|
97
|
+
redundantSettlements.add(member.id);
|
|
98
|
+
}
|
|
95
99
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
// A corrupt AgentTeams state file (e.g. an invalid team.json) must never
|
|
104
|
+
// hold the host's step admission hostage: degrade to plain admission.
|
|
105
|
+
ctx.logger?.warn(`agent-teams: mailbox admission degraded to plain pass-through for agent ${payload.agent.id}: could not read team state under ${root} (a team.json may be corrupt or unreadable): ${String(error)}`);
|
|
106
|
+
return decision;
|
|
107
|
+
}
|
|
98
108
|
}
|
|
99
109
|
const batches = new Map();
|
|
100
110
|
const inputs = decision.messages.map(input => {
|
|
@@ -116,27 +126,42 @@ export function installMailboxAdmission(ctx, stateDir) {
|
|
|
116
126
|
// One read/acknowledgement per recipient per step, even for a large burst.
|
|
117
127
|
for (const batch of batches.values()) {
|
|
118
128
|
const { receipt } = batch;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
try {
|
|
130
|
+
await withTeamLock(`team:${root}:${receipt.teamId}`, async () => {
|
|
131
|
+
const team = await readTeam(root, receipt.teamId);
|
|
132
|
+
if (team === undefined)
|
|
133
|
+
return;
|
|
134
|
+
// Captain mail is admitted for any lead session of the team: after a
|
|
135
|
+
// fork the human reads it in the fork while members still address the
|
|
136
|
+
// recorded captain. Acknowledging marks it read for both.
|
|
137
|
+
const isCaptainRecipient = receipt.recipient === CAPTAIN_KEY
|
|
138
|
+
&& await sessionLeadsTeamAsync(ctx, team, payload.agent.id);
|
|
139
|
+
const recipientId = receipt.recipient === CAPTAIN_KEY ? team.captainSessionId
|
|
140
|
+
: team.members.find(member => member.name === receipt.recipient && member.status !== 'removed' && member.stopping !== true)?.id;
|
|
141
|
+
if (!isCaptainRecipient && recipientId !== payload.agent.id)
|
|
142
|
+
return;
|
|
143
|
+
const selected = (await readMailbox(root, team.id, receipt.recipient)).filter(message => batch.ids.has(message.id));
|
|
144
|
+
const current = selected.filter(message => message.readAt === undefined && isCurrentMail(team, message));
|
|
145
|
+
await discardMailboxMessages(root, team.id, receipt.recipient, selected.filter(message => !isCurrentMail(team, message)).map(message => message.id));
|
|
146
|
+
await acknowledgeMailbox(root, team.id, receipt.recipient, current.map(message => message.id));
|
|
147
|
+
batch.current = new Map(current.map(message => [message.id, message]));
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// Narrow containment, per team: the messages of this batch are not
|
|
152
|
+
// acked (the teamId/recipient above identify the unread mail), but the
|
|
153
|
+
// receipt inputs still pass through untouched instead of holding the
|
|
154
|
+
// host's step admission hostage.
|
|
155
|
+
batch.failed = true;
|
|
156
|
+
ctx.logger?.warn(`agent-teams: mailbox admission degraded to plain pass-through for agent ${payload.agent.id}: could not read team "${receipt.teamId}" (state under ${root} may be corrupt or unreadable, recipient ${receipt.recipient} mail left unacked): ${String(error)}`);
|
|
157
|
+
}
|
|
133
158
|
}
|
|
134
159
|
const admitted = [];
|
|
135
160
|
for (const { input, receipt, batch } of inputs) {
|
|
136
161
|
if (input.source?.kind === 'subagent-settled' && redundantSettlements.has(input.source.senderSessionId)
|
|
137
162
|
&& input.source.summary === `Background subagent ${input.source.senderSessionId} finished and will do no further work unless you send it more.`)
|
|
138
163
|
continue;
|
|
139
|
-
if (receipt === undefined || batch === undefined) {
|
|
164
|
+
if (receipt === undefined || batch === undefined || batch.failed === true) {
|
|
140
165
|
admitted.push(input);
|
|
141
166
|
continue;
|
|
142
167
|
}
|