@wowyuarm/dsh-agent-team 0.1.6 → 0.1.8
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 +11 -5
- package/README.zh.md +11 -5
- package/package.json +44 -42
- package/packages/agent-team/README.md +2 -0
- package/packages/agent-team/README.zh.md +2 -0
- package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +2 -0
- package/packages/agent-team/lib/index.js +140 -204
- package/packages/agent-team/lib/ledger.js +436 -25
- package/packages/agent-team/lib/member-context.js +6 -2
- package/packages/agent-team/lib/member-runtime.js +229 -0
- package/packages/agent-team/lib/preset-roster.js +1 -0
- package/packages/agent-team/lib/progress-nudge.js +320 -0
- package/packages/agent-team/lib/spec.js +30 -1
- package/packages/agent-team/lib/typert.host.js +250 -70
- package/packages/agent-team/lib/typert.remote-client.d.ts +5 -1
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +168 -38
- package/packages/agent-team/lib/types/entities.js +1 -0
- package/packages/agent-team/lib/types/index.d.ts +28 -44
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +60 -2
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts +108 -0
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -0
- package/packages/agent-team/lib/types/operations.js +1 -0
- package/packages/agent-team/lib/types/preset-roster.d.ts.map +1 -1
- package/packages/agent-team/lib/types/progress-nudge.d.ts +136 -0
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -0
- package/packages/agent-team/lib/types/requests-results.js +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +357 -0
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/operations.d.ts +303 -0
- package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts +529 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types.d.ts +10 -1070
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +6 -4
- package/packages/client-agent-team/README.md +3 -1
- package/packages/client-agent-team/README.zh.md +3 -1
- package/packages/client-agent-team/lib/client.js +773 -733
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -2
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +30 -7
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +5 -9
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +31 -5
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +39 -28
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.js +3 -2
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +15 -3
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +4 -6
- package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts +14 -0
- package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamStateDot.js +15 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +41 -16
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceRow.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +9 -77
- package/packages/client-agent-team/lib/types/client/locales.d.ts +26 -0
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +26 -0
- package/packages/client-agent-team/lib/types/client/navigation.d.ts +2 -1
- package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +1 -2
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/sidebar-sections.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts +5 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts +7 -1
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/task-refs.js +25 -3
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +11 -10
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-formatters.js +14 -11
- package/packages/client-agent-team/lib/types/client/team-membership.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
- package/packages/tool-agent-team/lib/index.js +9 -9
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +0 -17
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +0 -135
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +0 -22
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/member-session-input.js +0 -98
|
@@ -40,9 +40,6 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
40
40
|
done = true;
|
|
41
41
|
};
|
|
42
42
|
import { randomUUID } from 'node:crypto';
|
|
43
|
-
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
44
|
-
import { dirname, join, resolve } from 'node:path';
|
|
45
|
-
import { fileURLToPath } from 'node:url';
|
|
46
43
|
import { isDeepStrictEqual } from 'node:util';
|
|
47
44
|
import { Service } from '@deepseek-ai/cordis';
|
|
48
45
|
import { installModelSelection } from '@deepseek-ai/dsh-agent';
|
|
@@ -50,26 +47,21 @@ import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
|
50
47
|
import { dshHomePath } from '@deepseek-ai/dsh-home-paths';
|
|
51
48
|
import { scopeOf } from '@deepseek-ai/dsh-scope';
|
|
52
49
|
import { SessionId } from '@deepseek-ai/dsh-session';
|
|
53
|
-
import {
|
|
50
|
+
import { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy';
|
|
54
51
|
import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
55
52
|
import { ATTACHMENT_MAX_BYTES, attachmentPayloadPath, attachmentsRoot, copyPathAttachment, newAttachmentId, readAttachment, sanitizeMediaType, sweepAttachmentCache, validatePathAttachment, writeAttachment } from "./attachments.js";
|
|
56
53
|
import { acceptedTaskCompactionMembers, AutoCompactionCoordinator, PRE_COMPACTION_NOTICE_SUMMARY, preCompactionNoticeText } from "./auto-compaction.js";
|
|
57
54
|
import { AGENT_TEAM_HUMAN_MEMBER_ID, AgentTeamLedger, agentTeamHumanActor } from "./ledger.js";
|
|
58
|
-
import
|
|
55
|
+
import { AGENT_TEAM_TOOL_NAMES, deepCopyCapabilities, MemberRuntime } from "./member-runtime.js";
|
|
56
|
+
import { ProgressNudgeCoordinator } from "./progress-nudge.js";
|
|
59
57
|
import { classifyRecoverableError, RecoveryCoordinator, RECOVERY_MAX_CONSECUTIVE_ERRORS } from "./recovery.js";
|
|
60
58
|
import { agentTeamDomainSpec } from "./spec.js";
|
|
61
59
|
export { agentTeamDomainSpec, agentTeamOperationSchema } from "./spec.js";
|
|
62
60
|
export { AGENT_TEAM_HUMAN_MEMBER_ID, AGENT_TEAM_INITIALIZE_REQUEST_ID } from "./ledger.js";
|
|
61
|
+
export { AGENT_TEAM_TOOL_NAMES } from "./member-runtime.js";
|
|
63
62
|
/** Process-stable marker carried by the final Team message tool definition. */
|
|
64
63
|
export const AGENT_TEAM_PRESET_MARKER = Symbol.for('@wowyuarm/dsh-agent-team.preset');
|
|
65
64
|
const AGENT_TEAM_PLUGIN_ID = '@wowyuarm/dsh-agent-team';
|
|
66
|
-
/**
|
|
67
|
-
* Read-only core skills shipped beside the preset (the meta skill first:
|
|
68
|
-
* its description routes any skill-management work to itself). Resolved
|
|
69
|
-
* from this module's emitted location so it follows the installed plugin,
|
|
70
|
-
* like the preset roster's own root.
|
|
71
|
-
*/
|
|
72
|
-
const BUNDLED_SKILLS_DIRECTORY = resolve(dirname(fileURLToPath(import.meta.url)), '../core-skills');
|
|
73
65
|
const INBOX_NOTICE_SUMMARY = 'Team Inbox has unread work.';
|
|
74
66
|
const RECOVERY_NOTICE_SUMMARY = 'Recovery: continue your interrupted work.';
|
|
75
67
|
const ORPHANED_MEMBER_DIAGNOSTIC = 'Member preset composition was lost after a reload; its tools are unavailable. Resume rebuilds the member in place.';
|
|
@@ -82,27 +74,11 @@ function sameChangeScope(left, right) {
|
|
|
82
74
|
return left.threadRef === right.threadRef;
|
|
83
75
|
return false;
|
|
84
76
|
}
|
|
85
|
-
/** Copy a Remote-supplied capability overlay into owned frozen storage. */
|
|
86
|
-
function deepCopyCapabilities(capabilities) {
|
|
87
|
-
const copyAllow = (allow) => allow === undefined ? {} : { allow: [...allow] };
|
|
88
|
-
return {
|
|
89
|
-
...(capabilities.tools === undefined ? {} : { tools: copyAllow(capabilities.tools.allow) }),
|
|
90
|
-
...(capabilities.skills === undefined ? {} : { skills: copyAllow(capabilities.skills.allow) }),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
77
|
/** Mark the preset's `team_message` definition as an Agent Team consumer. */
|
|
94
78
|
export function markAgentTeamPreset(definition) {
|
|
95
79
|
Object.defineProperty(definition, AGENT_TEAM_PRESET_MARKER, { value: true });
|
|
96
80
|
return definition;
|
|
97
81
|
}
|
|
98
|
-
/** Model-facing capabilities every Team-enabled preset must publish. */
|
|
99
|
-
export const AGENT_TEAM_TOOL_NAMES = Object.freeze([
|
|
100
|
-
'team_inbox',
|
|
101
|
-
'team_thread',
|
|
102
|
-
'team_message',
|
|
103
|
-
'team_claim',
|
|
104
|
-
'team_view',
|
|
105
|
-
]);
|
|
106
82
|
/**
|
|
107
83
|
* A DM was durably recorded but its session injection could not run (no live
|
|
108
84
|
* handle, or the wake itself failed). The recorded DM stays durable; the
|
|
@@ -127,10 +103,12 @@ let AgentTeam = (() => {
|
|
|
127
103
|
let _changes_decorators;
|
|
128
104
|
let _createChannel_decorators;
|
|
129
105
|
let _updateChannel_decorators;
|
|
106
|
+
let _archiveChannel_decorators;
|
|
130
107
|
let _addMember_decorators;
|
|
131
108
|
let _recoverMember_decorators;
|
|
132
109
|
let _clearMemberContext_decorators;
|
|
133
110
|
let _updateMember_decorators;
|
|
111
|
+
let _archiveMember_decorators;
|
|
134
112
|
let _changeTask_decorators;
|
|
135
113
|
let _promoteThread_decorators;
|
|
136
114
|
let _joinChannel_decorators;
|
|
@@ -153,10 +131,12 @@ let AgentTeam = (() => {
|
|
|
153
131
|
_changes_decorators = [Remote('changes')];
|
|
154
132
|
_createChannel_decorators = [Remote('createChannel')];
|
|
155
133
|
_updateChannel_decorators = [Remote('updateChannel')];
|
|
134
|
+
_archiveChannel_decorators = [Remote('archiveChannel')];
|
|
156
135
|
_addMember_decorators = [Remote('addMember')];
|
|
157
136
|
_recoverMember_decorators = [Remote('recoverMember')];
|
|
158
137
|
_clearMemberContext_decorators = [Remote('clearMemberContext')];
|
|
159
138
|
_updateMember_decorators = [Remote('updateMember')];
|
|
139
|
+
_archiveMember_decorators = [Remote('archiveMember')];
|
|
160
140
|
_changeTask_decorators = [Remote('changeTask')];
|
|
161
141
|
_promoteThread_decorators = [Remote('promoteThread')];
|
|
162
142
|
_joinChannel_decorators = [Remote('joinChannel')];
|
|
@@ -176,10 +156,12 @@ let AgentTeam = (() => {
|
|
|
176
156
|
__esDecorate(this, null, _changes_decorators, { kind: "method", name: "changes", static: false, private: false, access: { has: obj => "changes" in obj, get: obj => obj.changes }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
177
157
|
__esDecorate(this, null, _createChannel_decorators, { kind: "method", name: "createChannel", static: false, private: false, access: { has: obj => "createChannel" in obj, get: obj => obj.createChannel }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
178
158
|
__esDecorate(this, null, _updateChannel_decorators, { kind: "method", name: "updateChannel", static: false, private: false, access: { has: obj => "updateChannel" in obj, get: obj => obj.updateChannel }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
159
|
+
__esDecorate(this, null, _archiveChannel_decorators, { kind: "method", name: "archiveChannel", static: false, private: false, access: { has: obj => "archiveChannel" in obj, get: obj => obj.archiveChannel }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
179
160
|
__esDecorate(this, null, _addMember_decorators, { kind: "method", name: "addMember", static: false, private: false, access: { has: obj => "addMember" in obj, get: obj => obj.addMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
180
161
|
__esDecorate(this, null, _recoverMember_decorators, { kind: "method", name: "recoverMember", static: false, private: false, access: { has: obj => "recoverMember" in obj, get: obj => obj.recoverMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
181
162
|
__esDecorate(this, null, _clearMemberContext_decorators, { kind: "method", name: "clearMemberContext", static: false, private: false, access: { has: obj => "clearMemberContext" in obj, get: obj => obj.clearMemberContext }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
182
163
|
__esDecorate(this, null, _updateMember_decorators, { kind: "method", name: "updateMember", static: false, private: false, access: { has: obj => "updateMember" in obj, get: obj => obj.updateMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
164
|
+
__esDecorate(this, null, _archiveMember_decorators, { kind: "method", name: "archiveMember", static: false, private: false, access: { has: obj => "archiveMember" in obj, get: obj => obj.archiveMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
183
165
|
__esDecorate(this, null, _changeTask_decorators, { kind: "method", name: "changeTask", static: false, private: false, access: { has: obj => "changeTask" in obj, get: obj => obj.changeTask }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
184
166
|
__esDecorate(this, null, _promoteThread_decorators, { kind: "method", name: "promoteThread", static: false, private: false, access: { has: obj => "promoteThread" in obj, get: obj => obj.promoteThread }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
185
167
|
__esDecorate(this, null, _joinChannel_decorators, { kind: "method", name: "joinChannel", static: false, private: false, access: { has: obj => "joinChannel" in obj, get: obj => obj.joinChannel }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -208,12 +190,25 @@ let AgentTeam = (() => {
|
|
|
208
190
|
domain = __runInitializers(this, _instanceExtraInitializers);
|
|
209
191
|
ledger;
|
|
210
192
|
handles = new Map();
|
|
193
|
+
/** Live Member per session id; drives the root session/event listener. */
|
|
194
|
+
memberBySessionId = new Map();
|
|
211
195
|
/** Live selection refs let model edits take effect without disposing the Session. */
|
|
212
196
|
modelSelections = new Map();
|
|
213
|
-
/**
|
|
214
|
-
|
|
215
|
-
/** Per-Member
|
|
216
|
-
|
|
197
|
+
/** Agent ids with a turn in flight; restarts must wait for the boundary. */
|
|
198
|
+
runningAgents = new Set();
|
|
199
|
+
/** Per-Member runtime state: tool restrictions, skill mounts, warnings, private memory. */
|
|
200
|
+
memberRuntime = new MemberRuntime({
|
|
201
|
+
// Deferred field access: the constructor runs before `handles` is
|
|
202
|
+
// populated, so the resolver must dereference at call time.
|
|
203
|
+
ctx: this.ctx,
|
|
204
|
+
liveMemberContext: memberId => {
|
|
205
|
+
const handle = this.handles.get(memberId);
|
|
206
|
+
if (handle === undefined)
|
|
207
|
+
throw new Error(`Agent Member '${this.memberLabel(memberId)}' has no live session for a tool-policy update`);
|
|
208
|
+
return handle.agent.ctx;
|
|
209
|
+
},
|
|
210
|
+
runningAgents: this.runningAgents,
|
|
211
|
+
});
|
|
217
212
|
/**
|
|
218
213
|
* Why one Member shows error presence, per failure source. Reads prefer
|
|
219
214
|
* activation, then runtime, then compaction; slots clear independently, so
|
|
@@ -222,23 +217,7 @@ let AgentTeam = (() => {
|
|
|
222
217
|
* stale keys.
|
|
223
218
|
*/
|
|
224
219
|
memberFailures = new Map();
|
|
225
|
-
/**
|
|
226
|
-
* Live per-Member tool restriction disposers, mirroring modelSelections:
|
|
227
|
-
* activation registers, disposal paths release, edits swap at a turn
|
|
228
|
-
* boundary. Deliberate interface reservation: the restriction seam is the
|
|
229
|
-
* primitive future Runtime Revision manifests orchestrate — do not remove
|
|
230
|
-
* during cleanup.
|
|
231
|
-
*/
|
|
232
|
-
memberRestrictions = new Map();
|
|
233
|
-
/**
|
|
234
|
-
* Runtime-derived capability warnings, recomputed at every activation (like
|
|
235
|
-
* memberFailures, keyed by Member and never persisted): persisted warnings
|
|
236
|
-
* would lie after a Host restart or a Harness upgrade renames tools.
|
|
237
|
-
*/
|
|
238
|
-
capabilityWarnings = new Map();
|
|
239
220
|
autoCompaction;
|
|
240
|
-
/** Agent ids with a turn in flight; restarts must wait for the boundary. */
|
|
241
|
-
runningAgents = new Set();
|
|
242
221
|
notifiedInbox = new Map();
|
|
243
222
|
attachmentGcTimer;
|
|
244
223
|
recovery = new RecoveryCoordinator({
|
|
@@ -250,6 +229,22 @@ let AgentTeam = (() => {
|
|
|
250
229
|
this.ctx.logger.warn(`agent-team: member '${this.memberLabel(memberId)}' reached ${consecutiveFailures}/${RECOVERY_MAX_CONSECUTIVE_ERRORS} consecutive recoverable failures; leaving it in error for the operator`);
|
|
251
230
|
},
|
|
252
231
|
});
|
|
232
|
+
/**
|
|
233
|
+
* Advisory progress-visibility nudges. Purely in-process: the ledger owns
|
|
234
|
+
* eligibility, this coordinator owns counting and notices, and neither ever
|
|
235
|
+
* writes Team facts. See docs/team-collaboration.md for the regimes.
|
|
236
|
+
*/
|
|
237
|
+
progressNudge = new ProgressNudgeCoordinator({
|
|
238
|
+
agentForMember: memberId => this.handles.get(memberId)?.agent,
|
|
239
|
+
targetsForMember: memberId => this.requireLedger().progressNudgeTargets(memberId),
|
|
240
|
+
sessionLogForMember: (memberId, sessionId) => {
|
|
241
|
+
const handle = this.handles.get(memberId);
|
|
242
|
+
if (handle === undefined || handle.agent.session.id !== sessionId)
|
|
243
|
+
return undefined;
|
|
244
|
+
return { events: handle.agent.session.ownEvents() };
|
|
245
|
+
},
|
|
246
|
+
log: message => { this.ctx.logger.warn(message); },
|
|
247
|
+
});
|
|
253
248
|
lifecycleTail = Promise.resolve();
|
|
254
249
|
accepting = true;
|
|
255
250
|
changeVersion = 0;
|
|
@@ -276,6 +271,10 @@ let AgentTeam = (() => {
|
|
|
276
271
|
content: [{ type: 'text', text: preCompactionNoticeText() }],
|
|
277
272
|
source: { kind: 'plugin', plugin: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: PRE_COMPACTION_NOTICE_SUMMARY },
|
|
278
273
|
});
|
|
274
|
+
// Persist-your-conclusions outranks a queued progress nudge.
|
|
275
|
+
const member = this.memberForAgent(agent);
|
|
276
|
+
if (member !== undefined)
|
|
277
|
+
this.progressNudge.revokePendingNotice(member.memberId);
|
|
279
278
|
agent.steer(hint);
|
|
280
279
|
},
|
|
281
280
|
});
|
|
@@ -319,10 +318,28 @@ let AgentTeam = (() => {
|
|
|
319
318
|
this.emitChanged([{ kind: 'workspace', workspaceId: member.workspaceId }]);
|
|
320
319
|
}
|
|
321
320
|
});
|
|
321
|
+
// Progress nudges count every `tool/call` of each Member Session. The
|
|
322
|
+
// store's dispatch carrier is untagged, so a scope-tagged listener inside
|
|
323
|
+
// the Agent setup would receive nothing; one root listener that maps the
|
|
324
|
+
// session id back to its Member is the seam that works (same shape as the
|
|
325
|
+
// `agent/status` listener above). The first turn of a freshly published
|
|
326
|
+
// Member cannot race this: `handles.set()` precedes the same activation
|
|
327
|
+
// continuation that publishes the Agent, so by the time any tool call
|
|
328
|
+
// streams, the map lookup succeeds.
|
|
329
|
+
this.ctx.on('session/event', (session, event) => {
|
|
330
|
+
const memberId = this.memberBySessionId.get(session.id);
|
|
331
|
+
if (memberId === undefined)
|
|
332
|
+
return;
|
|
333
|
+
const handle = this.handles.get(memberId);
|
|
334
|
+
if (handle === undefined || handle.agent.session.id !== session.id)
|
|
335
|
+
return;
|
|
336
|
+
this.progressNudge.onSessionEvent(memberId, session.id, handle.agent, event);
|
|
337
|
+
});
|
|
322
338
|
const domain = await this.ctx.storageDomain.open(agentTeamDomainSpec);
|
|
323
339
|
this.ctx.effect(() => async () => {
|
|
324
340
|
this.accepting = false;
|
|
325
341
|
this.recovery.dispose();
|
|
342
|
+
this.progressNudge.dispose();
|
|
326
343
|
await this.autoCompaction.dispose();
|
|
327
344
|
if (this.attachmentGcTimer !== undefined)
|
|
328
345
|
clearInterval(this.attachmentGcTimer);
|
|
@@ -332,14 +349,7 @@ let AgentTeam = (() => {
|
|
|
332
349
|
await Promise.all([...this.handles.values()].map(handle => handle.dispose()));
|
|
333
350
|
this.handles.clear();
|
|
334
351
|
this.modelSelections.clear();
|
|
335
|
-
this.
|
|
336
|
-
for (const dispose of this.skillProviderDisposals.values())
|
|
337
|
-
dispose();
|
|
338
|
-
this.skillProviderDisposals.clear();
|
|
339
|
-
for (const dispose of this.memberRestrictions.values())
|
|
340
|
-
dispose();
|
|
341
|
-
this.memberRestrictions.clear();
|
|
342
|
-
this.capabilityWarnings.clear();
|
|
352
|
+
this.memberRuntime.disposeAll();
|
|
343
353
|
this.runningAgents.clear();
|
|
344
354
|
await domain.close();
|
|
345
355
|
}, 'agentTeam.dispose');
|
|
@@ -357,7 +367,7 @@ let AgentTeam = (() => {
|
|
|
357
367
|
if (member.state === 'enabled')
|
|
358
368
|
await this.activateMember(member, undefined, persistedSessions);
|
|
359
369
|
else if (member.state === 'inactive')
|
|
360
|
-
await this.cleanupRemovedMember(member);
|
|
370
|
+
await this.memberRuntime.cleanupRemovedMember(member);
|
|
361
371
|
}
|
|
362
372
|
}
|
|
363
373
|
/** Resolve one exact live Agent to its durable Team Member; forks do not inherit identity. */
|
|
@@ -458,6 +468,20 @@ let AgentTeam = (() => {
|
|
|
458
468
|
this.emitCommitted(result.value.receipt);
|
|
459
469
|
return result.value;
|
|
460
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Archive one Channel: hidden from every surface with all facts kept. Pure
|
|
473
|
+
* ledger projection change — Member sessions stay live (they may work in
|
|
474
|
+
* other Channels), every active Claim on the Channel's Threads releases,
|
|
475
|
+
* and affected Members' Attention clears.
|
|
476
|
+
*/
|
|
477
|
+
async archiveChannel(request) {
|
|
478
|
+
this.requireAccepting();
|
|
479
|
+
this.requireWorkspace(request.workspaceId);
|
|
480
|
+
const result = await this.requireLedger().archiveChannel({ ...request, actor: agentTeamHumanActor() });
|
|
481
|
+
if (result.committed)
|
|
482
|
+
this.emitCommitted(result.value.receipt);
|
|
483
|
+
return result.value;
|
|
484
|
+
}
|
|
461
485
|
/** Create a durable Member and atomically grant its declared initial Channels. */
|
|
462
486
|
async addMember(request) {
|
|
463
487
|
return this.enqueueLifecycle(async () => {
|
|
@@ -583,12 +607,14 @@ let AgentTeam = (() => {
|
|
|
583
607
|
// Drop the old handle's transient state: pending recovery episodes and
|
|
584
608
|
// error markers belong to the disposed agent, not to the Member.
|
|
585
609
|
this.recovery.stopTracking(request.memberId);
|
|
610
|
+
// The fresh Session may re-earn one Claim suggestion per Thread; the
|
|
611
|
+
// old Session's one-shot records must not leak into it.
|
|
612
|
+
this.progressNudge.stopTracking(request.memberId);
|
|
613
|
+
this.memberBySessionId.delete(previousSessionId);
|
|
586
614
|
await active.dispose();
|
|
587
615
|
this.handles.delete(request.memberId);
|
|
588
616
|
this.modelSelections.delete(request.memberId);
|
|
589
|
-
this.
|
|
590
|
-
this.releaseMemberToolPolicy(request.memberId);
|
|
591
|
-
this.releaseMemberSkillProvider(request.memberId);
|
|
617
|
+
this.memberRuntime.forgetMember(request.memberId);
|
|
592
618
|
this.clearMemberFailure(request.memberId, 'activation');
|
|
593
619
|
this.clearMemberNotificationState(request.memberId);
|
|
594
620
|
// The previous log survives on disk; archiving hides it from every
|
|
@@ -647,6 +673,9 @@ let AgentTeam = (() => {
|
|
|
647
673
|
if (this.isInboxNotice(pending))
|
|
648
674
|
handle.agent.inbox.remove(pending.id);
|
|
649
675
|
}
|
|
676
|
+
// Recovery carries the concrete interrupted work; a queued progress nudge
|
|
677
|
+
// is stale next to it and must not survive as a second reminder.
|
|
678
|
+
this.progressNudge.revokePendingNotice(member.memberId);
|
|
650
679
|
handle.agent.steer(hint);
|
|
651
680
|
}
|
|
652
681
|
/** Automatic-recovery wakeup; throwing tells the coordinator the target is gone. */
|
|
@@ -696,37 +725,15 @@ let AgentTeam = (() => {
|
|
|
696
725
|
*/
|
|
697
726
|
async applyCapabilityEdit(active, stored) {
|
|
698
727
|
const memberId = stored.memberId;
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
resolve();
|
|
706
|
-
};
|
|
707
|
-
disposers.push(this.ctx.on('agent/status', (payload) => {
|
|
708
|
-
if (payload.agent !== active.agent)
|
|
709
|
-
return;
|
|
710
|
-
// A turn that ends — clean idle or error — is the boundary; the
|
|
711
|
-
// next step recomputes schemas from the new restriction.
|
|
712
|
-
if (payload.status !== 'running')
|
|
713
|
-
settle();
|
|
714
|
-
}),
|
|
715
|
-
// Disposal (suspend/remove/reactivation) resolves the wait: the old
|
|
716
|
-
// restriction went with the disposed scope, so only the ledger
|
|
717
|
-
// intent remains to apply at the next activation.
|
|
718
|
-
this.ctx.on('session/disposed', (session) => {
|
|
719
|
-
if (session.id === active.agent.session.id)
|
|
720
|
-
settle();
|
|
721
|
-
}));
|
|
722
|
-
});
|
|
723
|
-
if (this.handles.get(memberId) !== active)
|
|
724
|
-
return;
|
|
728
|
+
const waited = await this.memberRuntime.awaitTurnBoundary(active);
|
|
729
|
+
if (waited && this.handles.get(memberId) !== active) {
|
|
730
|
+
// The wait resolved because the old generation was disposed, not
|
|
731
|
+
// because the turn ended; the ledger intent applies at the next
|
|
732
|
+
// activation instead.
|
|
733
|
+
return;
|
|
725
734
|
}
|
|
726
|
-
this.reapplyMemberToolPolicy(stored);
|
|
727
|
-
|
|
728
|
-
if (skillSelection !== undefined)
|
|
729
|
-
skillSelection.swap(stored.capabilities?.skills?.allow);
|
|
735
|
+
this.memberRuntime.reapplyMemberToolPolicy(stored);
|
|
736
|
+
this.memberRuntime.swapSkillSelection(memberId, stored.capabilities?.skills?.allow);
|
|
730
737
|
}
|
|
731
738
|
/** Irreversibly remove one Member, archive its Session, and delete its private namespace. */
|
|
732
739
|
async removeMember(request) {
|
|
@@ -735,7 +742,23 @@ let AgentTeam = (() => {
|
|
|
735
742
|
if (result.committed)
|
|
736
743
|
this.emitCommitted(result.value.receipt);
|
|
737
744
|
await this.disposeMemberSession(request.memberId, result.value.member);
|
|
738
|
-
await this.cleanupRemovedMember(result.value.member);
|
|
745
|
+
await this.memberRuntime.cleanupRemovedMember(result.value.member);
|
|
746
|
+
return result.value;
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Archive one Member: commit the archival, stop its live session (disposal
|
|
751
|
+
* only — private memory and the Session log stay on disk for a future
|
|
752
|
+
* restore), and archive the Session from every grouping surface. Like
|
|
753
|
+
* removal, all active Claims release and the Member's Attention clears.
|
|
754
|
+
*/
|
|
755
|
+
async archiveMember(request) {
|
|
756
|
+
return this.enqueueLifecycle(async () => {
|
|
757
|
+
const result = await this.requireLedger().archiveMember({ ...request, actor: agentTeamHumanActor() });
|
|
758
|
+
if (result.committed)
|
|
759
|
+
this.emitCommitted(result.value.receipt);
|
|
760
|
+
await this.disposeMemberSession(request.memberId, result.value.member);
|
|
761
|
+
await this.ctx.workspaceRegistry.archiveSession(result.value.member.sessionId);
|
|
739
762
|
return result.value;
|
|
740
763
|
});
|
|
741
764
|
}
|
|
@@ -1068,7 +1091,7 @@ let AgentTeam = (() => {
|
|
|
1068
1091
|
try {
|
|
1069
1092
|
const workspace = this.requireWorkspace(member.workspaceId);
|
|
1070
1093
|
const workspacePath = knownWorkspacePath ?? workspace.path;
|
|
1071
|
-
await this.initializePrivateMemory(member.privateMemoryPath);
|
|
1094
|
+
await this.memberRuntime.initializePrivateMemory(member.privateMemoryPath);
|
|
1072
1095
|
const persisted = knownSessions !== undefined ? knownSessions.has(member.sessionId)
|
|
1073
1096
|
: (await this.ctx.sessionPersistence.list()).some(header => header.id === member.sessionId);
|
|
1074
1097
|
// AgentOptions declares only provider/model. Install the full selection
|
|
@@ -1083,7 +1106,7 @@ let AgentTeam = (() => {
|
|
|
1083
1106
|
const skillSelection = { current: member.capabilities?.skills?.allow, swap: () => { } };
|
|
1084
1107
|
const setup = async (agentCtx) => {
|
|
1085
1108
|
await this.ctx.agentPresets.mount(agentCtx, member.presetId);
|
|
1086
|
-
this.applyMemberToolPolicy(agentCtx, member);
|
|
1109
|
+
this.memberRuntime.applyMemberToolPolicy(agentCtx, member);
|
|
1087
1110
|
this.validateMemberPreset(agentCtx);
|
|
1088
1111
|
installModelSelection(agentCtx, selected);
|
|
1089
1112
|
return {
|
|
@@ -1091,7 +1114,13 @@ let AgentTeam = (() => {
|
|
|
1091
1114
|
const agent = agentCtx.agent;
|
|
1092
1115
|
if (agent === undefined)
|
|
1093
1116
|
throw new Error('agent-team setup has no unpublished Agent');
|
|
1094
|
-
|
|
1117
|
+
// The member scope composes no sandbox-policy service (the preset
|
|
1118
|
+
// owns no sandbox row), so read the last logged mode straight from
|
|
1119
|
+
// the session log; `sandbox/mode` is log-only and never joins the
|
|
1120
|
+
// model-visible surface. Re-appending only when the effective mode
|
|
1121
|
+
// differs keeps resumed members from growing redundant events.
|
|
1122
|
+
const logged = agent.session.ownEvents().toReversed().find(event => event.type === 'sandbox/mode');
|
|
1123
|
+
if (logged?.data.mode !== 'danger-full-access')
|
|
1095
1124
|
setSandboxMode(agent.session, 'danger-full-access');
|
|
1096
1125
|
},
|
|
1097
1126
|
};
|
|
@@ -1106,19 +1135,11 @@ let AgentTeam = (() => {
|
|
|
1106
1135
|
agentOptions,
|
|
1107
1136
|
setup,
|
|
1108
1137
|
});
|
|
1109
|
-
|
|
1110
|
-
// exact scope layer (the traceable-service seam, like the tool
|
|
1111
|
-
// restriction): bundled read-only core skills plus this Member's own
|
|
1112
|
-
// private directory.
|
|
1113
|
-
this.skillProviderDisposals.set(member.memberId, memberSkills.mountMemberSkillProvider(created.agent.ctx, {
|
|
1114
|
-
skillsDirectory: join(member.privateMemoryPath, 'skills'),
|
|
1115
|
-
bundledSkillsDirectory: BUNDLED_SKILLS_DIRECTORY,
|
|
1116
|
-
selection: skillSelection,
|
|
1117
|
-
}));
|
|
1138
|
+
this.memberRuntime.mountMemberSkillProvider(member, created.agent.ctx, skillSelection);
|
|
1118
1139
|
await workspace.attachSession(member.sessionId);
|
|
1119
1140
|
this.handles.set(member.memberId, created);
|
|
1141
|
+
this.memberBySessionId.set(member.sessionId, member.memberId);
|
|
1120
1142
|
this.modelSelections.set(member.memberId, selected);
|
|
1121
|
-
this.skillSelections.set(member.memberId, skillSelection);
|
|
1122
1143
|
this.clearMemberFailure(member.memberId, 'activation');
|
|
1123
1144
|
this.nameMemberSession(member, created.agent);
|
|
1124
1145
|
this.notifyMember(created.agent);
|
|
@@ -1127,9 +1148,7 @@ let AgentTeam = (() => {
|
|
|
1127
1148
|
catch (error) {
|
|
1128
1149
|
await created?.dispose();
|
|
1129
1150
|
this.modelSelections.delete(member.memberId);
|
|
1130
|
-
this.
|
|
1131
|
-
this.releaseMemberToolPolicy(member.memberId);
|
|
1132
|
-
this.releaseMemberSkillProvider(member.memberId);
|
|
1151
|
+
this.memberRuntime.forgetMember(member.memberId);
|
|
1133
1152
|
this.setMemberFailure(member.memberId, 'activation', error instanceof Error ? error.message : String(error));
|
|
1134
1153
|
}
|
|
1135
1154
|
finally {
|
|
@@ -1156,9 +1175,7 @@ let AgentTeam = (() => {
|
|
|
1156
1175
|
if (stale !== undefined) {
|
|
1157
1176
|
this.handles.delete(memberId);
|
|
1158
1177
|
this.modelSelections.delete(memberId);
|
|
1159
|
-
this.
|
|
1160
|
-
this.releaseMemberToolPolicy(memberId);
|
|
1161
|
-
this.releaseMemberSkillProvider(memberId);
|
|
1178
|
+
this.memberRuntime.forgetMember(memberId);
|
|
1162
1179
|
// The composition-loss diagnostic this heal answers is stale once the
|
|
1163
1180
|
// rebuild starts; a later activation must not resurface it.
|
|
1164
1181
|
this.clearMemberFailure(memberId, 'compaction');
|
|
@@ -1199,99 +1216,11 @@ let AgentTeam = (() => {
|
|
|
1199
1216
|
if (missing.length > 0)
|
|
1200
1217
|
throw new Error(`team-enabled preset is missing tools: ${missing.join(', ')}`);
|
|
1201
1218
|
}
|
|
1202
|
-
/**
|
|
1203
|
-
* Apply one Member's persisted tool allow-list as a scoped restriction on
|
|
1204
|
-
* the freshly composed preset surface, and derive activation-time warnings
|
|
1205
|
-
* for entries the current tool surface no longer knows. Runs inside setup
|
|
1206
|
-
* BEFORE validateMemberPreset so the validation observes the restricted
|
|
1207
|
-
* view (the Host always unions the five Team tools over the configured
|
|
1208
|
-
* list). Deliberate interface reservation: this restriction seam is the
|
|
1209
|
-
* primitive future Runtime Revision manifests orchestrate — do not remove
|
|
1210
|
-
* during cleanup.
|
|
1211
|
-
*/
|
|
1212
|
-
applyMemberToolPolicy(agentCtx, member) {
|
|
1213
|
-
const scope = scopeOf(agentCtx);
|
|
1214
|
-
const configured = member.capabilities?.tools?.allow;
|
|
1215
|
-
if (configured === undefined) {
|
|
1216
|
-
this.capabilityWarnings.delete(member.memberId);
|
|
1217
|
-
return;
|
|
1218
|
-
}
|
|
1219
|
-
// Drop names the current surface does not know rather than failing the
|
|
1220
|
-
// activation: a Harness upgrade renaming a tool must not make the Member
|
|
1221
|
-
// unavailable. The warning carries the known-name digest so a distant
|
|
1222
|
-
// future reader can diagnose the drift.
|
|
1223
|
-
const known = this.ctx.tools.schemas(scope).map(tool => tool.name);
|
|
1224
|
-
const knownSet = new Set(known);
|
|
1225
|
-
const dropped = configured.filter(name => !knownSet.has(name));
|
|
1226
|
-
this.setCapabilityWarnings(member.memberId, dropped.map(name => ({ name, knownNames: known })));
|
|
1227
|
-
const allow = [...new Set([...configured.filter(name => knownSet.has(name)), ...AGENT_TEAM_TOOL_NAMES])];
|
|
1228
|
-
if (allow.length === 0)
|
|
1229
|
-
return;
|
|
1230
|
-
// tools.restrict() requires a scoped context and rejects names outside
|
|
1231
|
-
// the inherited surface; both errors surface as this Member's activation
|
|
1232
|
-
// failure without touching any other Member.
|
|
1233
|
-
const dispose = agentCtx.tools.restrict({ allow });
|
|
1234
|
-
this.memberRestrictions.set(member.memberId, dispose);
|
|
1235
|
-
}
|
|
1236
|
-
/** Swap a live Member's tool policy at a turn boundary: dispose the old restriction, apply the new. */
|
|
1237
|
-
reapplyMemberToolPolicy(member) {
|
|
1238
|
-
this.releaseMemberToolPolicy(member.memberId);
|
|
1239
|
-
this.applyMemberToolPolicy(this.requireLiveMemberContext(member.memberId), member);
|
|
1240
|
-
}
|
|
1241
|
-
requireLiveMemberContext(memberId) {
|
|
1242
|
-
const handle = this.handles.get(memberId);
|
|
1243
|
-
if (handle === undefined)
|
|
1244
|
-
throw new Error(`Agent Member '${this.memberLabel(memberId)}' has no live session for a tool-policy update`);
|
|
1245
|
-
return handle.agent.ctx;
|
|
1246
|
-
}
|
|
1247
|
-
/** Release one Member's restriction disposer and warning state; safe to call twice. */
|
|
1248
|
-
releaseMemberToolPolicy(memberId) {
|
|
1249
|
-
const dispose = this.memberRestrictions.get(memberId);
|
|
1250
|
-
if (dispose !== undefined) {
|
|
1251
|
-
this.memberRestrictions.delete(memberId);
|
|
1252
|
-
dispose();
|
|
1253
|
-
}
|
|
1254
|
-
this.capabilityWarnings.delete(memberId);
|
|
1255
|
-
}
|
|
1256
|
-
/** Release one Member's private skill provider; safe to call twice. */
|
|
1257
|
-
releaseMemberSkillProvider(memberId) {
|
|
1258
|
-
const dispose = this.skillProviderDisposals.get(memberId);
|
|
1259
|
-
if (dispose === undefined)
|
|
1260
|
-
return;
|
|
1261
|
-
this.skillProviderDisposals.delete(memberId);
|
|
1262
|
-
dispose();
|
|
1263
|
-
}
|
|
1264
|
-
setCapabilityWarnings(memberId, warnings) {
|
|
1265
|
-
if (warnings.length === 0)
|
|
1266
|
-
this.capabilityWarnings.delete(memberId);
|
|
1267
|
-
else
|
|
1268
|
-
this.capabilityWarnings.set(memberId, Object.freeze([...warnings]));
|
|
1269
|
-
}
|
|
1270
|
-
async initializePrivateMemory(path) {
|
|
1271
|
-
await mkdir(join(path, 'notes'), { recursive: true });
|
|
1272
|
-
// The Member-private skills directory starts empty; the per-Member
|
|
1273
|
-
// provider scans exactly this root (default roots excluded).
|
|
1274
|
-
await mkdir(join(path, 'skills'), { recursive: true });
|
|
1275
|
-
try {
|
|
1276
|
-
await writeFile(join(path, 'memory.md'), '# Member memory\n\n## Stable facts\n- Add only verified, durable facts that help future work.\n\n## Notes index\n- Add focused `notes/*.md` entries here when a reusable detail needs on-demand reading.\n', { flag: 'wx' });
|
|
1277
|
-
}
|
|
1278
|
-
catch (error) {
|
|
1279
|
-
if (error.code !== 'EEXIST')
|
|
1280
|
-
throw error;
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
async cleanupRemovedMember(member) {
|
|
1284
|
-
const results = await Promise.allSettled([
|
|
1285
|
-
this.ctx.workspaceRegistry.archiveSession(member.sessionId),
|
|
1286
|
-
rm(member.privateMemoryPath, { recursive: true, force: true }),
|
|
1287
|
-
]);
|
|
1288
|
-
const failures = results.flatMap(result => result.status === 'rejected' ? [result.reason] : []);
|
|
1289
|
-
if (failures.length > 0)
|
|
1290
|
-
throw new AggregateError(failures, `failed to clean up removed Member '${member.memberId}'`);
|
|
1291
|
-
}
|
|
1292
1219
|
memberStatus(member) {
|
|
1293
1220
|
if (member.state === 'inactive')
|
|
1294
1221
|
return Object.freeze({ member, availability: 'inactive', presence: 'unavailable' });
|
|
1222
|
+
if (member.state === 'archived')
|
|
1223
|
+
return Object.freeze({ member, availability: 'archived', presence: 'unavailable' });
|
|
1295
1224
|
if (member.state === 'suspended')
|
|
1296
1225
|
return Object.freeze({ member, availability: 'suspended', presence: 'unavailable' });
|
|
1297
1226
|
const failures = this.memberFailures.get(member.memberId);
|
|
@@ -1308,7 +1237,7 @@ let AgentTeam = (() => {
|
|
|
1308
1237
|
return Object.freeze({ member, availability: 'active', presence: 'error', diagnostic: runtimeError });
|
|
1309
1238
|
// Capability warnings are runtime-derived at activation (handles-scoped,
|
|
1310
1239
|
// like failures): absent while capabilities resolve cleanly.
|
|
1311
|
-
const capabilityWarnings = this.
|
|
1240
|
+
const capabilityWarnings = this.memberRuntime.capabilityWarningsFor(member.memberId);
|
|
1312
1241
|
return Object.freeze({
|
|
1313
1242
|
member, availability: 'active', presence: handle.agent.status === 'running' ? 'working' : 'available',
|
|
1314
1243
|
...(capabilityWarnings === undefined ? {} : { capabilityWarnings }),
|
|
@@ -1353,6 +1282,10 @@ let AgentTeam = (() => {
|
|
|
1353
1282
|
}
|
|
1354
1283
|
const ledger = this.requireLedger();
|
|
1355
1284
|
this.emitChanged(ledger.changeScopesOf(operation));
|
|
1285
|
+
// Nudge reconciliation precedes notifyMember: a committed reply both
|
|
1286
|
+
// resets the author's silence and cancels any of its queued nudge before
|
|
1287
|
+
// the Inbox notice (higher priority) is considered.
|
|
1288
|
+
this.progressNudge.onCommitted(operation);
|
|
1356
1289
|
for (const memberId of ledger.affectedMembersOf(operation)) {
|
|
1357
1290
|
const handle = this.handles.get(memberId);
|
|
1358
1291
|
if (handle !== undefined)
|
|
@@ -1391,6 +1324,9 @@ let AgentTeam = (() => {
|
|
|
1391
1324
|
const existingInboxHint = pending.find(message => this.isInboxNotice(message));
|
|
1392
1325
|
if (existingInboxHint !== undefined)
|
|
1393
1326
|
agent.inbox.remove(existingInboxHint.id);
|
|
1327
|
+
// A durable Inbox notice outranks a queued progress nudge; revoke it so
|
|
1328
|
+
// the model reads concrete unread work instead of a generic reminder.
|
|
1329
|
+
this.progressNudge.revokePendingNotice(member.memberId);
|
|
1394
1330
|
const hint = createUserMessage({
|
|
1395
1331
|
content: [{ type: 'text', text: this.notificationText(notifications, member.memberId) }],
|
|
1396
1332
|
source: { kind: 'plugin', plugin: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: INBOX_NOTICE_SUMMARY },
|
|
@@ -1496,14 +1432,14 @@ let AgentTeam = (() => {
|
|
|
1496
1432
|
await handle.dispose();
|
|
1497
1433
|
this.handles.delete(memberId);
|
|
1498
1434
|
}
|
|
1435
|
+
this.memberBySessionId.delete(member.sessionId);
|
|
1499
1436
|
this.modelSelections.delete(memberId);
|
|
1500
|
-
this.
|
|
1501
|
-
this.releaseMemberToolPolicy(memberId);
|
|
1502
|
-
this.releaseMemberSkillProvider(memberId);
|
|
1437
|
+
this.memberRuntime.forgetMember(memberId);
|
|
1503
1438
|
this.clearMemberFailure(memberId, 'activation');
|
|
1504
1439
|
}
|
|
1505
1440
|
clearMemberRecoveryState(member) {
|
|
1506
1441
|
this.recovery.stopTracking(member.memberId);
|
|
1442
|
+
this.progressNudge.stopTracking(member.memberId);
|
|
1507
1443
|
this.clearMemberFailure(member.memberId, 'runtime');
|
|
1508
1444
|
this.clearMemberNotificationState(member.memberId);
|
|
1509
1445
|
}
|