@wowyuarm/dsh-agent-team 0.1.1 → 0.1.2
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/package.json +31 -23
- package/packages/agent-team/lib/index.js +51 -62
- package/packages/agent-team/lib/ledger.js +63 -39
- package/packages/agent-team/lib/spec.js +10 -4
- package/packages/agent-team/lib/typert.host.js +60 -73
- package/packages/agent-team/lib/typert.remote-client.d.ts +3 -3
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +41 -56
- package/packages/agent-team/lib/types/index.d.ts +10 -13
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +11 -11
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types.d.ts +20 -12
- package/packages/agent-team/lib/types/types.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +2 -2
- package/packages/client-agent-team/README.md +3 -2
- package/packages/client-agent-team/README.zh.md +3 -2
- package/packages/client-agent-team/lib/client.js +758 -184
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -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 +20 -17
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -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 +38 -2
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +16 -2
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +22 -1
- 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 +3 -3
- package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +7 -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 +123 -11
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +4 -0
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +78 -8
- 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.js +1 -1
- package/packages/client-agent-team/lib/types/client/locales.d.ts +8 -2
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +8 -2
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +35 -0
- package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/sidebar-drag.js +70 -0
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts +27 -0
- package/packages/client-agent-team/lib/types/client/sidebar-order.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/sidebar-order.js +170 -0
- package/packages/client-agent-team/lib/types/client/slots.d.ts +2 -2
- 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 +20 -0
- package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/task-refs.js +58 -0
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +13 -0
- 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 +26 -2
- package/packages/tool-agent-team/lib/index.js +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wowyuarm/dsh-agent-team",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Help humans organize tasks and let agents collaborate - a Team plugin for DeepSeek Harness",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -111,20 +111,22 @@
|
|
|
111
111
|
"./package.json": "./package.json"
|
|
112
112
|
},
|
|
113
113
|
"peerDependencies": {
|
|
114
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
114
115
|
"@deepseek-ai/dsh-agent": ">=0.1.1-rc.2 <0.2.0",
|
|
115
116
|
"@deepseek-ai/dsh-agent-default-model": ">=0.1.1-rc.2 <0.2.0",
|
|
116
|
-
"@deepseek-ai/dsh-agent-tool-presentation": ">=0.1.1-rc.2 <0.2.0",
|
|
117
117
|
"@deepseek-ai/dsh-agent-presets": ">=0.1.1-rc.2 <0.2.0",
|
|
118
|
-
"@deepseek-ai/dsh-tool-
|
|
119
|
-
"@deepseek-ai/dsh-
|
|
120
|
-
"@deepseek-ai/dsh-tool-fs": ">=0.1.1-rc.2 <0.2.0",
|
|
121
|
-
"@deepseek-ai/dsh-tool-fs-search": ">=0.1.1-rc.2 <0.2.0",
|
|
122
|
-
"@deepseek-ai/dsh-tool-jobs": ">=0.1.1-rc.2 <0.2.0",
|
|
123
|
-
"@deepseek-ai/dsh-skill-filesystem": ">=0.1.1-rc.2 <0.2.0",
|
|
124
|
-
"@deepseek-ai/dsh-tool-skill": ">=0.1.1-rc.2 <0.2.0",
|
|
125
|
-
"@deepseek-ai/dsh-tool-todo": ">=0.1.1-rc.2 <0.2.0",
|
|
126
|
-
"@deepseek-ai/dsh-tool-web": ">=0.1.1-rc.2 <0.2.0",
|
|
118
|
+
"@deepseek-ai/dsh-agent-tool-presentation": ">=0.1.1-rc.2 <0.2.0",
|
|
119
|
+
"@deepseek-ai/dsh-api-remotes": ">=0.1.1-rc.2 <0.2.0",
|
|
127
120
|
"@deepseek-ai/dsh-brand": ">=0.1.1-rc.2 <0.2.0",
|
|
121
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.1-rc.2 <0.2.0",
|
|
122
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.1-rc.2 <0.2.0",
|
|
123
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.1-rc.2 <0.2.0",
|
|
124
|
+
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.1-rc.2 <0.2.0",
|
|
125
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.1-rc.2 <0.2.0",
|
|
126
|
+
"@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.1-rc.2 <0.2.0",
|
|
127
|
+
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.1-rc.2 <0.2.0",
|
|
128
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.1-rc.2 <0.2.0",
|
|
129
|
+
"@deepseek-ai/dsh-client-ui-workspace": ">=0.1.1-rc.2 <0.2.0",
|
|
128
130
|
"@deepseek-ai/dsh-home-paths": ">=0.1.1-rc.2 <0.2.0",
|
|
129
131
|
"@deepseek-ai/dsh-invariants": ">=0.1.1-rc.2 <0.2.0",
|
|
130
132
|
"@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.2.0",
|
|
@@ -132,21 +134,27 @@
|
|
|
132
134
|
"@deepseek-ai/dsh-scope": ">=0.1.1-rc.2 <0.2.0",
|
|
133
135
|
"@deepseek-ai/dsh-session": ">=0.1.1-rc.2 <0.2.0",
|
|
134
136
|
"@deepseek-ai/dsh-session-persistence": ">=0.1.1-rc.2 <0.2.0",
|
|
137
|
+
"@deepseek-ai/dsh-skill-filesystem": ">=0.1.1-rc.2 <0.2.0",
|
|
135
138
|
"@deepseek-ai/dsh-storage-domain": ">=0.1.1-rc.2 <0.2.0",
|
|
139
|
+
"@deepseek-ai/dsh-tool-bash": ">=0.1.1-rc.2 <0.2.0",
|
|
140
|
+
"@deepseek-ai/dsh-tool-fs": ">=0.1.1-rc.2 <0.2.0",
|
|
141
|
+
"@deepseek-ai/dsh-tool-fs-search": ">=0.1.1-rc.2 <0.2.0",
|
|
142
|
+
"@deepseek-ai/dsh-tool-jobs": ">=0.1.1-rc.2 <0.2.0",
|
|
143
|
+
"@deepseek-ai/dsh-tool-pwsh": ">=0.1.1-rc.2 <0.2.0",
|
|
144
|
+
"@deepseek-ai/dsh-tool-skill": ">=0.1.1-rc.2 <0.2.0",
|
|
145
|
+
"@deepseek-ai/dsh-tool-todo": ">=0.1.1-rc.2 <0.2.0",
|
|
146
|
+
"@deepseek-ai/dsh-tool-web": ">=0.1.1-rc.2 <0.2.0",
|
|
136
147
|
"@deepseek-ai/dsh-tools": ">=0.1.1-rc.2 <0.2.0",
|
|
137
148
|
"@deepseek-ai/dsh-typert-protocol": ">=0.1.1-rc.2 <0.2.0",
|
|
138
149
|
"@deepseek-ai/dsh-workspace": ">=0.1.1-rc.2 <0.2.0",
|
|
139
|
-
"@deepseek-ai/cordis": "^4.0.1",
|
|
140
|
-
"@deepseek-ai/dsh-api-remotes": ">=0.1.1-rc.2 <0.2.0",
|
|
141
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.1-rc.2 <0.2.0",
|
|
142
|
-
"@deepseek-ai/dsh-client-runtime": ">=0.1.1-rc.2 <0.2.0",
|
|
143
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.1-rc.2 <0.2.0",
|
|
144
|
-
"@deepseek-ai/dsh-client-ui-workspace": ">=0.1.1-rc.2 <0.2.0",
|
|
145
|
-
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.1-rc.2 <0.2.0",
|
|
146
|
-
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.1-rc.2 <0.2.0",
|
|
147
|
-
"@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.1-rc.2 <0.2.0",
|
|
148
|
-
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.1-rc.2 <0.2.0",
|
|
149
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.1-rc.2 <0.2.0",
|
|
150
150
|
"react": "^18.2.0"
|
|
151
|
-
}
|
|
151
|
+
},
|
|
152
|
+
"keywords": [
|
|
153
|
+
"deepseek-harness",
|
|
154
|
+
"dsh",
|
|
155
|
+
"dsh-plugin",
|
|
156
|
+
"agent-team",
|
|
157
|
+
"multi-agent",
|
|
158
|
+
"ai-agents"
|
|
159
|
+
]
|
|
152
160
|
}
|
|
@@ -44,6 +44,7 @@ import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
|
44
44
|
import { join } from 'node:path';
|
|
45
45
|
import { isDeepStrictEqual } from 'node:util';
|
|
46
46
|
import { Service } from '@deepseek-ai/cordis';
|
|
47
|
+
import { installModelSelection } from '@deepseek-ai/dsh-agent';
|
|
47
48
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
48
49
|
import { dshHomePath } from '@deepseek-ai/dsh-home-paths';
|
|
49
50
|
import { scopeOf } from '@deepseek-ai/dsh-scope';
|
|
@@ -83,13 +84,13 @@ export const AGENT_TEAM_TOOL_NAMES = Object.freeze([
|
|
|
83
84
|
let AgentTeam = (() => {
|
|
84
85
|
let _classSuper = TypertRemoteService;
|
|
85
86
|
let _instanceExtraInitializers = [];
|
|
87
|
+
let _resolveTaskRefs_decorators;
|
|
86
88
|
let _membersForClient_decorators;
|
|
87
89
|
let _changes_decorators;
|
|
88
90
|
let _createChannel_decorators;
|
|
89
91
|
let _updateChannel_decorators;
|
|
90
92
|
let _addMember_decorators;
|
|
91
93
|
let _recoverMember_decorators;
|
|
92
|
-
let _restartMember_decorators;
|
|
93
94
|
let _updateMember_decorators;
|
|
94
95
|
let _changeTask_decorators;
|
|
95
96
|
let _joinChannel_decorators;
|
|
@@ -107,13 +108,13 @@ let AgentTeam = (() => {
|
|
|
107
108
|
return class AgentTeam extends _classSuper {
|
|
108
109
|
static {
|
|
109
110
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
111
|
+
_resolveTaskRefs_decorators = [Remote('resolveTaskRefs')];
|
|
110
112
|
_membersForClient_decorators = [Remote('members')];
|
|
111
113
|
_changes_decorators = [Remote('changes')];
|
|
112
114
|
_createChannel_decorators = [Remote('createChannel')];
|
|
113
115
|
_updateChannel_decorators = [Remote('updateChannel')];
|
|
114
116
|
_addMember_decorators = [Remote('addMember')];
|
|
115
117
|
_recoverMember_decorators = [Remote('recoverMember')];
|
|
116
|
-
_restartMember_decorators = [Remote('restartMember')];
|
|
117
118
|
_updateMember_decorators = [Remote('updateMember')];
|
|
118
119
|
_changeTask_decorators = [Remote('changeTask')];
|
|
119
120
|
_joinChannel_decorators = [Remote('joinChannel')];
|
|
@@ -128,13 +129,13 @@ let AgentTeam = (() => {
|
|
|
128
129
|
_threadObservations_decorators = [Remote('threadObservations')];
|
|
129
130
|
_threadHistory_decorators = [Remote('threadHistory')];
|
|
130
131
|
_view_decorators = [Remote('view')];
|
|
132
|
+
__esDecorate(this, null, _resolveTaskRefs_decorators, { kind: "method", name: "resolveTaskRefs", static: false, private: false, access: { has: obj => "resolveTaskRefs" in obj, get: obj => obj.resolveTaskRefs }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
131
133
|
__esDecorate(this, null, _membersForClient_decorators, { kind: "method", name: "membersForClient", static: false, private: false, access: { has: obj => "membersForClient" in obj, get: obj => obj.membersForClient }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
132
134
|
__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);
|
|
133
135
|
__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);
|
|
134
136
|
__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);
|
|
135
137
|
__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);
|
|
136
138
|
__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);
|
|
137
|
-
__esDecorate(this, null, _restartMember_decorators, { kind: "method", name: "restartMember", static: false, private: false, access: { has: obj => "restartMember" in obj, get: obj => obj.restartMember }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
138
139
|
__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);
|
|
139
140
|
__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);
|
|
140
141
|
__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);
|
|
@@ -163,6 +164,8 @@ let AgentTeam = (() => {
|
|
|
163
164
|
domain = __runInitializers(this, _instanceExtraInitializers);
|
|
164
165
|
ledger;
|
|
165
166
|
handles = new Map();
|
|
167
|
+
/** Live selection refs let model edits take effect without disposing the Session. */
|
|
168
|
+
modelSelections = new Map();
|
|
166
169
|
diagnostics = new Map();
|
|
167
170
|
runtimeErrors = new Map();
|
|
168
171
|
/** Agent ids with a turn in flight; restarts must wait for the boundary. */
|
|
@@ -228,6 +231,7 @@ let AgentTeam = (() => {
|
|
|
228
231
|
await this.lifecycleTail;
|
|
229
232
|
await Promise.all([...this.handles.values()].map(handle => handle.dispose()));
|
|
230
233
|
this.handles.clear();
|
|
234
|
+
this.modelSelections.clear();
|
|
231
235
|
this.runningAgents.clear();
|
|
232
236
|
await domain.close();
|
|
233
237
|
}, 'agentTeam.dispose');
|
|
@@ -261,6 +265,18 @@ let AgentTeam = (() => {
|
|
|
261
265
|
return this.requireLedger().listMembers().map(member => this.memberStatus(member));
|
|
262
266
|
}
|
|
263
267
|
/** Return only this Workspace's current Member projection to the Client. */
|
|
268
|
+
/** Read-only navigation lookup for branded Task refs found in message bodies. */
|
|
269
|
+
resolveTaskRefs(request) {
|
|
270
|
+
this.requireWorkspace(request.workspaceId);
|
|
271
|
+
const seen = new Set();
|
|
272
|
+
const taskRefs = request.taskRefs.filter(taskRef => {
|
|
273
|
+
if (seen.has(taskRef))
|
|
274
|
+
return false;
|
|
275
|
+
seen.add(taskRef);
|
|
276
|
+
return true;
|
|
277
|
+
});
|
|
278
|
+
return Object.freeze({ resolved: Object.freeze(this.requireLedger().resolveTaskRefs(request.workspaceId, taskRefs)) });
|
|
279
|
+
}
|
|
264
280
|
membersForClient(request) {
|
|
265
281
|
this.requireWorkspace(request.workspaceId);
|
|
266
282
|
return this.members()
|
|
@@ -371,6 +387,7 @@ let AgentTeam = (() => {
|
|
|
371
387
|
await handle.dispose();
|
|
372
388
|
this.handles.delete(request.memberId);
|
|
373
389
|
}
|
|
390
|
+
this.modelSelections.delete(request.memberId);
|
|
374
391
|
this.diagnostics.delete(request.memberId);
|
|
375
392
|
this.clearMemberNotificationState(request.memberId);
|
|
376
393
|
return Object.freeze({ receipt: result.value.receipt, status: this.memberStatus(result.value.member) });
|
|
@@ -404,47 +421,6 @@ let AgentTeam = (() => {
|
|
|
404
421
|
this.steerResume(member, this.resumeText(kind ?? 'unspecified failure', { operatorRequested: true }));
|
|
405
422
|
return Object.freeze({ status: this.memberStatus(member) });
|
|
406
423
|
}
|
|
407
|
-
/**
|
|
408
|
-
* Restart one enabled Member's live session in place: dispose the handle and
|
|
409
|
-
* reactivate on the same session id, so the transcript, private memory, and
|
|
410
|
-
* every ledger fact survive while tools and prompt templates are re-minted
|
|
411
|
-
* from the running plugin. The audit operation changes no projection state.
|
|
412
|
-
*/
|
|
413
|
-
async restartMember(request) {
|
|
414
|
-
return this.enqueueLifecycle(async () => {
|
|
415
|
-
this.requireAccepting();
|
|
416
|
-
this.requireWorkspace(request.workspaceId);
|
|
417
|
-
const stored = this.requireLedger().getMember(request.memberId);
|
|
418
|
-
if (stored === undefined || stored.workspaceId !== request.workspaceId)
|
|
419
|
-
throw new Error(`unknown Member '${request.memberId}' in workspace '${request.workspaceId}'`);
|
|
420
|
-
if (stored.state !== 'enabled')
|
|
421
|
-
throw new Error(`Agent Member '${stored.handle}' is ${stored.state}; only enabled Members can be restarted`);
|
|
422
|
-
const active = this.handles.get(request.memberId);
|
|
423
|
-
if (active === undefined)
|
|
424
|
-
throw new Error(`Agent Member '${stored.handle}' has no active session to restart`);
|
|
425
|
-
if (this.runningAgents.has(active.agent.id))
|
|
426
|
-
throw new Error(`Agent Member '${stored.handle}' is still running; wait for the current turn to end before restarting`);
|
|
427
|
-
const result = await this.requireLedger().restartMember({ ...request, actor: agentTeamHumanActor() });
|
|
428
|
-
if (result.committed)
|
|
429
|
-
this.emitCommitted(result.value.receipt);
|
|
430
|
-
// Drop the old handle's transient state: pending recovery episodes and
|
|
431
|
-
// error markers belong to the disposed agent, not to the Member.
|
|
432
|
-
this.recovery.stopTracking(request.memberId);
|
|
433
|
-
this.runtimeErrors.delete(active.agent.id);
|
|
434
|
-
this.notifiedInbox.delete(request.memberId);
|
|
435
|
-
await active.dispose();
|
|
436
|
-
this.handles.delete(request.memberId);
|
|
437
|
-
this.diagnostics.delete(request.memberId);
|
|
438
|
-
await this.activateMember(stored);
|
|
439
|
-
const reactivated = this.handles.get(request.memberId);
|
|
440
|
-
if (reactivated === undefined) {
|
|
441
|
-
// Reactivation failed; the activation diagnostic carries the reason and
|
|
442
|
-
// the audit record stays honest about the attempt.
|
|
443
|
-
throw new Error(`Agent Member '${stored.handle}' failed to reactivate: ${this.diagnostics.get(request.memberId) ?? 'unknown error'}`);
|
|
444
|
-
}
|
|
445
|
-
return Object.freeze({ receipt: result.value.receipt, status: this.memberStatus(stored) });
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
424
|
/** Ledger handle for log lines; falls back to the raw id when unknown. */
|
|
449
425
|
memberLabel(memberId) {
|
|
450
426
|
return this.ledger?.getMember(memberId)?.handle ?? memberId;
|
|
@@ -494,7 +470,7 @@ let AgentTeam = (() => {
|
|
|
494
470
|
if (handle === undefined)
|
|
495
471
|
throw new Error(`member '${member.handle}' has no active session`);
|
|
496
472
|
const notifications = this.requireLedger().notificationFacts(member.memberId, { workspaceId: member.workspaceId });
|
|
497
|
-
const body = notifications.length === 0 ? text : `${text}\n\n${this.notificationText(notifications)}`;
|
|
473
|
+
const body = notifications.length === 0 ? text : `${text}\n\n${this.notificationText(notifications, member.memberId)}`;
|
|
498
474
|
const hint = createUserMessage({
|
|
499
475
|
content: [{ type: 'text', text: body }],
|
|
500
476
|
source: { kind: 'plugin', plugin: '@wowyuarm/dsh-agent-team', form: 'notice', summary: 'Recovery: continue your interrupted work.' },
|
|
@@ -511,10 +487,10 @@ let AgentTeam = (() => {
|
|
|
511
487
|
this.steerResume(member, this.resumeText(kind, { attempt }));
|
|
512
488
|
}
|
|
513
489
|
/**
|
|
514
|
-
* Human edit of one Member's mutable facts. A model
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
*
|
|
490
|
+
* Human edit of one Member's mutable facts. A live model selection is
|
|
491
|
+
* updated in place: disposing an Agent emits session/disposed, which makes
|
|
492
|
+
* the Web Client permanently mark the same Session id unavailable even when
|
|
493
|
+
* Team immediately recreates it.
|
|
518
494
|
*/
|
|
519
495
|
async updateMember(request) {
|
|
520
496
|
return this.enqueueLifecycle(async () => {
|
|
@@ -526,9 +502,10 @@ let AgentTeam = (() => {
|
|
|
526
502
|
const stored = result.value.member;
|
|
527
503
|
const active = this.handles.get(request.memberId);
|
|
528
504
|
if (active !== undefined && !isDeepStrictEqual(previous?.model ?? undefined, stored.model ?? undefined)) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
505
|
+
const selection = this.modelSelections.get(request.memberId);
|
|
506
|
+
if (selection === undefined)
|
|
507
|
+
throw new Error(`Agent Member '${stored.handle}' has no live model selection`);
|
|
508
|
+
selection.current = stored.model ?? this.ctx.agentDefaultModel.currentSelection();
|
|
532
509
|
}
|
|
533
510
|
return Object.freeze({ receipt: result.value.receipt, status: this.memberStatus(stored) });
|
|
534
511
|
});
|
|
@@ -544,6 +521,7 @@ let AgentTeam = (() => {
|
|
|
544
521
|
await handle.dispose();
|
|
545
522
|
this.handles.delete(request.memberId);
|
|
546
523
|
}
|
|
524
|
+
this.modelSelections.delete(request.memberId);
|
|
547
525
|
this.diagnostics.delete(request.memberId);
|
|
548
526
|
this.clearMemberNotificationState(request.memberId);
|
|
549
527
|
await this.cleanupRemovedMember(result.value.member);
|
|
@@ -844,9 +822,16 @@ let AgentTeam = (() => {
|
|
|
844
822
|
await this.initializePrivateMemory(member.privateMemoryPath);
|
|
845
823
|
const persisted = knownSessions !== undefined ? knownSessions.has(member.sessionId)
|
|
846
824
|
: (await this.ctx.sessionPersistence.list()).some(header => header.id === member.sessionId);
|
|
825
|
+
// AgentOptions declares only provider/model. Install the full selection
|
|
826
|
+
// through the public Agent model-selection seam so reasoning effort is
|
|
827
|
+
// applied to the next request and not lost during activation.
|
|
828
|
+
const selection = member.model ?? this.ctx.agentDefaultModel.currentSelection();
|
|
829
|
+
const agentOptions = { provider: selection.provider, model: selection.model };
|
|
830
|
+
const selected = { current: selection, assembled: undefined };
|
|
847
831
|
const setup = async (agentCtx) => {
|
|
848
832
|
await this.ctx.agentPresets.mount(agentCtx, member.presetId);
|
|
849
833
|
this.validateMemberPreset(agentCtx);
|
|
834
|
+
installModelSelection(agentCtx, selected);
|
|
850
835
|
return {
|
|
851
836
|
commit: () => {
|
|
852
837
|
const agent = agentCtx.agent;
|
|
@@ -857,10 +842,6 @@ let AgentTeam = (() => {
|
|
|
857
842
|
},
|
|
858
843
|
};
|
|
859
844
|
};
|
|
860
|
-
// A Member-pinned selection wins; otherwise the Host default applies at
|
|
861
|
-
// every activation, so an override survives restarts and a cleared one
|
|
862
|
-
// re-reads the live default.
|
|
863
|
-
const agentOptions = member.model ?? this.ctx.agentDefaultModel.currentSelection();
|
|
864
845
|
created = persisted
|
|
865
846
|
? await this.ctx.agents.resume({ resumeSessionId: member.sessionId, agentOptions, setup })
|
|
866
847
|
: await this.ctx.agents.create({
|
|
@@ -871,12 +852,14 @@ let AgentTeam = (() => {
|
|
|
871
852
|
});
|
|
872
853
|
await workspace.attachSession(member.sessionId);
|
|
873
854
|
this.handles.set(member.memberId, created);
|
|
855
|
+
this.modelSelections.set(member.memberId, selected);
|
|
874
856
|
this.diagnostics.delete(member.memberId);
|
|
875
857
|
this.nameMemberSession(member, created.agent);
|
|
876
858
|
this.notifyMember(created.agent);
|
|
877
859
|
}
|
|
878
860
|
catch (error) {
|
|
879
861
|
await created?.dispose();
|
|
862
|
+
this.modelSelections.delete(member.memberId);
|
|
880
863
|
this.diagnostics.set(member.memberId, error instanceof Error ? error.message : String(error));
|
|
881
864
|
}
|
|
882
865
|
finally {
|
|
@@ -998,7 +981,7 @@ let AgentTeam = (() => {
|
|
|
998
981
|
if (existingHint !== undefined)
|
|
999
982
|
agent.inbox.remove(existingHint.id);
|
|
1000
983
|
const hint = createUserMessage({
|
|
1001
|
-
content: [{ type: 'text', text: this.notificationText(notifications) }],
|
|
984
|
+
content: [{ type: 'text', text: this.notificationText(notifications, member.memberId) }],
|
|
1002
985
|
source: { kind: 'plugin', plugin: '@wowyuarm/dsh-agent-team', form: 'notice', summary: 'Team Inbox has unread work.' },
|
|
1003
986
|
});
|
|
1004
987
|
this.notifiedInbox.set(member.memberId, signature);
|
|
@@ -1010,7 +993,7 @@ let AgentTeam = (() => {
|
|
|
1010
993
|
throw error;
|
|
1011
994
|
}
|
|
1012
995
|
}
|
|
1013
|
-
notificationText(notifications) {
|
|
996
|
+
notificationText(notifications, readerId) {
|
|
1014
997
|
const maxCharacters = 32 * 1024;
|
|
1015
998
|
const sections = ['Team Inbox has unread work.'];
|
|
1016
999
|
let characterCount = sections[0].length;
|
|
@@ -1036,19 +1019,19 @@ let AgentTeam = (() => {
|
|
|
1036
1019
|
? 'human' : this.requireLedger().getMember(fact.message.sender)?.handle ?? fact.message.sender;
|
|
1037
1020
|
const detail = ['Direct Team mention', `From: ${sender}`, `Channel: ${item.channelRef}`,
|
|
1038
1021
|
`Task: ${item.task.taskRef}`, `Thread: ${item.thread.threadRef}`, `Message ref: ${fact.message.messageRef}`,
|
|
1039
|
-
`
|
|
1022
|
+
`Message: ${this.boundedNotificationBody(fact.message.body)}`].join('\n');
|
|
1040
1023
|
if (append(detail))
|
|
1041
1024
|
detailedFactCount += 1;
|
|
1042
1025
|
}
|
|
1043
1026
|
else if (fact.kind === 'activity') {
|
|
1044
|
-
const detail = `${this.activityNotification(fact.activity)}\nThread: ${item.thread.threadRef}
|
|
1027
|
+
const detail = `${this.activityNotification(fact.activity, readerId)}\nThread: ${item.thread.threadRef}`;
|
|
1045
1028
|
if (append(detail))
|
|
1046
1029
|
detailedFactCount += 1;
|
|
1047
1030
|
}
|
|
1048
1031
|
}
|
|
1049
1032
|
const ordinaryCount = facts.filter(entry => entry.fact.kind === 'message' && !entry.direct).length;
|
|
1050
1033
|
if (ordinaryCount > 0)
|
|
1051
|
-
append(`Task ${item.task.taskRef}: ${ordinaryCount} unread update${ordinaryCount === 1 ? '' : 's'}
|
|
1034
|
+
append(`Task ${item.task.taskRef}: ${ordinaryCount} unread update${ordinaryCount === 1 ? '' : 's'}.`);
|
|
1052
1035
|
}
|
|
1053
1036
|
if (omitted)
|
|
1054
1037
|
sections.push('More unread work remains in team_inbox; the automatic context is bounded.');
|
|
@@ -1059,9 +1042,15 @@ let AgentTeam = (() => {
|
|
|
1059
1042
|
const limit = 8 * 1024;
|
|
1060
1043
|
return body.length <= limit ? body : `${body.slice(0, limit)}\n[Message body truncated; use team_thread read for the full Message.]`;
|
|
1061
1044
|
}
|
|
1062
|
-
activityNotification(activity) {
|
|
1045
|
+
activityNotification(activity, readerId) {
|
|
1063
1046
|
const actor = activity.actor === AGENT_TEAM_HUMAN_MEMBER_ID
|
|
1064
1047
|
? 'human' : this.requireLedger().getMember(activity.actor)?.handle ?? activity.actor;
|
|
1048
|
+
// Early acceptance completes the reader's own open Claim inside the accept
|
|
1049
|
+
// operation: say so plainly, or the owner keeps working on a done Task.
|
|
1050
|
+
if (activity.kind === 'accept' && activity.actor === AGENT_TEAM_HUMAN_MEMBER_ID && readerId !== undefined
|
|
1051
|
+
&& activity.completedClaimRefs?.some(claimRef => this.requireLedger().getClaim(claimRef)?.owner === readerId)) {
|
|
1052
|
+
return `Team Task update\n${actor} accepted Task ${activity.taskRef} and your open Claim was completed with it. No further work is needed.`;
|
|
1053
|
+
}
|
|
1065
1054
|
if (activity.kind === 'claim' || activity.kind === 'done' || activity.kind === 'release') {
|
|
1066
1055
|
return `Team Task update\n${actor} ${activity.kind} Claim ${activity.claimRef} on Task ${activity.taskRef}.`;
|
|
1067
1056
|
}
|
|
@@ -191,31 +191,6 @@ export class AgentTeamLedger {
|
|
|
191
191
|
resumeMember(request) {
|
|
192
192
|
return this.setMemberState(request, 'enabled');
|
|
193
193
|
}
|
|
194
|
-
/**
|
|
195
|
-
* Audit record of one in-place Member session restart. The operation changes
|
|
196
|
-
* no projection state — identity, transcript, and memory are untouched — so
|
|
197
|
-
* replay treats it as a marker while the Host re-mints the live handle.
|
|
198
|
-
*/
|
|
199
|
-
restartMember(request) {
|
|
200
|
-
return this.enqueue(async () => {
|
|
201
|
-
const existing = this.state.byRequest.get(request.requestId);
|
|
202
|
-
if (existing !== undefined) {
|
|
203
|
-
this.assertSameMemberRestart(existing, request);
|
|
204
|
-
return this.resolved(this.memberResult(existing));
|
|
205
|
-
}
|
|
206
|
-
this.assertHumanActor(request.actor);
|
|
207
|
-
const member = this.requireMember(request.memberId);
|
|
208
|
-
if (member.state !== 'enabled')
|
|
209
|
-
throw new Error(`Agent Member '${member.handle}' is ${member.state}; only enabled Members can be restarted`);
|
|
210
|
-
const operation = Object.freeze({
|
|
211
|
-
...this.operationBase(request, this.nextSequence()), kind: 'team/member-session-restarted',
|
|
212
|
-
data: Object.freeze({ member }),
|
|
213
|
-
});
|
|
214
|
-
await this.table.put(operation.operationId, operation);
|
|
215
|
-
this.apply(operation);
|
|
216
|
-
return this.committed(this.memberResult(operation));
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
194
|
getMember(memberId) {
|
|
220
195
|
return this.state.members.get(memberId);
|
|
221
196
|
}
|
|
@@ -477,13 +452,24 @@ export class AgentTeamLedger {
|
|
|
477
452
|
throw new Error(`Task '${task.taskRef}' is already ${task.resolution}`);
|
|
478
453
|
if (request.action === 'close' && task.resolution === 'closed')
|
|
479
454
|
throw new Error(`Task '${task.taskRef}' is already closed`);
|
|
480
|
-
|
|
481
|
-
|
|
455
|
+
// Acceptance normally waits for every Claim to finish (in_review);
|
|
456
|
+
// a Human may also accept early while work is in progress, which then
|
|
457
|
+
// completes the still-active Claims inside the same atomic operation.
|
|
458
|
+
if (request.action === 'accept' && task.status !== 'in_review' && task.status !== 'in_progress') {
|
|
459
|
+
throw new Error(`Task '${task.taskRef}' must be in_review or in_progress before acceptance`);
|
|
460
|
+
}
|
|
461
|
+
const priorActiveClaims = [...this.state.claims.values()].filter(claim => claim.taskRef === task.taskRef && claim.state === 'active');
|
|
462
|
+
if (request.action === 'accept' && task.status === 'in_progress' && priorActiveClaims.length === 0) {
|
|
463
|
+
throw new Error(`Task '${task.taskRef}' has no active Claims to complete for early acceptance`);
|
|
464
|
+
}
|
|
482
465
|
if (request.action === 'reopen' && task.resolution === 'open')
|
|
483
466
|
throw new Error(`Task '${task.taskRef}' is already open`);
|
|
484
467
|
const sequence = this.nextSequence();
|
|
485
|
-
const claims = [...this.state.claims.values()].filter(claim => claim.taskRef === task.taskRef).map(claim => request.action === 'close' && claim.state === 'active' ? Object.freeze({ ...claim, state: 'released' })
|
|
468
|
+
const claims = [...this.state.claims.values()].filter(claim => claim.taskRef === task.taskRef).map(claim => request.action === 'close' && claim.state === 'active' ? Object.freeze({ ...claim, state: 'released' })
|
|
469
|
+
: request.action === 'accept' && claim.state === 'active' ? Object.freeze({ ...claim, state: 'done' })
|
|
470
|
+
: claim);
|
|
486
471
|
const releasedClaims = claims.filter(claim => claim.state === 'released' && this.state.claims.get(claim.claimRef)?.state === 'active');
|
|
472
|
+
const completedClaims = claims.filter(claim => claim.state === 'done' && this.state.claims.get(claim.claimRef)?.state === 'active');
|
|
487
473
|
const resolution = request.action === 'reopen' ? 'open' : request.action === 'accept' ? 'accepted' : 'closed';
|
|
488
474
|
const status = resolution === 'accepted' ? 'done' : resolution === 'closed' ? 'closed'
|
|
489
475
|
: this.deriveTaskStatus(task.taskRef, claims);
|
|
@@ -491,12 +477,13 @@ export class AgentTeamLedger {
|
|
|
491
477
|
const nextThread = Object.freeze({ ...thread, revision: sequence });
|
|
492
478
|
const activity = Object.freeze({ activityRef: this.ref('activity'), kind: request.action,
|
|
493
479
|
taskRef: task.taskRef, threadRef: task.threadRef, actor: request.actor.memberId, sequence,
|
|
494
|
-
...(releasedClaims.length === 0 ? {} : { releasedClaimRefs: Object.freeze(releasedClaims.map(claim => claim.claimRef)) })
|
|
480
|
+
...(releasedClaims.length === 0 ? {} : { releasedClaimRefs: Object.freeze(releasedClaims.map(claim => claim.claimRef)) }),
|
|
481
|
+
...(completedClaims.length === 0 ? {} : { completedClaimRefs: Object.freeze(completedClaims.map(claim => claim.claimRef)) }) });
|
|
495
482
|
const inbox = request.action === 'close'
|
|
496
483
|
? this.closeThreadInbox(activity, thread.threadRef)
|
|
497
484
|
: request.action === 'reopen'
|
|
498
485
|
? this.reopenThreadInbox(activity, thread.threadRef)
|
|
499
|
-
: this.
|
|
486
|
+
: this.acceptThreadInbox(activity, thread.threadRef, completedClaims.map(claim => claim.owner));
|
|
500
487
|
const operation = Object.freeze({
|
|
501
488
|
...this.operationBase(request, sequence), kind: 'team/task-changed',
|
|
502
489
|
data: Object.freeze({ workspaceId: request.workspaceId, baseRevision: request.baseRevision,
|
|
@@ -745,6 +732,21 @@ export class AgentTeamLedger {
|
|
|
745
732
|
getTask(taskRef) {
|
|
746
733
|
return this.state.tasks.get(taskRef);
|
|
747
734
|
}
|
|
735
|
+
getClaim(claimRef) {
|
|
736
|
+
return this.state.claims.get(claimRef);
|
|
737
|
+
}
|
|
738
|
+
/** Navigation facts for message-body Task refs; unknown refs are omitted. */
|
|
739
|
+
resolveTaskRefs(workspaceId, taskRefs) {
|
|
740
|
+
const numbers = this.taskNumbers(workspaceId);
|
|
741
|
+
const resolved = [];
|
|
742
|
+
for (const taskRef of taskRefs) {
|
|
743
|
+
const task = this.state.tasks.get(taskRef);
|
|
744
|
+
if (task === undefined || this.state.channels.get(task.channelRef)?.workspaceId !== workspaceId)
|
|
745
|
+
continue;
|
|
746
|
+
resolved.push(Object.freeze({ taskRef: task.taskRef, channelRef: task.channelRef, threadRef: task.threadRef, taskNumber: numbers.get(task.taskRef) ?? 0 }));
|
|
747
|
+
}
|
|
748
|
+
return resolved;
|
|
749
|
+
}
|
|
748
750
|
view(request, memberId) {
|
|
749
751
|
const limit = request.limit ?? 20;
|
|
750
752
|
const direction = request.direction ?? 'after';
|
|
@@ -1001,7 +1003,7 @@ export class AgentTeamLedger {
|
|
|
1001
1003
|
if (operation.kind === 'team/member-added') {
|
|
1002
1004
|
assertHuman();
|
|
1003
1005
|
const { member, channelRefs } = operation.data;
|
|
1004
|
-
if (projection.members.has(member.memberId) ||
|
|
1006
|
+
if (projection.members.has(member.memberId) || new Set(channelRefs).size !== channelRefs.length)
|
|
1005
1007
|
throw new Error('invalid Member creation');
|
|
1006
1008
|
this.addRef(refs, member.memberId);
|
|
1007
1009
|
for (const channelRef of channelRefs) {
|
|
@@ -1202,12 +1204,18 @@ export class AgentTeamLedger {
|
|
|
1202
1204
|
const expectedResolution = activity.kind === 'accept' ? 'accepted' : activity.kind === 'close' ? 'closed' : 'open';
|
|
1203
1205
|
const expectedStatus = expectedResolution === 'accepted' ? 'done' : expectedResolution === 'closed' ? 'closed'
|
|
1204
1206
|
: this.deriveTaskStatus(task.taskRef, operation.data.claims);
|
|
1207
|
+
const expectedCompletedClaimRefs = operation.data.claims
|
|
1208
|
+
.filter(claim => projection.claims.get(claim.claimRef)?.state === 'active' && claim.state === 'done')
|
|
1209
|
+
.map(claim => claim.claimRef);
|
|
1205
1210
|
if (task.resolution !== expectedResolution || task.status !== expectedStatus
|
|
1206
1211
|
|| (activity.kind !== 'close' && activity.releasedClaimRefs !== undefined)
|
|
1212
|
+
|| (activity.kind !== 'accept' && activity.completedClaimRefs !== undefined)
|
|
1207
1213
|
|| (activity.kind === 'close' && !this.sameList(activity.releasedClaimRefs ?? [], operation.data.claims
|
|
1208
1214
|
.filter(claim => projection.claims.get(claim.claimRef)?.state === 'active' && claim.state === 'released')
|
|
1209
|
-
.map(claim => claim.claimRef)))
|
|
1215
|
+
.map(claim => claim.claimRef)))
|
|
1216
|
+
|| !this.sameList(activity.completedClaimRefs ?? [], expectedCompletedClaimRefs)) {
|
|
1210
1217
|
throw new Error('invalid Task state transition');
|
|
1218
|
+
}
|
|
1211
1219
|
const priorClaims = [...projection.claims.values()].filter(claim => claim.taskRef === task.taskRef).sort((left, right) => left.claimRef.localeCompare(right.claimRef));
|
|
1212
1220
|
const operationClaims = [...operation.data.claims].sort((left, right) => left.claimRef.localeCompare(right.claimRef));
|
|
1213
1221
|
if (priorClaims.length !== operationClaims.length || priorClaims.some((claim, index) => claim.claimRef !== operationClaims[index]?.claimRef))
|
|
@@ -1218,7 +1226,9 @@ export class AgentTeamLedger {
|
|
|
1218
1226
|
throw new Error('invalid Task Claim identity');
|
|
1219
1227
|
const legal = activity.kind === 'close'
|
|
1220
1228
|
? (previousClaim.state === 'active' ? claim.state === 'released' : claim.state === previousClaim.state)
|
|
1221
|
-
:
|
|
1229
|
+
: activity.kind === 'accept'
|
|
1230
|
+
? (previousClaim.state === 'active' ? claim.state === 'done' : claim.state === previousClaim.state)
|
|
1231
|
+
: claim.state === previousClaim.state;
|
|
1222
1232
|
if (!legal)
|
|
1223
1233
|
throw new Error('invalid Task Claim transition');
|
|
1224
1234
|
}
|
|
@@ -1227,7 +1237,7 @@ export class AgentTeamLedger {
|
|
|
1227
1237
|
? this.closeThreadInboxFrom(projection, activity, thread.threadRef)
|
|
1228
1238
|
: activity.kind === 'reopen'
|
|
1229
1239
|
? this.reopenThreadInboxFrom(projection, activity, thread.threadRef)
|
|
1230
|
-
: this.
|
|
1240
|
+
: this.acceptThreadInboxFrom(projection, activity, thread.threadRef, expectedCompletedClaimRefs);
|
|
1231
1241
|
if (!isDeepStrictEqual(operation.data.inbox, expectedInbox))
|
|
1232
1242
|
throw new Error('invalid Task inbox projection');
|
|
1233
1243
|
this.validateInboxDelta(operation.data.inbox, projection, refs, [], [], [activity]);
|
|
@@ -1648,6 +1658,25 @@ export class AgentTeamLedger {
|
|
|
1648
1658
|
activityRef: activity.activityRef, sequence: activity.sequence }));
|
|
1649
1659
|
return this.inboxDelta([], removed, [], [...projection.directMarkers.values()].filter(marker => marker.threadRef === threadRef), activityMarkers, [...projection.activityMarkers.values()].filter(marker => marker.threadRef === threadRef));
|
|
1650
1660
|
}
|
|
1661
|
+
/**
|
|
1662
|
+
* Early acceptance completes open Claims inside the accept operation; their
|
|
1663
|
+
* owners learn about it through activity markers regardless of whether they
|
|
1664
|
+
* still follow the Thread. Plain accepts (no completed Claims) stay silent.
|
|
1665
|
+
*/
|
|
1666
|
+
acceptThreadInbox(activity, threadRef, completedOwners) {
|
|
1667
|
+
if (completedOwners.length === 0)
|
|
1668
|
+
return this.inboxDelta();
|
|
1669
|
+
const recipients = [...new Set(completedOwners)].filter(memberId => memberId !== activity.actor);
|
|
1670
|
+
const markers = recipients.map(memberId => Object.freeze({ memberId, threadRef,
|
|
1671
|
+
activityRef: activity.activityRef, sequence: activity.sequence }));
|
|
1672
|
+
return this.inboxDelta([], [], [], [], markers);
|
|
1673
|
+
}
|
|
1674
|
+
acceptThreadInboxFrom(projection, activity, threadRef, completedClaimRefs) {
|
|
1675
|
+
if (completedClaimRefs.length === 0)
|
|
1676
|
+
return this.inboxDelta();
|
|
1677
|
+
const owners = completedClaimRefs.map(claimRef => projection.claims.get(claimRef)?.owner).filter(owner => owner !== undefined);
|
|
1678
|
+
return this.acceptThreadInbox(activity, threadRef, owners);
|
|
1679
|
+
}
|
|
1651
1680
|
reopenThreadInbox(activity, threadRef) {
|
|
1652
1681
|
return this.reopenThreadInboxFrom(this.state, activity, threadRef);
|
|
1653
1682
|
}
|
|
@@ -1987,11 +2016,6 @@ export class AgentTeamLedger {
|
|
|
1987
2016
|
|| !this.sameList(operation.data.channelRefs, this.normalizeUnique(request.channelRefs, 'initial Member Channels')))
|
|
1988
2017
|
this.throwRequestCollision(request.requestId);
|
|
1989
2018
|
}
|
|
1990
|
-
assertSameMemberRestart(operation, request) {
|
|
1991
|
-
if (operation.kind !== 'team/member-session-restarted' || !this.sameActor(operation.actor, request.actor)
|
|
1992
|
-
|| operation.data.member.memberId !== request.memberId)
|
|
1993
|
-
this.throwRequestCollision(request.requestId);
|
|
1994
|
-
}
|
|
1995
2019
|
assertSameMemberState(operation, request, state) {
|
|
1996
2020
|
const kind = state === 'suspended' ? 'team/member-suspended' : 'team/member-resumed';
|
|
1997
2021
|
if (operation.kind !== kind || !this.sameActor(operation.actor, request.actor) || operation.data.member.memberId !== request.memberId)
|
|
@@ -26,13 +26,18 @@ const operationBase = {
|
|
|
26
26
|
const modelSelectionSchema = z.object({
|
|
27
27
|
provider: z.string().min(1),
|
|
28
28
|
model: z.string().min(1),
|
|
29
|
-
|
|
29
|
+
reasoningEffort: z.string().min(1).transform(value => value).optional(),
|
|
30
|
+
}).strict().transform(({ provider, model, reasoningEffort }) => ({
|
|
31
|
+
provider,
|
|
32
|
+
model,
|
|
33
|
+
...(reasoningEffort === undefined ? {} : { reasoningEffort }),
|
|
34
|
+
}));
|
|
30
35
|
const memberSchema = z.object({
|
|
31
36
|
memberId: memberIdSchema,
|
|
32
37
|
sessionId: sessionIdSchema,
|
|
33
38
|
workspaceId: workspaceIdSchema,
|
|
34
39
|
handle: z.string().min(1),
|
|
35
|
-
description: z.string()
|
|
40
|
+
description: z.string(),
|
|
36
41
|
presetId: z.string().min(1),
|
|
37
42
|
// Ledgers written before per-Member model selection existed omit the field.
|
|
38
43
|
model: modelSelectionSchema.optional(),
|
|
@@ -43,7 +48,7 @@ const channelSchema = z.object({
|
|
|
43
48
|
channelRef: channelRefSchema,
|
|
44
49
|
workspaceId: workspaceIdSchema,
|
|
45
50
|
name: z.string().min(1),
|
|
46
|
-
description: z.string()
|
|
51
|
+
description: z.string(),
|
|
47
52
|
createdAtSequence: z.number().int().positive(),
|
|
48
53
|
}).strict();
|
|
49
54
|
// Ledgers written before message occurredAt or attachments existed store bare
|
|
@@ -155,6 +160,7 @@ const taskActivitySchema = z.object({
|
|
|
155
160
|
...activityBase,
|
|
156
161
|
kind: z.union([z.literal('accept'), z.literal('close'), z.literal('reopen')]),
|
|
157
162
|
releasedClaimRefs: z.array(claimRefSchema).min(1).optional(),
|
|
163
|
+
completedClaimRefs: z.array(claimRefSchema).min(1).optional(),
|
|
158
164
|
}).strict();
|
|
159
165
|
const claimsReleasedActivitySchema = z.object({
|
|
160
166
|
...activityBase,
|
|
@@ -208,7 +214,7 @@ const storedAgentTeamOperationSchema = z.discriminatedUnion('kind', [
|
|
|
208
214
|
...operationBase,
|
|
209
215
|
previousOperationId: operationIdSchema.nullable(),
|
|
210
216
|
kind: z.literal('team/member-added'),
|
|
211
|
-
data: z.object({ member: memberSchema, channelRefs: z.array(channelRefSchema)
|
|
217
|
+
data: z.object({ member: memberSchema, channelRefs: z.array(channelRefSchema) }).strict(),
|
|
212
218
|
}).strict(),
|
|
213
219
|
z.object({
|
|
214
220
|
...operationBase,
|