@wowyuarm/dsh-agent-team 0.1.12 → 0.1.14-alpha.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 +3 -1
- package/README.zh.md +3 -1
- package/cordis.patch.yml +7 -3
- package/package.json +57 -45
- package/packages/agent-team/README.md +2 -2
- package/packages/agent-team/README.zh.md +2 -2
- package/packages/agent-team/lib/index.js +151 -69
- package/packages/agent-team/lib/ledger.js +249 -31
- package/packages/agent-team/lib/member-context.js +18 -1
- package/packages/agent-team/lib/member-runtime.js +5 -4
- package/packages/agent-team/lib/mentions.js +48 -24
- package/packages/agent-team/lib/spec.js +19 -0
- package/packages/agent-team/lib/typert.host.js +187 -41
- package/packages/agent-team/lib/typert.remote-client.d.ts +7 -3
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +132 -27
- package/packages/agent-team/lib/types/index.d.ts +32 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +46 -2
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts +6 -0
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/mentions.d.ts +20 -7
- package/packages/agent-team/lib/types/mentions.d.ts.map +1 -1
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +3 -2
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/operations.d.ts +37 -1
- package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +50 -10
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts +87 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/index.d.ts.map +1 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts +59 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/schema.d.ts.map +1 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts +57 -0
- package/packages/agent-team/lib/types/vendor/storage-sqlite/unit.d.ts.map +1 -0
- package/packages/agent-team/lib/vendor/storage-sqlite/index.js +139 -0
- package/packages/agent-team/lib/vendor/storage-sqlite/schema.js +120 -0
- package/packages/agent-team/lib/vendor/storage-sqlite/unit.js +132 -0
- package/packages/client-agent-team/README.md +1 -1
- package/packages/client-agent-team/README.zh.md +1 -1
- package/packages/client-agent-team/lib/client.js +604 -344
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts +12 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentImport.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentImport.js +69 -0
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +3 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +29 -17
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +19 -44
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +15 -14
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -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 +15 -29
- 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/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +8 -1
- package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -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 +18 -0
- 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-changes.d.ts +15 -31
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.js +82 -111
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +13 -11
- 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 +29 -35
- package/packages/tool-agent-team/README.md +1 -1
- package/packages/tool-agent-team/README.zh.md +1 -1
- package/packages/tool-agent-team/lib/host-access.js +19 -0
- package/packages/tool-agent-team/lib/index.js +42 -33
- package/packages/tool-agent-team/lib/types/host-access.d.ts +10 -0
- package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -1
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +0 -41
- package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/scope-coverage.js +0 -64
|
@@ -178,6 +178,8 @@ let AgentTeam = (() => {
|
|
|
178
178
|
let _promoteThread_decorators;
|
|
179
179
|
let _joinChannel_decorators;
|
|
180
180
|
let _removeChannelMember_decorators;
|
|
181
|
+
let _joinWorkspace_decorators;
|
|
182
|
+
let _leaveWorkspace_decorators;
|
|
181
183
|
let _sendMessage_decorators;
|
|
182
184
|
let _putAttachment_decorators;
|
|
183
185
|
let _getAttachment_decorators;
|
|
@@ -193,7 +195,7 @@ let AgentTeam = (() => {
|
|
|
193
195
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
194
196
|
_resolveTaskRefs_decorators = [Remote('resolveTaskRefs')];
|
|
195
197
|
_membersForClient_decorators = [Remote('members')];
|
|
196
|
-
_changes_decorators = [Remote('
|
|
198
|
+
_changes_decorators = [Remote({ mode: 'stream' })];
|
|
197
199
|
_createChannel_decorators = [Remote('createChannel')];
|
|
198
200
|
_updateChannel_decorators = [Remote('updateChannel')];
|
|
199
201
|
_archiveChannel_decorators = [Remote('archiveChannel')];
|
|
@@ -206,6 +208,8 @@ let AgentTeam = (() => {
|
|
|
206
208
|
_promoteThread_decorators = [Remote('promoteThread')];
|
|
207
209
|
_joinChannel_decorators = [Remote('joinChannel')];
|
|
208
210
|
_removeChannelMember_decorators = [Remote('removeChannelMember')];
|
|
211
|
+
_joinWorkspace_decorators = [Remote('joinWorkspace')];
|
|
212
|
+
_leaveWorkspace_decorators = [Remote('leaveWorkspace')];
|
|
209
213
|
_sendMessage_decorators = [Remote('sendMessage')];
|
|
210
214
|
_putAttachment_decorators = [Remote('putAttachment')];
|
|
211
215
|
_getAttachment_decorators = [Remote('getAttachment')];
|
|
@@ -231,6 +235,8 @@ let AgentTeam = (() => {
|
|
|
231
235
|
__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);
|
|
232
236
|
__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);
|
|
233
237
|
__esDecorate(this, null, _removeChannelMember_decorators, { kind: "method", name: "removeChannelMember", static: false, private: false, access: { has: obj => "removeChannelMember" in obj, get: obj => obj.removeChannelMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
238
|
+
__esDecorate(this, null, _joinWorkspace_decorators, { kind: "method", name: "joinWorkspace", static: false, private: false, access: { has: obj => "joinWorkspace" in obj, get: obj => obj.joinWorkspace }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
239
|
+
__esDecorate(this, null, _leaveWorkspace_decorators, { kind: "method", name: "leaveWorkspace", static: false, private: false, access: { has: obj => "leaveWorkspace" in obj, get: obj => obj.leaveWorkspace }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
234
240
|
__esDecorate(this, null, _sendMessage_decorators, { kind: "method", name: "sendMessage", static: false, private: false, access: { has: obj => "sendMessage" in obj, get: obj => obj.sendMessage }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
235
241
|
__esDecorate(this, null, _putAttachment_decorators, { kind: "method", name: "putAttachment", static: false, private: false, access: { has: obj => "putAttachment" in obj, get: obj => obj.putAttachment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
236
242
|
__esDecorate(this, null, _getAttachment_decorators, { kind: "method", name: "getAttachment", static: false, private: false, access: { has: obj => "getAttachment" in obj, get: obj => obj.getAttachment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -382,7 +388,7 @@ let AgentTeam = (() => {
|
|
|
382
388
|
if (kind !== undefined)
|
|
383
389
|
this.ctx.logger.warn(`agent-team: member '${member.handle}' hit a recoverable ${kind} error; recording a consecutive error occurrence`);
|
|
384
390
|
this.recovery.onError(member.memberId, message);
|
|
385
|
-
this.
|
|
391
|
+
this.emitMemberPresenceChanged(member);
|
|
386
392
|
});
|
|
387
393
|
this.ctx.on('agent/status', ({ agent, status }) => {
|
|
388
394
|
const member = this.memberForAgent(agent);
|
|
@@ -394,7 +400,7 @@ let AgentTeam = (() => {
|
|
|
394
400
|
const recovered = this.clearMemberFailure(member.memberId, 'runtime');
|
|
395
401
|
if (recovered)
|
|
396
402
|
this.notifiedInbox.delete(member.memberId);
|
|
397
|
-
this.
|
|
403
|
+
this.emitMemberPresenceChanged(member);
|
|
398
404
|
// A rollover/recovery in flight delivers its own sequenced
|
|
399
405
|
// rederived Inbox after the handoff and carried input; a status-driven
|
|
400
406
|
// steer here would claim the handoff turn's next step and leapfrog
|
|
@@ -411,7 +417,7 @@ let AgentTeam = (() => {
|
|
|
411
417
|
if (this.memberFailures.get(member.memberId)?.runtime === undefined) {
|
|
412
418
|
this.recovery.onCleanTurnEnd(member.memberId);
|
|
413
419
|
}
|
|
414
|
-
this.
|
|
420
|
+
this.emitMemberPresenceChanged(member);
|
|
415
421
|
}
|
|
416
422
|
});
|
|
417
423
|
// The store's dispatch carrier is untagged, so a scope-tagged listener
|
|
@@ -477,6 +483,7 @@ let AgentTeam = (() => {
|
|
|
477
483
|
// One metadata listing serves every Member restore; per-member list calls
|
|
478
484
|
// would repeat the same I/O linearly during startup.
|
|
479
485
|
const persistedSessions = new Set((await this.persistedSessionHeaders()).map(snapshot => snapshot.header.id));
|
|
486
|
+
await this.sweepWorkspaceParticipations(ledger);
|
|
480
487
|
for (const member of ledger.listMembers()) {
|
|
481
488
|
if (member.state === 'enabled')
|
|
482
489
|
await this.activateMember(member, undefined, persistedSessions);
|
|
@@ -484,6 +491,31 @@ let AgentTeam = (() => {
|
|
|
484
491
|
await this.memberRuntime.cleanupRemovedMember(member);
|
|
485
492
|
}
|
|
486
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Lazy Workspace-deletion handling: a Workspace that no longer exists can
|
|
496
|
+
* only be detected through the registry — there is no deletion event. A
|
|
497
|
+
* dead non-default participation is withdrawn here (its Claims and
|
|
498
|
+
* Attention release through the normal leave path); a dead default
|
|
499
|
+
* Workspace is left alone — activation fails on its missing cwd and the
|
|
500
|
+
* Member surfaces as unavailable for Human attention.
|
|
501
|
+
*/
|
|
502
|
+
async sweepWorkspaceParticipations(ledger) {
|
|
503
|
+
for (const member of ledger.listMembers()) {
|
|
504
|
+
if (member.state === 'inactive' || member.state === 'archived')
|
|
505
|
+
continue;
|
|
506
|
+
for (const workspaceId of ledger.workspacesOf(member.memberId)) {
|
|
507
|
+
if (workspaceId === member.workspaceId || this.ctx.workspaceRegistry.get(workspaceId) !== undefined)
|
|
508
|
+
continue;
|
|
509
|
+
this.ctx.logger.warn(`agent-team: workspace '${workspaceId}' is gone; withdrawing member '${member.handle}' from it`);
|
|
510
|
+
try {
|
|
511
|
+
await ledger.leaveWorkspace({ requestId: randomUUID(), workspaceId, memberId: member.memberId, actor: agentTeamHumanActor() });
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
this.ctx.logger.warn(`agent-team: failed to withdraw member '${member.handle}' from deleted workspace '${workspaceId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
487
519
|
/**
|
|
488
520
|
* Whether one Member Session has durable persisted content, decided through
|
|
489
521
|
* {@link SessionPersistence.stat} rather than a bare metadata listing: the
|
|
@@ -519,56 +551,52 @@ let AgentTeam = (() => {
|
|
|
519
551
|
});
|
|
520
552
|
return Object.freeze({ resolved: Object.freeze(this.requireLedger().resolveTaskRefs(request.workspaceId, taskRefs)) });
|
|
521
553
|
}
|
|
522
|
-
/**
|
|
554
|
+
/** Browser-safe Human roster, optionally filtered to one participation. */
|
|
523
555
|
membersForClient(request) {
|
|
524
|
-
|
|
556
|
+
if (request.workspaceId !== undefined)
|
|
557
|
+
this.requireWorkspace(request.workspaceId);
|
|
558
|
+
const ledger = this.requireLedger();
|
|
525
559
|
return this.members()
|
|
526
|
-
.filter(status => status.member.
|
|
527
|
-
.map(({ member: { privateMemoryPath: _privateMemoryPath, ...member }, ...status }) => Object.freeze({ ...status, member: Object.freeze(member) }));
|
|
560
|
+
.filter(status => request.workspaceId === undefined || ledger.participatesIn(status.member.memberId, request.workspaceId))
|
|
561
|
+
.map(({ member: { privateMemoryPath: _privateMemoryPath, ...member }, ...status }) => Object.freeze({ ...status, member: Object.freeze(member), workspaceIds: ledger.workspacesOf(member.memberId) }));
|
|
528
562
|
}
|
|
529
|
-
/**
|
|
530
|
-
async changes(request, signal) {
|
|
531
|
-
if (!Number.isInteger(request.afterVersion) || request.afterVersion < 0)
|
|
532
|
-
throw new Error('afterVersion must be a non-negative integer');
|
|
563
|
+
/** Emit a current baseline, then coalesced invalidations until canceled. */
|
|
564
|
+
async *changes(request, signal) {
|
|
533
565
|
const scope = this.validateChangeScope(request.scope);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}, 25_000);
|
|
557
|
-
const onAbort = () => {
|
|
558
|
-
if (settled)
|
|
566
|
+
let pending;
|
|
567
|
+
let resume;
|
|
568
|
+
const waiter = {
|
|
569
|
+
scope,
|
|
570
|
+
wake: version => {
|
|
571
|
+
pending = version;
|
|
572
|
+
resume?.();
|
|
573
|
+
},
|
|
574
|
+
};
|
|
575
|
+
const onAbort = () => { resume?.(); };
|
|
576
|
+
if (signal?.aborted || !this.accepting)
|
|
577
|
+
return;
|
|
578
|
+
this.changeWaiters.add(waiter);
|
|
579
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
580
|
+
try {
|
|
581
|
+
// Listen before yielding so a commit during the consumer's read is kept.
|
|
582
|
+
yield { version: this.changeVersionOf(scope) };
|
|
583
|
+
while (!signal?.aborted && this.accepting) {
|
|
584
|
+
if (pending === undefined)
|
|
585
|
+
await new Promise(resolve => { resume = resolve; });
|
|
586
|
+
resume = undefined;
|
|
587
|
+
if (signal?.aborted || !this.accepting)
|
|
559
588
|
return;
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
signal?.addEventListener('abort', onAbort, { once: true });
|
|
566
|
-
if (signal?.aborted === true) {
|
|
567
|
-
onAbort();
|
|
568
|
-
return;
|
|
589
|
+
if (pending !== undefined) {
|
|
590
|
+
const version = pending;
|
|
591
|
+
pending = undefined;
|
|
592
|
+
yield { version };
|
|
593
|
+
}
|
|
569
594
|
}
|
|
570
|
-
|
|
571
|
-
|
|
595
|
+
}
|
|
596
|
+
finally {
|
|
597
|
+
this.changeWaiters.delete(waiter);
|
|
598
|
+
signal?.removeEventListener('abort', onAbort);
|
|
599
|
+
}
|
|
572
600
|
}
|
|
573
601
|
/** Return durable Team status without issuing a model request or a storage write. */
|
|
574
602
|
status() {
|
|
@@ -672,7 +700,7 @@ let AgentTeam = (() => {
|
|
|
672
700
|
async recoverMember(request) {
|
|
673
701
|
this.requireAccepting();
|
|
674
702
|
const member = this.requireLedger().getMember(request.memberId);
|
|
675
|
-
if (member === undefined ||
|
|
703
|
+
if (member === undefined || !this.requireLedger().participatesIn(request.memberId, request.workspaceId))
|
|
676
704
|
throw new Error(`unknown Member '${request.memberId}' in workspace '${request.workspaceId}'`);
|
|
677
705
|
this.recovery.stopTracking(request.memberId);
|
|
678
706
|
// An orphaned composition cannot be steered: its tools are gone, so a
|
|
@@ -730,7 +758,7 @@ let AgentTeam = (() => {
|
|
|
730
758
|
this.requireAccepting();
|
|
731
759
|
this.requireWorkspace(request.workspaceId);
|
|
732
760
|
const stored = this.requireLedger().getMember(request.memberId);
|
|
733
|
-
if (stored === undefined ||
|
|
761
|
+
if (stored === undefined || !this.requireLedger().participatesIn(request.memberId, request.workspaceId))
|
|
734
762
|
throw new Error(`unknown Member '${request.memberId}' in workspace '${request.workspaceId}'`);
|
|
735
763
|
if (stored.state !== 'enabled')
|
|
736
764
|
throw new Error(`Agent Member '${stored.handle}' is ${stored.state}; only enabled Members can start from a new context`);
|
|
@@ -876,7 +904,7 @@ let AgentTeam = (() => {
|
|
|
876
904
|
reactivated.agent.steer(this.contextManagement.handoffMessageFor(plan));
|
|
877
905
|
for (const message of carriedInput)
|
|
878
906
|
reactivated.agent.followup(message);
|
|
879
|
-
const notifications = this.requireLedger().notificationFacts(
|
|
907
|
+
const notifications = this.requireLedger().notificationFacts(rolled.member.memberId);
|
|
880
908
|
if (notifications.length > 0)
|
|
881
909
|
this.notifyMember(reactivated.agent, carriedInput.length > 0);
|
|
882
910
|
});
|
|
@@ -914,7 +942,7 @@ let AgentTeam = (() => {
|
|
|
914
942
|
const handle = this.handles.get(member.memberId);
|
|
915
943
|
if (handle === undefined)
|
|
916
944
|
throw new Error(`member '${member.handle}' has no active session`);
|
|
917
|
-
const notifications = this.requireLedger().notificationFacts(member.memberId
|
|
945
|
+
const notifications = this.requireLedger().notificationFacts(member.memberId);
|
|
918
946
|
const body = notifications.length === 0 ? text : `${text}\n\n${this.notificationText(notifications, member.memberId)}`;
|
|
919
947
|
const hint = createUserMessage({
|
|
920
948
|
content: [{ type: 'text', text: body }],
|
|
@@ -1045,6 +1073,22 @@ let AgentTeam = (() => {
|
|
|
1045
1073
|
this.emitCommitted(result.value.receipt);
|
|
1046
1074
|
return result.value;
|
|
1047
1075
|
}
|
|
1076
|
+
/** Human-only Workspace participation grant; a pure relation — no Session moves. */
|
|
1077
|
+
async joinWorkspace(request) {
|
|
1078
|
+
const actor = this.humanCall(request.workspaceId);
|
|
1079
|
+
const result = await this.requireLedger().joinWorkspace({ ...request, actor });
|
|
1080
|
+
if (result.committed)
|
|
1081
|
+
this.emitCommitted(result.value.receipt);
|
|
1082
|
+
return result.value;
|
|
1083
|
+
}
|
|
1084
|
+
/** Human-only Workspace participation withdrawal and Workspace-scoped cleanup. */
|
|
1085
|
+
async leaveWorkspace(request) {
|
|
1086
|
+
const actor = this.humanCall(request.workspaceId);
|
|
1087
|
+
const result = await this.requireLedger().leaveWorkspace({ ...request, actor });
|
|
1088
|
+
if (result.committed)
|
|
1089
|
+
this.emitCommitted(result.value.receipt);
|
|
1090
|
+
return result.value;
|
|
1091
|
+
}
|
|
1048
1092
|
/** Human top-level Thread start; asTask attaches an optional Task overlay. */
|
|
1049
1093
|
async sendMessage(request) {
|
|
1050
1094
|
return this.sendMessageAs(this.humanCall(request.workspaceId), request);
|
|
@@ -1185,8 +1229,10 @@ let AgentTeam = (() => {
|
|
|
1185
1229
|
}
|
|
1186
1230
|
inboxForAgent(agent, request) {
|
|
1187
1231
|
const actor = this.memberActor(agent);
|
|
1232
|
+
if (request.workspaceId === undefined)
|
|
1233
|
+
return this.requireLedger().memberInbox(actor, request);
|
|
1188
1234
|
this.requireAgentWorkspace(actor, request.workspaceId);
|
|
1189
|
-
return this.requireLedger().inbox(actor, request);
|
|
1235
|
+
return this.requireLedger().inbox(actor, { ...request, workspaceId: request.workspaceId });
|
|
1190
1236
|
}
|
|
1191
1237
|
async readThreadForAgent(agent, request) {
|
|
1192
1238
|
const actor = this.memberCall(agent, request.workspaceId);
|
|
@@ -1270,7 +1316,7 @@ let AgentTeam = (() => {
|
|
|
1270
1316
|
}
|
|
1271
1317
|
try {
|
|
1272
1318
|
const message = createUserMessage({
|
|
1273
|
-
content: [{ type: 'text', text: this.dmRelayText(agent, recipient, request.body.trim(), result.value.receipt.occurredAt, result.value.receipt.operationId) }],
|
|
1319
|
+
content: [{ type: 'text', text: this.dmRelayText(agent, recipient, request.body.trim(), result.value.receipt.occurredAt, result.value.receipt.operationId, request.workspaceId) }],
|
|
1274
1320
|
source: { kind: 'plugin', plugin: AGENT_TEAM_PLUGIN_ID, form: 'relay' },
|
|
1275
1321
|
});
|
|
1276
1322
|
// An idle recipient gets one ordinary turn; a busy one is steered into
|
|
@@ -1286,26 +1332,38 @@ let AgentTeam = (() => {
|
|
|
1286
1332
|
return result.value;
|
|
1287
1333
|
}
|
|
1288
1334
|
/** Relay body: the DM itself plus one bounded line of adjacent context. */
|
|
1289
|
-
dmRelayText(senderAgent, recipient, body, occurredAt, excluding) {
|
|
1335
|
+
dmRelayText(senderAgent, recipient, body, occurredAt, excluding, workspaceId) {
|
|
1290
1336
|
const sender = this.memberForAgent(senderAgent);
|
|
1291
1337
|
const prior = this.requireLedger().dmHistoryBetween(senderAgent.id, recipient.memberId, excluding);
|
|
1292
1338
|
const header = `Direct message from @${sender?.handle ?? 'a Team Member'} at ${formatTeamTimestamp(occurredAt)}:`;
|
|
1293
1339
|
const context = prior === undefined ? '' : `\n\n[most recent prior DM between you: ${prior}]`;
|
|
1294
|
-
return `${header}\n\n${body}${context}`;
|
|
1340
|
+
return `${header}\nWorkspace: ${workspaceId}\n\n${body}${context}`;
|
|
1295
1341
|
}
|
|
1296
1342
|
threadHistoryForAgent(agent, request) {
|
|
1297
1343
|
const actor = this.memberActor(agent);
|
|
1298
1344
|
this.requireAgentWorkspace(actor, request.workspaceId);
|
|
1299
1345
|
return this.requireLedger().threadHistory(actor, request);
|
|
1300
1346
|
}
|
|
1301
|
-
/**
|
|
1347
|
+
/** Live participation addresses; paths remain owned by the Harness registry. */
|
|
1348
|
+
workspacesForAgent(agent) {
|
|
1349
|
+
const actor = this.memberActor(agent);
|
|
1350
|
+
const member = this.requireLedger().getMember(actor.memberId);
|
|
1351
|
+
return Object.freeze(this.requireLedger().workspacesOf(actor.memberId).map(workspaceId => Object.freeze({
|
|
1352
|
+
workspaceId, path: this.ctx.workspaceRegistry.get(workspaceId)?.path, default: workspaceId === member.workspaceId,
|
|
1353
|
+
})));
|
|
1354
|
+
}
|
|
1355
|
+
/** Agent-only bounded discovery projection; participation list carries registry titles when known. */
|
|
1302
1356
|
viewForAgent(agent, request) {
|
|
1303
1357
|
const member = this.memberForAgent(agent);
|
|
1304
1358
|
if (member === undefined)
|
|
1305
1359
|
throw new Error('Agent is not an active Team Member');
|
|
1306
|
-
if (member.
|
|
1360
|
+
if (!this.requireLedger().participatesIn(member.memberId, request.workspaceId))
|
|
1307
1361
|
throw new Error('Member cannot view another Workspace');
|
|
1308
|
-
|
|
1362
|
+
const view = this.requireLedger().view(request, member.memberId);
|
|
1363
|
+
return Object.freeze({ ...view, workspaces: Object.freeze(view.workspaces.map(participation => {
|
|
1364
|
+
const title = this.ctx.workspaceRegistry.get(participation.workspaceId)?.title;
|
|
1365
|
+
return title === undefined ? participation : Object.freeze({ ...participation, title });
|
|
1366
|
+
})) });
|
|
1309
1367
|
}
|
|
1310
1368
|
/** Validate the durable ledger against an independently replayed projection. */
|
|
1311
1369
|
validateLedger() {
|
|
@@ -2040,9 +2098,10 @@ let AgentTeam = (() => {
|
|
|
2040
2098
|
this.requireWorkspace(workspaceId);
|
|
2041
2099
|
return agentTeamHumanActor();
|
|
2042
2100
|
}
|
|
2043
|
-
/** Fence one Member call: accepting Host, live Member binding, matching Workspace. */
|
|
2101
|
+
/** Fence one Member call: accepting Host, live Member binding, matching Workspace participation. */
|
|
2044
2102
|
memberCall(agent, workspaceId) {
|
|
2045
2103
|
this.requireAccepting();
|
|
2104
|
+
this.requireWorkspace(workspaceId);
|
|
2046
2105
|
const actor = this.memberActor(agent);
|
|
2047
2106
|
this.requireAgentWorkspace(actor, workspaceId);
|
|
2048
2107
|
return actor;
|
|
@@ -2054,7 +2113,7 @@ let AgentTeam = (() => {
|
|
|
2054
2113
|
return Object.freeze({ kind: 'member', memberId: member.memberId, handle: member.handle });
|
|
2055
2114
|
}
|
|
2056
2115
|
requireAgentWorkspace(actor, workspaceId) {
|
|
2057
|
-
if (this.requireLedger().
|
|
2116
|
+
if (!this.requireLedger().participatesIn(actor.memberId, workspaceId))
|
|
2058
2117
|
throw new Error('Member cannot mutate another Workspace');
|
|
2059
2118
|
}
|
|
2060
2119
|
/**
|
|
@@ -2313,7 +2372,7 @@ let AgentTeam = (() => {
|
|
|
2313
2372
|
}
|
|
2314
2373
|
finally {
|
|
2315
2374
|
// Activation only changes this Workspace's presence projection.
|
|
2316
|
-
this.
|
|
2375
|
+
this.emitMemberPresenceChanged(member);
|
|
2317
2376
|
}
|
|
2318
2377
|
}
|
|
2319
2378
|
/**
|
|
@@ -2486,6 +2545,25 @@ let AgentTeam = (() => {
|
|
|
2486
2545
|
}
|
|
2487
2546
|
const ledger = this.requireLedger();
|
|
2488
2547
|
this.emitChanged(ledger.changeScopesOf(operation));
|
|
2548
|
+
if (operation.kind === 'team/member-workspace-joined' || operation.kind === 'team/member-workspace-left') {
|
|
2549
|
+
const agent = this.handles.get(operation.data.memberId)?.agent;
|
|
2550
|
+
if (agent !== undefined) {
|
|
2551
|
+
const path = this.ctx.workspaceRegistry.get(operation.data.workspaceId)?.path;
|
|
2552
|
+
const text = `Team participation changed: you have ${operation.kind === 'team/member-workspace-joined' ? 'joined' : 'left'} Workspace ${operation.data.workspaceId}${path === undefined ? ' (path unavailable)' : ` (${JSON.stringify(path)})`}.\nCurrent Workspace ids: ${ledger.workspacesOf(operation.data.memberId).join(', ')}. This replaces earlier participation information. Your Session and cwd have not moved.`;
|
|
2553
|
+
const notice = createUserMessage({ content: [{ type: 'text', text }],
|
|
2554
|
+
source: { kind: 'plugin', plugin: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: 'Team Workspace participation changed' } });
|
|
2555
|
+
try {
|
|
2556
|
+
if (agent.status === 'idle' || agent.inbox.nextTurn.some(message => message.source.kind === 'user'))
|
|
2557
|
+
agent.followup(notice);
|
|
2558
|
+
else
|
|
2559
|
+
agent.steer(notice);
|
|
2560
|
+
}
|
|
2561
|
+
catch (error) {
|
|
2562
|
+
// Notification delivery cannot roll back a committed participation.
|
|
2563
|
+
this.ctx.logger.warn(`agent-team: participation notice not delivered: ${error instanceof Error ? error.message : String(error)}`);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2489
2567
|
for (const memberId of ledger.affectedMembersOf(operation)) {
|
|
2490
2568
|
const handle = this.handles.get(memberId);
|
|
2491
2569
|
if (handle !== undefined)
|
|
@@ -2521,10 +2599,8 @@ let AgentTeam = (() => {
|
|
|
2521
2599
|
.map((job) => `${job.name ?? job.id}`);
|
|
2522
2600
|
}
|
|
2523
2601
|
emitAutoCompactionChanged(memberId) {
|
|
2524
|
-
const workspaceId
|
|
2525
|
-
|
|
2526
|
-
return;
|
|
2527
|
-
this.emitPresenceChanged(workspaceId);
|
|
2602
|
+
for (const workspaceId of this.ledger?.workspacesOf(memberId) ?? [])
|
|
2603
|
+
this.emitPresenceChanged(workspaceId);
|
|
2528
2604
|
}
|
|
2529
2605
|
/**
|
|
2530
2606
|
* Presence-only invalidation: Agent running/idle/activation/failure changes
|
|
@@ -2534,12 +2610,17 @@ let AgentTeam = (() => {
|
|
|
2534
2610
|
emitPresenceChanged(workspaceId) {
|
|
2535
2611
|
this.emitChanged([{ kind: 'presence', workspaceId }]);
|
|
2536
2612
|
}
|
|
2613
|
+
/** Presence invalidation in every Workspace the Member participates in — each panel listing it must refresh. */
|
|
2614
|
+
emitMemberPresenceChanged(member) {
|
|
2615
|
+
for (const workspaceId of this.requireLedger().workspacesOf(member.memberId))
|
|
2616
|
+
this.emitPresenceChanged(workspaceId);
|
|
2617
|
+
}
|
|
2537
2618
|
/** Wake from durable unread state with bounded facts for direct and state-changing work. */
|
|
2538
2619
|
notifyMember(agent, sequenced = false) {
|
|
2539
2620
|
const member = this.memberForAgent(agent);
|
|
2540
2621
|
if (member === undefined || member.state !== 'enabled')
|
|
2541
2622
|
return;
|
|
2542
|
-
const notifications = this.requireLedger().notificationFacts(member.memberId
|
|
2623
|
+
const notifications = this.requireLedger().notificationFacts(member.memberId);
|
|
2543
2624
|
if (notifications.length === 0) {
|
|
2544
2625
|
this.notifiedInbox.delete(member.memberId);
|
|
2545
2626
|
return;
|
|
@@ -2612,6 +2693,8 @@ let AgentTeam = (() => {
|
|
|
2612
2693
|
return true;
|
|
2613
2694
|
};
|
|
2614
2695
|
for (const { item, facts } of notifications.slice(0, 8)) {
|
|
2696
|
+
if (!append(`Workspace: ${item.workspaceId}\nChannel: ${item.channelRef}`))
|
|
2697
|
+
break;
|
|
2615
2698
|
for (const { fact, direct } of facts) {
|
|
2616
2699
|
if (detailedFactCount >= 20) {
|
|
2617
2700
|
omitted = true;
|
|
@@ -2641,7 +2724,7 @@ let AgentTeam = (() => {
|
|
|
2641
2724
|
}
|
|
2642
2725
|
if (omitted)
|
|
2643
2726
|
sections.push('More unread work remains in team_inbox; the automatic context is bounded.');
|
|
2644
|
-
sections.push('Use team_thread read with the relevant threadRef before acting or replying. Use team_inbox only when you need to triage the remaining Threads.');
|
|
2727
|
+
sections.push('Use team_thread read with the relevant workspace and threadRef before acting or replying. Use team_inbox only when you need to triage the remaining Threads.');
|
|
2645
2728
|
return sections.join('\n\n');
|
|
2646
2729
|
}
|
|
2647
2730
|
boundedNotificationBody(body) {
|
|
@@ -2731,7 +2814,6 @@ let AgentTeam = (() => {
|
|
|
2731
2814
|
const waiterScope = waiter.scope;
|
|
2732
2815
|
if (scopes !== undefined && (waiterScope === undefined ? !touchesProjection : !scopes.some(scope => sameChangeScope(scope, waiterScope))))
|
|
2733
2816
|
continue;
|
|
2734
|
-
this.changeWaiters.delete(waiter);
|
|
2735
2817
|
waiter.wake(this.changeVersionOf(waiterScope));
|
|
2736
2818
|
}
|
|
2737
2819
|
}
|