@wowyuarm/dsh-agent-team 0.1.6 → 0.1.7
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/lib/index.js +82 -204
- package/packages/agent-team/lib/ledger.js +301 -13
- package/packages/agent-team/lib/member-context.js +5 -1
- 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/spec.js +30 -1
- package/packages/agent-team/lib/typert.host.js +253 -74
- 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 +172 -43
- package/packages/agent-team/lib/types/entities.js +1 -0
- package/packages/agent-team/lib/types/index.d.ts +20 -44
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +34 -1
- 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/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 +339 -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 +527 -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 +4 -2
- 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 +444 -298
- 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 +2 -2
- 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.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +2 -1
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts +12 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberDock.js +13 -0
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +10 -3
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- 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 +25 -28
- package/packages/client-agent-team/lib/types/client/locales.d.ts +28 -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 +28 -0
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +1 -3
- package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/member-session-input.js +18 -6
- 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-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 +3 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- 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/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
|
@@ -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,20 @@ 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";
|
|
59
56
|
import { classifyRecoverableError, RecoveryCoordinator, RECOVERY_MAX_CONSECUTIVE_ERRORS } from "./recovery.js";
|
|
60
57
|
import { agentTeamDomainSpec } from "./spec.js";
|
|
61
58
|
export { agentTeamDomainSpec, agentTeamOperationSchema } from "./spec.js";
|
|
62
59
|
export { AGENT_TEAM_HUMAN_MEMBER_ID, AGENT_TEAM_INITIALIZE_REQUEST_ID } from "./ledger.js";
|
|
60
|
+
export { AGENT_TEAM_TOOL_NAMES } from "./member-runtime.js";
|
|
63
61
|
/** Process-stable marker carried by the final Team message tool definition. */
|
|
64
62
|
export const AGENT_TEAM_PRESET_MARKER = Symbol.for('@wowyuarm/dsh-agent-team.preset');
|
|
65
63
|
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
64
|
const INBOX_NOTICE_SUMMARY = 'Team Inbox has unread work.';
|
|
74
65
|
const RECOVERY_NOTICE_SUMMARY = 'Recovery: continue your interrupted work.';
|
|
75
66
|
const ORPHANED_MEMBER_DIAGNOSTIC = 'Member preset composition was lost after a reload; its tools are unavailable. Resume rebuilds the member in place.';
|
|
@@ -82,27 +73,11 @@ function sameChangeScope(left, right) {
|
|
|
82
73
|
return left.threadRef === right.threadRef;
|
|
83
74
|
return false;
|
|
84
75
|
}
|
|
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
76
|
/** Mark the preset's `team_message` definition as an Agent Team consumer. */
|
|
94
77
|
export function markAgentTeamPreset(definition) {
|
|
95
78
|
Object.defineProperty(definition, AGENT_TEAM_PRESET_MARKER, { value: true });
|
|
96
79
|
return definition;
|
|
97
80
|
}
|
|
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
81
|
/**
|
|
107
82
|
* A DM was durably recorded but its session injection could not run (no live
|
|
108
83
|
* handle, or the wake itself failed). The recorded DM stays durable; the
|
|
@@ -127,10 +102,12 @@ let AgentTeam = (() => {
|
|
|
127
102
|
let _changes_decorators;
|
|
128
103
|
let _createChannel_decorators;
|
|
129
104
|
let _updateChannel_decorators;
|
|
105
|
+
let _archiveChannel_decorators;
|
|
130
106
|
let _addMember_decorators;
|
|
131
107
|
let _recoverMember_decorators;
|
|
132
108
|
let _clearMemberContext_decorators;
|
|
133
109
|
let _updateMember_decorators;
|
|
110
|
+
let _archiveMember_decorators;
|
|
134
111
|
let _changeTask_decorators;
|
|
135
112
|
let _promoteThread_decorators;
|
|
136
113
|
let _joinChannel_decorators;
|
|
@@ -153,10 +130,12 @@ let AgentTeam = (() => {
|
|
|
153
130
|
_changes_decorators = [Remote('changes')];
|
|
154
131
|
_createChannel_decorators = [Remote('createChannel')];
|
|
155
132
|
_updateChannel_decorators = [Remote('updateChannel')];
|
|
133
|
+
_archiveChannel_decorators = [Remote('archiveChannel')];
|
|
156
134
|
_addMember_decorators = [Remote('addMember')];
|
|
157
135
|
_recoverMember_decorators = [Remote('recoverMember')];
|
|
158
136
|
_clearMemberContext_decorators = [Remote('clearMemberContext')];
|
|
159
137
|
_updateMember_decorators = [Remote('updateMember')];
|
|
138
|
+
_archiveMember_decorators = [Remote('archiveMember')];
|
|
160
139
|
_changeTask_decorators = [Remote('changeTask')];
|
|
161
140
|
_promoteThread_decorators = [Remote('promoteThread')];
|
|
162
141
|
_joinChannel_decorators = [Remote('joinChannel')];
|
|
@@ -176,10 +155,12 @@ let AgentTeam = (() => {
|
|
|
176
155
|
__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
156
|
__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
157
|
__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);
|
|
158
|
+
__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
159
|
__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
160
|
__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
161
|
__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
162
|
__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);
|
|
163
|
+
__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
164
|
__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
165
|
__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
166
|
__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);
|
|
@@ -210,10 +191,21 @@ let AgentTeam = (() => {
|
|
|
210
191
|
handles = new Map();
|
|
211
192
|
/** Live selection refs let model edits take effect without disposing the Session. */
|
|
212
193
|
modelSelections = new Map();
|
|
213
|
-
/**
|
|
214
|
-
|
|
215
|
-
/** Per-Member
|
|
216
|
-
|
|
194
|
+
/** Agent ids with a turn in flight; restarts must wait for the boundary. */
|
|
195
|
+
runningAgents = new Set();
|
|
196
|
+
/** Per-Member runtime state: tool restrictions, skill mounts, warnings, private memory. */
|
|
197
|
+
memberRuntime = new MemberRuntime({
|
|
198
|
+
// Deferred field access: the constructor runs before `handles` is
|
|
199
|
+
// populated, so the resolver must dereference at call time.
|
|
200
|
+
ctx: this.ctx,
|
|
201
|
+
liveMemberContext: memberId => {
|
|
202
|
+
const handle = this.handles.get(memberId);
|
|
203
|
+
if (handle === undefined)
|
|
204
|
+
throw new Error(`Agent Member '${this.memberLabel(memberId)}' has no live session for a tool-policy update`);
|
|
205
|
+
return handle.agent.ctx;
|
|
206
|
+
},
|
|
207
|
+
runningAgents: this.runningAgents,
|
|
208
|
+
});
|
|
217
209
|
/**
|
|
218
210
|
* Why one Member shows error presence, per failure source. Reads prefer
|
|
219
211
|
* activation, then runtime, then compaction; slots clear independently, so
|
|
@@ -222,23 +214,7 @@ let AgentTeam = (() => {
|
|
|
222
214
|
* stale keys.
|
|
223
215
|
*/
|
|
224
216
|
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
217
|
autoCompaction;
|
|
240
|
-
/** Agent ids with a turn in flight; restarts must wait for the boundary. */
|
|
241
|
-
runningAgents = new Set();
|
|
242
218
|
notifiedInbox = new Map();
|
|
243
219
|
attachmentGcTimer;
|
|
244
220
|
recovery = new RecoveryCoordinator({
|
|
@@ -332,14 +308,7 @@ let AgentTeam = (() => {
|
|
|
332
308
|
await Promise.all([...this.handles.values()].map(handle => handle.dispose()));
|
|
333
309
|
this.handles.clear();
|
|
334
310
|
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();
|
|
311
|
+
this.memberRuntime.disposeAll();
|
|
343
312
|
this.runningAgents.clear();
|
|
344
313
|
await domain.close();
|
|
345
314
|
}, 'agentTeam.dispose');
|
|
@@ -357,7 +326,7 @@ let AgentTeam = (() => {
|
|
|
357
326
|
if (member.state === 'enabled')
|
|
358
327
|
await this.activateMember(member, undefined, persistedSessions);
|
|
359
328
|
else if (member.state === 'inactive')
|
|
360
|
-
await this.cleanupRemovedMember(member);
|
|
329
|
+
await this.memberRuntime.cleanupRemovedMember(member);
|
|
361
330
|
}
|
|
362
331
|
}
|
|
363
332
|
/** Resolve one exact live Agent to its durable Team Member; forks do not inherit identity. */
|
|
@@ -458,6 +427,20 @@ let AgentTeam = (() => {
|
|
|
458
427
|
this.emitCommitted(result.value.receipt);
|
|
459
428
|
return result.value;
|
|
460
429
|
}
|
|
430
|
+
/**
|
|
431
|
+
* Archive one Channel: hidden from every surface with all facts kept. Pure
|
|
432
|
+
* ledger projection change — Member sessions stay live (they may work in
|
|
433
|
+
* other Channels), every active Claim on the Channel's Threads releases,
|
|
434
|
+
* and affected Members' Attention clears.
|
|
435
|
+
*/
|
|
436
|
+
async archiveChannel(request) {
|
|
437
|
+
this.requireAccepting();
|
|
438
|
+
this.requireWorkspace(request.workspaceId);
|
|
439
|
+
const result = await this.requireLedger().archiveChannel({ ...request, actor: agentTeamHumanActor() });
|
|
440
|
+
if (result.committed)
|
|
441
|
+
this.emitCommitted(result.value.receipt);
|
|
442
|
+
return result.value;
|
|
443
|
+
}
|
|
461
444
|
/** Create a durable Member and atomically grant its declared initial Channels. */
|
|
462
445
|
async addMember(request) {
|
|
463
446
|
return this.enqueueLifecycle(async () => {
|
|
@@ -586,9 +569,7 @@ let AgentTeam = (() => {
|
|
|
586
569
|
await active.dispose();
|
|
587
570
|
this.handles.delete(request.memberId);
|
|
588
571
|
this.modelSelections.delete(request.memberId);
|
|
589
|
-
this.
|
|
590
|
-
this.releaseMemberToolPolicy(request.memberId);
|
|
591
|
-
this.releaseMemberSkillProvider(request.memberId);
|
|
572
|
+
this.memberRuntime.forgetMember(request.memberId);
|
|
592
573
|
this.clearMemberFailure(request.memberId, 'activation');
|
|
593
574
|
this.clearMemberNotificationState(request.memberId);
|
|
594
575
|
// The previous log survives on disk; archiving hides it from every
|
|
@@ -696,37 +677,15 @@ let AgentTeam = (() => {
|
|
|
696
677
|
*/
|
|
697
678
|
async applyCapabilityEdit(active, stored) {
|
|
698
679
|
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;
|
|
680
|
+
const waited = await this.memberRuntime.awaitTurnBoundary(active);
|
|
681
|
+
if (waited && this.handles.get(memberId) !== active) {
|
|
682
|
+
// The wait resolved because the old generation was disposed, not
|
|
683
|
+
// because the turn ended; the ledger intent applies at the next
|
|
684
|
+
// activation instead.
|
|
685
|
+
return;
|
|
725
686
|
}
|
|
726
|
-
this.reapplyMemberToolPolicy(stored);
|
|
727
|
-
|
|
728
|
-
if (skillSelection !== undefined)
|
|
729
|
-
skillSelection.swap(stored.capabilities?.skills?.allow);
|
|
687
|
+
this.memberRuntime.reapplyMemberToolPolicy(stored);
|
|
688
|
+
this.memberRuntime.swapSkillSelection(memberId, stored.capabilities?.skills?.allow);
|
|
730
689
|
}
|
|
731
690
|
/** Irreversibly remove one Member, archive its Session, and delete its private namespace. */
|
|
732
691
|
async removeMember(request) {
|
|
@@ -735,7 +694,23 @@ let AgentTeam = (() => {
|
|
|
735
694
|
if (result.committed)
|
|
736
695
|
this.emitCommitted(result.value.receipt);
|
|
737
696
|
await this.disposeMemberSession(request.memberId, result.value.member);
|
|
738
|
-
await this.cleanupRemovedMember(result.value.member);
|
|
697
|
+
await this.memberRuntime.cleanupRemovedMember(result.value.member);
|
|
698
|
+
return result.value;
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Archive one Member: commit the archival, stop its live session (disposal
|
|
703
|
+
* only — private memory and the Session log stay on disk for a future
|
|
704
|
+
* restore), and archive the Session from every grouping surface. Like
|
|
705
|
+
* removal, all active Claims release and the Member's Attention clears.
|
|
706
|
+
*/
|
|
707
|
+
async archiveMember(request) {
|
|
708
|
+
return this.enqueueLifecycle(async () => {
|
|
709
|
+
const result = await this.requireLedger().archiveMember({ ...request, actor: agentTeamHumanActor() });
|
|
710
|
+
if (result.committed)
|
|
711
|
+
this.emitCommitted(result.value.receipt);
|
|
712
|
+
await this.disposeMemberSession(request.memberId, result.value.member);
|
|
713
|
+
await this.ctx.workspaceRegistry.archiveSession(result.value.member.sessionId);
|
|
739
714
|
return result.value;
|
|
740
715
|
});
|
|
741
716
|
}
|
|
@@ -1068,7 +1043,7 @@ let AgentTeam = (() => {
|
|
|
1068
1043
|
try {
|
|
1069
1044
|
const workspace = this.requireWorkspace(member.workspaceId);
|
|
1070
1045
|
const workspacePath = knownWorkspacePath ?? workspace.path;
|
|
1071
|
-
await this.initializePrivateMemory(member.privateMemoryPath);
|
|
1046
|
+
await this.memberRuntime.initializePrivateMemory(member.privateMemoryPath);
|
|
1072
1047
|
const persisted = knownSessions !== undefined ? knownSessions.has(member.sessionId)
|
|
1073
1048
|
: (await this.ctx.sessionPersistence.list()).some(header => header.id === member.sessionId);
|
|
1074
1049
|
// AgentOptions declares only provider/model. Install the full selection
|
|
@@ -1083,7 +1058,7 @@ let AgentTeam = (() => {
|
|
|
1083
1058
|
const skillSelection = { current: member.capabilities?.skills?.allow, swap: () => { } };
|
|
1084
1059
|
const setup = async (agentCtx) => {
|
|
1085
1060
|
await this.ctx.agentPresets.mount(agentCtx, member.presetId);
|
|
1086
|
-
this.applyMemberToolPolicy(agentCtx, member);
|
|
1061
|
+
this.memberRuntime.applyMemberToolPolicy(agentCtx, member);
|
|
1087
1062
|
this.validateMemberPreset(agentCtx);
|
|
1088
1063
|
installModelSelection(agentCtx, selected);
|
|
1089
1064
|
return {
|
|
@@ -1091,7 +1066,13 @@ let AgentTeam = (() => {
|
|
|
1091
1066
|
const agent = agentCtx.agent;
|
|
1092
1067
|
if (agent === undefined)
|
|
1093
1068
|
throw new Error('agent-team setup has no unpublished Agent');
|
|
1094
|
-
|
|
1069
|
+
// The member scope composes no sandbox-policy service (the preset
|
|
1070
|
+
// owns no sandbox row), so read the last logged mode straight from
|
|
1071
|
+
// the session log; `sandbox/mode` is log-only and never joins the
|
|
1072
|
+
// model-visible surface. Re-appending only when the effective mode
|
|
1073
|
+
// differs keeps resumed members from growing redundant events.
|
|
1074
|
+
const logged = agent.session.ownEvents().toReversed().find(event => event.type === 'sandbox/mode');
|
|
1075
|
+
if (logged?.data.mode !== 'danger-full-access')
|
|
1095
1076
|
setSandboxMode(agent.session, 'danger-full-access');
|
|
1096
1077
|
},
|
|
1097
1078
|
};
|
|
@@ -1106,19 +1087,10 @@ let AgentTeam = (() => {
|
|
|
1106
1087
|
agentOptions,
|
|
1107
1088
|
setup,
|
|
1108
1089
|
});
|
|
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
|
-
}));
|
|
1090
|
+
this.memberRuntime.mountMemberSkillProvider(member, created.agent.ctx, skillSelection);
|
|
1118
1091
|
await workspace.attachSession(member.sessionId);
|
|
1119
1092
|
this.handles.set(member.memberId, created);
|
|
1120
1093
|
this.modelSelections.set(member.memberId, selected);
|
|
1121
|
-
this.skillSelections.set(member.memberId, skillSelection);
|
|
1122
1094
|
this.clearMemberFailure(member.memberId, 'activation');
|
|
1123
1095
|
this.nameMemberSession(member, created.agent);
|
|
1124
1096
|
this.notifyMember(created.agent);
|
|
@@ -1127,9 +1099,7 @@ let AgentTeam = (() => {
|
|
|
1127
1099
|
catch (error) {
|
|
1128
1100
|
await created?.dispose();
|
|
1129
1101
|
this.modelSelections.delete(member.memberId);
|
|
1130
|
-
this.
|
|
1131
|
-
this.releaseMemberToolPolicy(member.memberId);
|
|
1132
|
-
this.releaseMemberSkillProvider(member.memberId);
|
|
1102
|
+
this.memberRuntime.forgetMember(member.memberId);
|
|
1133
1103
|
this.setMemberFailure(member.memberId, 'activation', error instanceof Error ? error.message : String(error));
|
|
1134
1104
|
}
|
|
1135
1105
|
finally {
|
|
@@ -1156,9 +1126,7 @@ let AgentTeam = (() => {
|
|
|
1156
1126
|
if (stale !== undefined) {
|
|
1157
1127
|
this.handles.delete(memberId);
|
|
1158
1128
|
this.modelSelections.delete(memberId);
|
|
1159
|
-
this.
|
|
1160
|
-
this.releaseMemberToolPolicy(memberId);
|
|
1161
|
-
this.releaseMemberSkillProvider(memberId);
|
|
1129
|
+
this.memberRuntime.forgetMember(memberId);
|
|
1162
1130
|
// The composition-loss diagnostic this heal answers is stale once the
|
|
1163
1131
|
// rebuild starts; a later activation must not resurface it.
|
|
1164
1132
|
this.clearMemberFailure(memberId, 'compaction');
|
|
@@ -1199,99 +1167,11 @@ let AgentTeam = (() => {
|
|
|
1199
1167
|
if (missing.length > 0)
|
|
1200
1168
|
throw new Error(`team-enabled preset is missing tools: ${missing.join(', ')}`);
|
|
1201
1169
|
}
|
|
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
1170
|
memberStatus(member) {
|
|
1293
1171
|
if (member.state === 'inactive')
|
|
1294
1172
|
return Object.freeze({ member, availability: 'inactive', presence: 'unavailable' });
|
|
1173
|
+
if (member.state === 'archived')
|
|
1174
|
+
return Object.freeze({ member, availability: 'archived', presence: 'unavailable' });
|
|
1295
1175
|
if (member.state === 'suspended')
|
|
1296
1176
|
return Object.freeze({ member, availability: 'suspended', presence: 'unavailable' });
|
|
1297
1177
|
const failures = this.memberFailures.get(member.memberId);
|
|
@@ -1308,7 +1188,7 @@ let AgentTeam = (() => {
|
|
|
1308
1188
|
return Object.freeze({ member, availability: 'active', presence: 'error', diagnostic: runtimeError });
|
|
1309
1189
|
// Capability warnings are runtime-derived at activation (handles-scoped,
|
|
1310
1190
|
// like failures): absent while capabilities resolve cleanly.
|
|
1311
|
-
const capabilityWarnings = this.
|
|
1191
|
+
const capabilityWarnings = this.memberRuntime.capabilityWarningsFor(member.memberId);
|
|
1312
1192
|
return Object.freeze({
|
|
1313
1193
|
member, availability: 'active', presence: handle.agent.status === 'running' ? 'working' : 'available',
|
|
1314
1194
|
...(capabilityWarnings === undefined ? {} : { capabilityWarnings }),
|
|
@@ -1497,9 +1377,7 @@ let AgentTeam = (() => {
|
|
|
1497
1377
|
this.handles.delete(memberId);
|
|
1498
1378
|
}
|
|
1499
1379
|
this.modelSelections.delete(memberId);
|
|
1500
|
-
this.
|
|
1501
|
-
this.releaseMemberToolPolicy(memberId);
|
|
1502
|
-
this.releaseMemberSkillProvider(memberId);
|
|
1380
|
+
this.memberRuntime.forgetMember(memberId);
|
|
1503
1381
|
this.clearMemberFailure(memberId, 'activation');
|
|
1504
1382
|
}
|
|
1505
1383
|
clearMemberRecoveryState(member) {
|