@wowyuarm/dsh-agent-team 0.1.14 → 0.2.0
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 +8 -4
- package/README.zh.md +8 -4
- package/cordis.patch.yml +187 -2
- package/package.json +52 -51
- package/packages/agent-team/README.md +1 -1
- package/packages/agent-team/README.zh.md +1 -1
- package/packages/agent-team/lib/context-continuity-host.js +2 -3
- package/packages/agent-team/lib/context-projection.js +3 -3
- package/packages/agent-team/lib/context-source.js +39 -13
- package/packages/agent-team/lib/environment-check.js +102 -0
- package/packages/agent-team/lib/human-profile.js +110 -13
- package/packages/agent-team/lib/index.js +192 -100
- package/packages/agent-team/lib/installed-manifest.js +32 -0
- package/packages/agent-team/lib/ledger.js +35 -0
- package/packages/agent-team/lib/member-context.js +3 -3
- package/packages/agent-team/lib/member-time-context.js +3 -2
- package/packages/agent-team/lib/pressure-policy.js +18 -11
- package/packages/agent-team/lib/stored-session-reader.js +1 -2
- package/packages/agent-team/lib/typert.host.js +479 -260
- package/packages/agent-team/lib/typert.remote-client.d.ts +8 -3
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +375 -228
- package/packages/agent-team/lib/types/context-continuity-host.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-source.d.ts +49 -13
- package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
- package/packages/agent-team/lib/types/environment-check.d.ts +66 -0
- package/packages/agent-team/lib/types/environment-check.d.ts.map +1 -0
- package/packages/agent-team/lib/types/human-profile.d.ts +87 -21
- package/packages/agent-team/lib/types/human-profile.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +85 -26
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/installed-manifest.d.ts +16 -0
- package/packages/agent-team/lib/types/installed-manifest.d.ts.map +1 -0
- package/packages/agent-team/lib/types/ledger.d.ts +12 -0
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-context.d.ts +14 -0
- package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-time-context.d.ts +15 -0
- package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
- package/packages/agent-team/lib/types/pressure-policy.d.ts +5 -1
- package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
- package/packages/agent-team/lib/types/stored-session-reader.d.ts +1 -2
- package/packages/agent-team/lib/types/stored-session-reader.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +1 -8
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +84 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- 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 +615 -275
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/EnvironmentCheck.d.ts +18 -0
- package/packages/client-agent-team/lib/types/client/EnvironmentCheck.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/EnvironmentCheck.js +58 -0
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts +3 -0
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/HumanSettingsSection.js +7 -4
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +6 -11
- package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +4 -4
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamFooterAction.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -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 +1 -1
- 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/TeamPresenceDot.js +2 -7
- package/packages/client-agent-team/lib/types/client/TeamRowMenu.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamRowMenu.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamSidebarSection.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceSelector.js +2 -2
- package/packages/client-agent-team/lib/types/client/environment-check.d.ts +65 -0
- package/packages/client-agent-team/lib/types/client/environment-check.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/environment-check.js +78 -0
- package/packages/client-agent-team/lib/types/client/human-identity.d.ts +4 -8
- package/packages/client-agent-team/lib/types/client/human-identity.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/human-identity.js +0 -21
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +59 -49
- package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -8
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +21 -8
- package/packages/client-agent-team/lib/types/client/multi-menu-field.js +2 -2
- package/packages/client-agent-team/lib/types/client/slots.d.ts +1 -1
- 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/context-tools.js +106 -94
- package/packages/tool-agent-team/lib/index.js +17 -2
- package/packages/tool-agent-team/lib/types/context-tools.d.ts +16 -7
- package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/preset-roster.js +0 -15
- package/packages/agent-team/lib/session-remediation.js +0 -493
- package/packages/agent-team/lib/types/preset-roster.d.ts +0 -5
- package/packages/agent-team/lib/types/preset-roster.d.ts.map +0 -1
- package/packages/agent-team/lib/types/session-remediation.d.ts +0 -172
- package/packages/agent-team/lib/types/session-remediation.d.ts.map +0 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +0 -166
|
@@ -40,6 +40,8 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
40
40
|
done = true;
|
|
41
41
|
};
|
|
42
42
|
import { randomUUID } from 'node:crypto';
|
|
43
|
+
import { readFileSync } from 'node:fs';
|
|
44
|
+
import { join } from 'node:path';
|
|
43
45
|
import { isDeepStrictEqual } from 'node:util';
|
|
44
46
|
import { Service } from '@deepseek-ai/cordis';
|
|
45
47
|
import { installModelSelection } from '@deepseek-ai/dsh-agent';
|
|
@@ -50,18 +52,18 @@ import { Session, SessionId, SessionLogOffset } from '@deepseek-ai/dsh-session';
|
|
|
50
52
|
import { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy';
|
|
51
53
|
import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
52
54
|
import { ATTACHMENT_MAX_BYTES, attachmentPayloadPath, attachmentsRoot, copyPathAttachment, newAttachmentId, readAttachment, sanitizeMediaType, sweepAttachmentCache, validatePathAttachment, writeAttachment } from "./attachments.js";
|
|
53
|
-
import {
|
|
55
|
+
import { reportEnvironment } from "./environment-check.js";
|
|
56
|
+
import { HUMAN_PROFILE_DEFAULT_NAME, HUMAN_PROFILE_REPO_URL, HUMAN_PROFILE_SETTINGS_NAMESPACE, HUMAN_PROFILE_SETTINGS_SCHEMA, HUMAN_PROFILE_VERSION, assertValidHumanName, normalizeHumanName, parseLegacyHumanProfile, planLegacyAdoption } from "./human-profile.js";
|
|
54
57
|
import { humanAvatarsRoot, readHumanAvatar, removeHumanAvatar, writeHumanAvatar } from "./human-avatar.js";
|
|
55
58
|
import { createHumanUpdateChecker } from "./human-update-check.js";
|
|
56
59
|
import { PressurePolicyCoordinator } from "./pressure-policy.js";
|
|
57
60
|
import { CONTEXT_CONTINUITY_PROJECTION_KEY, readContextTimeline } from '@wowyuarm/dsh-context-continuity';
|
|
58
61
|
import { createTeamContextManagement, TEAM_CONTEXT_CODEC } from "./context-continuity-host.js";
|
|
59
|
-
import { AGENT_TEAM_PLUGIN_ID } from "./context-source.js";
|
|
62
|
+
import { AGENT_TEAM_PLUGIN_ID, isAgentTeamSource } from "./context-source.js";
|
|
60
63
|
import { boundaryByRef, carriedInputOf, checkpointByRef, checkpointRefFor, createTeamContextProjectionConfig, createTeamContextProjectionDefinition, foldTeamContextProjection, retainedTopicsThrough, TeamContextProjectionHost } from "./context-projection.js";
|
|
61
64
|
import { AGENT_TEAM_HUMAN_MEMBER_ID, AgentTeamLedger, agentTeamHumanActor } from "./ledger.js";
|
|
62
65
|
import { AGENT_TEAM_TOOL_NAMES, deepCopyCapabilities, memberMemoryDirectoryName, MemberRuntime } from "./member-runtime.js";
|
|
63
66
|
import { classifyRecoverableError, RecoveryCoordinator, RECOVERY_MAX_CONSECUTIVE_ERRORS } from "./recovery.js";
|
|
64
|
-
import { SessionRemediation, handoffAlreadyInLog } from "./session-remediation.js";
|
|
65
67
|
import { StoredSessionReadError, StoredSessionReader, sessionFailureOf } from "./stored-session-reader.js";
|
|
66
68
|
import { agentTeamDomainSpec } from "./spec.js";
|
|
67
69
|
import { formatTeamTimestamp } from "./time-format.js";
|
|
@@ -90,7 +92,8 @@ class PresetCompositionError extends Error {
|
|
|
90
92
|
const MAX_CHECKPOINT_NAME_CHARS = 120;
|
|
91
93
|
/** Default and maximum number of timeline items one query returns. */
|
|
92
94
|
const DEFAULT_TIMELINE_LIMIT = 12;
|
|
93
|
-
|
|
95
|
+
/** The widest timeline window there is; the ref gate reads at this width so no printed ref is unreachable. */
|
|
96
|
+
export const MAX_TIMELINE_LIMIT = 24;
|
|
94
97
|
/**
|
|
95
98
|
* Archived generations the timeline and seed resolution walk: the timeline
|
|
96
99
|
* reads this many ancestors behind the current generation, and the seed guard
|
|
@@ -98,7 +101,7 @@ const MAX_TIMELINE_LIMIT = 24;
|
|
|
98
101
|
* disagree about where history ends.
|
|
99
102
|
*/
|
|
100
103
|
const MAX_TIMELINE_ANCESTORS = 8;
|
|
101
|
-
/** Product pressure budget constants (see docs/team-collaboration.md). */
|
|
104
|
+
/** Product pressure budget constants (see docs/team-collaboration/README.md). */
|
|
102
105
|
const CONTEXT_HARD_LIMIT_CAP = 256_000;
|
|
103
106
|
const CONTEXT_HANDOFF_AT_CAP = 200_000;
|
|
104
107
|
const CONTEXT_HANDOFF_RESERVE = 8_000;
|
|
@@ -194,10 +197,12 @@ let AgentTeam = (() => {
|
|
|
194
197
|
let _sendMessage_decorators;
|
|
195
198
|
let _putAttachment_decorators;
|
|
196
199
|
let _getAttachment_decorators;
|
|
200
|
+
let _environmentForClient_decorators;
|
|
197
201
|
let _humanProfileForClient_decorators;
|
|
198
202
|
let _putHumanAvatar_decorators;
|
|
199
203
|
let _getHumanAvatar_decorators;
|
|
200
204
|
let _removeHumanAvatar_decorators;
|
|
205
|
+
let _setHumanProfile_decorators;
|
|
201
206
|
let _reply_decorators;
|
|
202
207
|
let _changeAttention_decorators;
|
|
203
208
|
let _inbox_decorators;
|
|
@@ -229,10 +234,12 @@ let AgentTeam = (() => {
|
|
|
229
234
|
_sendMessage_decorators = [Remote('sendMessage')];
|
|
230
235
|
_putAttachment_decorators = [Remote('putAttachment')];
|
|
231
236
|
_getAttachment_decorators = [Remote('getAttachment')];
|
|
237
|
+
_environmentForClient_decorators = [Remote('environment')];
|
|
232
238
|
_humanProfileForClient_decorators = [Remote('humanProfile')];
|
|
233
239
|
_putHumanAvatar_decorators = [Remote('putHumanAvatar')];
|
|
234
240
|
_getHumanAvatar_decorators = [Remote('getHumanAvatar')];
|
|
235
241
|
_removeHumanAvatar_decorators = [Remote('removeHumanAvatar')];
|
|
242
|
+
_setHumanProfile_decorators = [Remote('setHumanProfile')];
|
|
236
243
|
_reply_decorators = [Remote('reply')];
|
|
237
244
|
_changeAttention_decorators = [Remote('changeAttention')];
|
|
238
245
|
_inbox_decorators = [Remote('inbox')];
|
|
@@ -261,10 +268,12 @@ let AgentTeam = (() => {
|
|
|
261
268
|
__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);
|
|
262
269
|
__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);
|
|
263
270
|
__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);
|
|
271
|
+
__esDecorate(this, null, _environmentForClient_decorators, { kind: "method", name: "environmentForClient", static: false, private: false, access: { has: obj => "environmentForClient" in obj, get: obj => obj.environmentForClient }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
264
272
|
__esDecorate(this, null, _humanProfileForClient_decorators, { kind: "method", name: "humanProfileForClient", static: false, private: false, access: { has: obj => "humanProfileForClient" in obj, get: obj => obj.humanProfileForClient }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
265
273
|
__esDecorate(this, null, _putHumanAvatar_decorators, { kind: "method", name: "putHumanAvatar", static: false, private: false, access: { has: obj => "putHumanAvatar" in obj, get: obj => obj.putHumanAvatar }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
266
274
|
__esDecorate(this, null, _getHumanAvatar_decorators, { kind: "method", name: "getHumanAvatar", static: false, private: false, access: { has: obj => "getHumanAvatar" in obj, get: obj => obj.getHumanAvatar }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
267
275
|
__esDecorate(this, null, _removeHumanAvatar_decorators, { kind: "method", name: "removeHumanAvatar", static: false, private: false, access: { has: obj => "removeHumanAvatar" in obj, get: obj => obj.removeHumanAvatar }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
276
|
+
__esDecorate(this, null, _setHumanProfile_decorators, { kind: "method", name: "setHumanProfile", static: false, private: false, access: { has: obj => "setHumanProfile" in obj, get: obj => obj.setHumanProfile }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
268
277
|
__esDecorate(this, null, _reply_decorators, { kind: "method", name: "reply", static: false, private: false, access: { has: obj => "reply" in obj, get: obj => obj.reply }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
269
278
|
__esDecorate(this, null, _changeAttention_decorators, { kind: "method", name: "changeAttention", static: false, private: false, access: { has: obj => "changeAttention" in obj, get: obj => obj.changeAttention }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
270
279
|
__esDecorate(this, null, _inbox_decorators, { kind: "method", name: "inbox", static: false, private: false, access: { has: obj => "inbox" in obj, get: obj => obj.inbox }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -274,6 +283,8 @@ let AgentTeam = (() => {
|
|
|
274
283
|
__esDecorate(this, null, _view_decorators, { kind: "method", name: "view", static: false, private: false, access: { has: obj => "view" in obj, get: obj => obj.view }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
275
284
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
276
285
|
}
|
|
286
|
+
config = __runInitializers(this, _instanceExtraInitializers);
|
|
287
|
+
static Config = HUMAN_PROFILE_SETTINGS_SCHEMA;
|
|
277
288
|
static inject = [
|
|
278
289
|
'storageDomain',
|
|
279
290
|
'workspaceRegistry',
|
|
@@ -284,7 +295,7 @@ let AgentTeam = (() => {
|
|
|
284
295
|
'sessionPersistence',
|
|
285
296
|
'sessionProjections',
|
|
286
297
|
];
|
|
287
|
-
domain
|
|
298
|
+
domain;
|
|
288
299
|
ledger;
|
|
289
300
|
handles = new Map();
|
|
290
301
|
/** Live Member per session id; drives the root session/event listener. */
|
|
@@ -324,12 +335,6 @@ let AgentTeam = (() => {
|
|
|
324
335
|
pressurePolicy;
|
|
325
336
|
notifiedInbox = new Map();
|
|
326
337
|
attachmentGcTimer;
|
|
327
|
-
/**
|
|
328
|
-
* Current human profile source, wired to the `agent-team-human` settings
|
|
329
|
-
* namespace when a settings service is present. Falls back to the historic
|
|
330
|
-
* default so team_view and @ matching keep working without settings.
|
|
331
|
-
*/
|
|
332
|
-
humanProfileSource = () => ({ name: HUMAN_PROFILE_DEFAULT_NAME });
|
|
333
338
|
/**
|
|
334
339
|
* New-release check behind the settings footnote. Memory-only and
|
|
335
340
|
* background-refreshed, so the profile read path never waits on the
|
|
@@ -361,7 +366,7 @@ let AgentTeam = (() => {
|
|
|
361
366
|
* successful `context_rollover` tool result into its next private context
|
|
362
367
|
* generation. The ledger owns the binding audit, the engine's projection
|
|
363
368
|
* unit owns intent, and this coordinator owns only reconstructible process
|
|
364
|
-
* state. See docs/architecture.md and docs/team-collaboration.md.
|
|
369
|
+
* state. See docs/architecture/README.md and docs/team-collaboration/README.md.
|
|
365
370
|
*/
|
|
366
371
|
contextManagement = createTeamContextManagement({
|
|
367
372
|
agentForMember: memberId => this.handles.get(memberId)?.agent,
|
|
@@ -381,6 +386,8 @@ let AgentTeam = (() => {
|
|
|
381
386
|
});
|
|
382
387
|
lifecycleTail = Promise.resolve();
|
|
383
388
|
accepting = true;
|
|
389
|
+
/** One adoption attempt per boot: the two readiness edges fire once each, and this keeps their attempt single. */
|
|
390
|
+
legacyAdoptionStarted = false;
|
|
384
391
|
/**
|
|
385
392
|
* Presence wake epoch: Agent running/idle/failure is runtime state with no
|
|
386
393
|
* durable fact behind it, so the presence scope counts those edge wakes in
|
|
@@ -388,14 +395,9 @@ let AgentTeam = (() => {
|
|
|
388
395
|
*/
|
|
389
396
|
presenceEpoch = 0;
|
|
390
397
|
changeWaiters = new Set();
|
|
391
|
-
|
|
392
|
-
* The startup-opened remediation instance, held for the restart heal: the
|
|
393
|
-
* completion-cache domain may only be opened once per plugin lifecycle, so
|
|
394
|
-
* the restart path reuses this instance instead of opening its own.
|
|
395
|
-
*/
|
|
396
|
-
remediation;
|
|
397
|
-
constructor(ctx) {
|
|
398
|
+
constructor(ctx, config) {
|
|
398
399
|
super(ctx, 'agentTeam');
|
|
400
|
+
this.config = config;
|
|
399
401
|
this.pressurePolicy = new PressurePolicyCoordinator({
|
|
400
402
|
agentForMember: memberId => this.handles.get(memberId)?.agent,
|
|
401
403
|
memberForAgent: agent => {
|
|
@@ -412,37 +414,30 @@ let AgentTeam = (() => {
|
|
|
412
414
|
},
|
|
413
415
|
log: message => { this.ctx.logger.warn(`agent-team: ${message}`); },
|
|
414
416
|
});
|
|
415
|
-
// Human profile
|
|
416
|
-
// the settings
|
|
417
|
-
//
|
|
418
|
-
//
|
|
417
|
+
// Human profile: this Host row's own Config (name + avatarRef, both
|
|
418
|
+
// volatile), so the settings service derives its form from the schema and
|
|
419
|
+
// an edit lands in the running plugin without a remount. Team's own page
|
|
420
|
+
// owns that surface, so the row declares itself presentation-owned rather
|
|
421
|
+
// than schema-page owned. Reads go straight to the live Config reference;
|
|
422
|
+
// this subscription is the change signal the retired section hook used to
|
|
423
|
+
// be — the ledger's runtime @ handle follows every edit.
|
|
419
424
|
this.ctx.inject(['settings'], settingsCtx => {
|
|
420
|
-
settingsCtx.settings.
|
|
421
|
-
|
|
422
|
-
this.humanProfileSource = current;
|
|
423
|
-
this.syncHumanHandle();
|
|
424
|
-
},
|
|
425
|
-
validate: (value) => {
|
|
426
|
-
this.validateHumanProfile(value);
|
|
427
|
-
},
|
|
428
|
-
onChange: () => {
|
|
429
|
-
this.syncHumanHandle();
|
|
430
|
-
},
|
|
431
|
-
});
|
|
425
|
+
settingsCtx.effect(() => settingsCtx.settings.configure({ auto: false }, this.ctx.fiber));
|
|
426
|
+
this.adoptLegacyHumanProfile();
|
|
432
427
|
});
|
|
428
|
+
this.ctx.on('loader/volatile-update', () => { this.syncHumanHandle(); });
|
|
433
429
|
}
|
|
434
430
|
/** Current human display name; the single source for team_view and @ matching. */
|
|
435
431
|
humanHandle() {
|
|
436
|
-
const name = normalizeHumanName(this.
|
|
432
|
+
const name = normalizeHumanName(this.config.name.get());
|
|
437
433
|
return name === '' ? HUMAN_PROFILE_DEFAULT_NAME : name;
|
|
438
434
|
}
|
|
439
|
-
/** Current human profile reference held in
|
|
435
|
+
/** Current human profile reference held in this Host row's Config (name + avatarRef). */
|
|
440
436
|
humanProfile() {
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
return Object.freeze({ name, ...(current.avatarRef === undefined ? {} : { avatarRef: current.avatarRef }) });
|
|
437
|
+
const avatarRef = this.config.avatarRef.get();
|
|
438
|
+
return Object.freeze({ name: this.humanHandle(), ...(avatarRef === undefined ? {} : { avatarRef }) });
|
|
444
439
|
}
|
|
445
|
-
/** Push the current
|
|
440
|
+
/** Push the current Config name into the ledger's runtime @ handle. */
|
|
446
441
|
syncHumanHandle() {
|
|
447
442
|
try {
|
|
448
443
|
this.ledger?.setHumanDisplayHandle(this.humanHandle());
|
|
@@ -452,9 +447,11 @@ let AgentTeam = (() => {
|
|
|
452
447
|
}
|
|
453
448
|
}
|
|
454
449
|
/**
|
|
455
|
-
*
|
|
456
|
-
* Member handles plus global uniqueness against live
|
|
457
|
-
* the
|
|
450
|
+
* The two judgements the Config schema cannot make about a Human name: the
|
|
451
|
+
* same non-empty floor as Member handles, plus global uniqueness against live
|
|
452
|
+
* Members. `setHumanProfile` runs it before the write, so a colliding rename
|
|
453
|
+
* rejects instead of persisting. It reads the one field it judges, so the
|
|
454
|
+
* caller passes the name alone rather than a whole profile shape.
|
|
458
455
|
*/
|
|
459
456
|
validateHumanProfile(value) {
|
|
460
457
|
const name = assertValidHumanName(value.name);
|
|
@@ -470,6 +467,73 @@ let AgentTeam = (() => {
|
|
|
470
467
|
}
|
|
471
468
|
}
|
|
472
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* One-time adoption of the profile facts the retired `agent-team-human`
|
|
472
|
+
* settings section held (see `LEGACY_HUMAN_PROFILE_SECTION` for why the
|
|
473
|
+
* upstream importer cannot carry them over). The values land in this Host
|
|
474
|
+
* row's own Config through the same Remote the profile page writes, so the
|
|
475
|
+
* page, the ledger's @ handle, and every avatar seat follow as after any
|
|
476
|
+
* edit. Readiness has two one-way edges — the settings service arrives, the
|
|
477
|
+
* ledger opens — and whichever fires second starts the attempt; only a
|
|
478
|
+
* pristine profile is adopted, and one attempt per boot is its whole
|
|
479
|
+
* lifetime, so adoption never loops and never re-writes.
|
|
480
|
+
*/
|
|
481
|
+
adoptLegacyHumanProfile() {
|
|
482
|
+
if (this.legacyAdoptionStarted)
|
|
483
|
+
return;
|
|
484
|
+
if (this.ctx.get('settings') === undefined || this.ledger === undefined)
|
|
485
|
+
return;
|
|
486
|
+
this.legacyAdoptionStarted = true;
|
|
487
|
+
void this.adoptLegacyHumanProfileNow().catch((error) => {
|
|
488
|
+
this.ctx.logger.warn('agent-team: legacy human profile adoption failed: %s', String(error));
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
/** Carry the first legacy document that still has the section into a pristine profile. */
|
|
492
|
+
async adoptLegacyHumanProfileNow() {
|
|
493
|
+
// A profile-launched Host always carries the profile context; a Host booted
|
|
494
|
+
// without one still adopts from the DSH home, which is where a pre-rc.1
|
|
495
|
+
// install kept the document. Read through `get`: cordis refuses a direct
|
|
496
|
+
// `ctx.profileContext` for a service this plugin does not declare, and
|
|
497
|
+
// adoption may not gate the Host on app-boot.
|
|
498
|
+
const profileHome = this.ctx.get('profileContext')?.home;
|
|
499
|
+
const homes = profileHome === undefined ? [dshHomePath()] : [dshHomePath(), profileHome];
|
|
500
|
+
const candidates = new Set(homes.flatMap(home => [join(home, 'settings.yaml'), join(home, 'settings.yaml.imported')]));
|
|
501
|
+
let legacy;
|
|
502
|
+
let source;
|
|
503
|
+
for (const candidate of candidates) {
|
|
504
|
+
let text;
|
|
505
|
+
try {
|
|
506
|
+
text = readFileSync(candidate, 'utf8');
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
// Absent candidates are the steady state once adoption settles; the
|
|
510
|
+
// live document is one only because the first boot after the upgrade
|
|
511
|
+
// can race the importer that renames it.
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
const parsed = parseLegacyHumanProfile(text);
|
|
515
|
+
if (parsed !== undefined) {
|
|
516
|
+
legacy = parsed;
|
|
517
|
+
source = candidate;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (legacy === undefined || source === undefined)
|
|
522
|
+
return;
|
|
523
|
+
// The reference is carried only while its bytes still draw: the avatar
|
|
524
|
+
// store is the authority for whether this avatar exists at all.
|
|
525
|
+
let avatarRef = legacy.avatarRef;
|
|
526
|
+
if (avatarRef !== undefined && await readHumanAvatar(humanAvatarsRoot(), avatarRef) === undefined)
|
|
527
|
+
avatarRef = undefined;
|
|
528
|
+
const plan = planLegacyAdoption(this.humanProfile(), {
|
|
529
|
+
...(legacy.name === undefined ? {} : { name: legacy.name }),
|
|
530
|
+
...(avatarRef === undefined ? {} : { avatarRef }),
|
|
531
|
+
});
|
|
532
|
+
if (plan === undefined)
|
|
533
|
+
return;
|
|
534
|
+
await this.setHumanProfile(plan);
|
|
535
|
+
this.ctx.logger.info('agent-team: adopted the legacy human profile from %s', source);
|
|
536
|
+
}
|
|
473
537
|
/** Open the durable ledger and restore every enabled Member independently. */
|
|
474
538
|
async [Service.init]() {
|
|
475
539
|
// The continuity projection registers once per Host: the framework keeps
|
|
@@ -545,7 +609,6 @@ let AgentTeam = (() => {
|
|
|
545
609
|
const domain = await this.ctx.storageDomain.open(agentTeamDomainSpec);
|
|
546
610
|
this.ctx.effect(() => async () => {
|
|
547
611
|
this.accepting = false;
|
|
548
|
-
this.remediation = undefined;
|
|
549
612
|
this.recovery.dispose();
|
|
550
613
|
this.contextManagement.dispose();
|
|
551
614
|
this.pressurePolicy.dispose();
|
|
@@ -564,25 +627,15 @@ let AgentTeam = (() => {
|
|
|
564
627
|
this.domain = domain;
|
|
565
628
|
const ledger = new AgentTeamLedger(domain.table('operations'));
|
|
566
629
|
this.ledger = ledger;
|
|
567
|
-
//
|
|
568
|
-
// existed; sync once here so @ matching starts from the stored
|
|
630
|
+
// A live Config edit in the constructor's window may have arrived before
|
|
631
|
+
// the ledger existed; sync once here so @ matching starts from the stored
|
|
632
|
+
// name.
|
|
569
633
|
this.syncHumanHandle();
|
|
634
|
+
this.adoptLegacyHumanProfile();
|
|
570
635
|
const initialization = await ledger.initialize();
|
|
571
636
|
if (initialization.committed)
|
|
572
637
|
this.emitCommitted(initialization.value);
|
|
573
638
|
this.startAttachmentGc(ledger);
|
|
574
|
-
// Legacy-artifact remediation runs before any Member activation: no write
|
|
575
|
-
// lease exists yet, so publishing sibling generations for refused Session
|
|
576
|
-
// logs cannot race a live writer. Remediation failure never blocks
|
|
577
|
-
// startup — the next start retries exactly what the cache does not cover.
|
|
578
|
-
try {
|
|
579
|
-
const remediation = new SessionRemediation(this.ctx, this.ctx.sessionPersistence, await SessionRemediation.open(this.ctx));
|
|
580
|
-
this.remediation = remediation;
|
|
581
|
-
await remediation.remediateEnabledMembers(ledger.listMembers());
|
|
582
|
-
}
|
|
583
|
-
catch (error) {
|
|
584
|
-
this.ctx.logger.warn(`agent-team: legacy Session remediation did not run to completion (it will retry on the next start): ${error instanceof Error ? error.message : String(error)}`);
|
|
585
|
-
}
|
|
586
639
|
// One metadata listing serves every Member restore; per-member list calls
|
|
587
640
|
// would repeat the same I/O linearly during startup.
|
|
588
641
|
const persistedSessions = new Set((await this.persistedSessionHeaders()).map(snapshot => snapshot.header.id));
|
|
@@ -836,23 +889,10 @@ let AgentTeam = (() => {
|
|
|
836
889
|
if (member.state !== 'enabled')
|
|
837
890
|
throw new Error(`Agent Member '${member.handle}' is ${member.state}; only enabled Members can be restarted`);
|
|
838
891
|
this.ctx.logger.info(`agent-team: restarting member '${member.handle}' after a failed activation`);
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
//
|
|
842
|
-
|
|
843
|
-
if (activation !== undefined && activation.class === 'session-refused' && this.remediation !== undefined) {
|
|
844
|
-
const outcome = await this.remediation.remediateMember(member);
|
|
845
|
-
if (outcome.repaired > 0) {
|
|
846
|
-
this.ctx.logger.info(`agent-team: repaired ${outcome.repaired} refused Session artifact(s) for member '${member.handle}'; retrying activation`);
|
|
847
|
-
}
|
|
848
|
-
else if (outcome.completed) {
|
|
849
|
-
// The walk finished and nothing was provably this plugin's to fix:
|
|
850
|
-
// a retry would fail identically. Mark the refusal non-remediable
|
|
851
|
-
// so the surface stops offering restart and says why.
|
|
852
|
-
this.markRefusalNonRemediable(request.memberId);
|
|
853
|
-
return Object.freeze({ status: this.memberStatus(member) });
|
|
854
|
-
}
|
|
855
|
-
}
|
|
892
|
+
// There is no write-side repair pass anymore: dsh 0.1.7 converts the
|
|
893
|
+
// released V3 history at read time, and this bundle no longer authors
|
|
894
|
+
// the old wrapper shape, so a refusal stays a deterministic failure the
|
|
895
|
+
// retry reports again rather than something the restart heals.
|
|
856
896
|
await this.reactivateMember(request.memberId);
|
|
857
897
|
return Object.freeze({ status: this.memberStatus(member) });
|
|
858
898
|
}
|
|
@@ -1068,7 +1108,7 @@ let AgentTeam = (() => {
|
|
|
1068
1108
|
const body = notifications.length === 0 ? text : `${text}\n\n${this.notificationText(notifications, member.memberId)}`;
|
|
1069
1109
|
const hint = createUserMessage({
|
|
1070
1110
|
content: [{ type: 'text', text: body }],
|
|
1071
|
-
source: { kind:
|
|
1111
|
+
source: { kind: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: RECOVERY_NOTICE_SUMMARY },
|
|
1072
1112
|
});
|
|
1073
1113
|
for (const pending of [...handle.agent.inbox.nextStep, ...handle.agent.inbox.nextTurn]) {
|
|
1074
1114
|
if (this.isInboxNotice(pending))
|
|
@@ -1276,12 +1316,32 @@ let AgentTeam = (() => {
|
|
|
1276
1316
|
}
|
|
1277
1317
|
/**
|
|
1278
1318
|
* Human profile read for the settings page and footnote: name + avatar
|
|
1279
|
-
* reference from
|
|
1280
|
-
* Client calls it); agent tools never receive avatar bytes, only the
|
|
1281
|
-
* through team_view. The new-release check stays best-effort and cached —
|
|
1319
|
+
* reference from this Host row's live Config plus version facts. Human-scoped
|
|
1320
|
+
* (the Web Client calls it); agent tools never receive avatar bytes, only the
|
|
1321
|
+
* name through team_view. The new-release check stays best-effort and cached —
|
|
1282
1322
|
* `updateAvailable` is false until a background refresh actually observes a
|
|
1283
1323
|
* newer published release.
|
|
1284
1324
|
*/
|
|
1325
|
+
/**
|
|
1326
|
+
* Local environment check for the settings page: which DSH line this Host
|
|
1327
|
+
* runs against, and whether that line is inside the range this bundle
|
|
1328
|
+
* declares. Human-scoped and read-only — the Client renders the verdict and
|
|
1329
|
+
* states the range in words, and nothing here is written back.
|
|
1330
|
+
*
|
|
1331
|
+
* Synchronous like `humanProfile`: both read the installed manifest once and
|
|
1332
|
+
* settle immediately, and the verdict comes from the Harness's own
|
|
1333
|
+
* compatibility evaluator rather than a second version comparison written
|
|
1334
|
+
* here.
|
|
1335
|
+
*
|
|
1336
|
+
* The wire type and `EnvironmentReport` keep separate top-level field lists on
|
|
1337
|
+
* purpose: the contract states every fact as optional because a Transport may
|
|
1338
|
+
* withhold any of them, while the report is the stricter thing the checker
|
|
1339
|
+
* guarantees. This assignment is where the compiler holds the two together,
|
|
1340
|
+
* and a new required contract field fails it here.
|
|
1341
|
+
*/
|
|
1342
|
+
environmentForClient(_request) {
|
|
1343
|
+
return Object.freeze(reportEnvironment());
|
|
1344
|
+
}
|
|
1285
1345
|
humanProfileForClient(_request) {
|
|
1286
1346
|
const profile = this.humanProfile();
|
|
1287
1347
|
const update = this.humanUpdateCheck.snapshot();
|
|
@@ -1318,6 +1378,47 @@ let AgentTeam = (() => {
|
|
|
1318
1378
|
await removeHumanAvatar(humanAvatarsRoot(), request.avatarRef);
|
|
1319
1379
|
return Object.freeze({ removed: true });
|
|
1320
1380
|
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Overwrite the Human profile fields the caller supplies. The Host owns this
|
|
1383
|
+
* write because the profile is the Host row's own Config: the schema supplies
|
|
1384
|
+
* the shape, this method supplies the two judgements the schema cannot make
|
|
1385
|
+
* (a non-empty name, a name no live Member already answers to), and the
|
|
1386
|
+
* settings service persists the result into the active profile's patch
|
|
1387
|
+
* document and applies it to the running plugin live.
|
|
1388
|
+
*
|
|
1389
|
+
* No expected revision accompanies the write: the profile is two scalar
|
|
1390
|
+
* fields written from the Human's own pages, where the last write wins. This
|
|
1391
|
+
* is not a hard boundary around a user-editable document — the settings
|
|
1392
|
+
* service's own document opener (and a text editor) can change the stored
|
|
1393
|
+
* name without passing here, exactly as the retired section validator could
|
|
1394
|
+
* not stop it.
|
|
1395
|
+
*/
|
|
1396
|
+
async setHumanProfile(request) {
|
|
1397
|
+
this.requireAccepting();
|
|
1398
|
+
const settings = this.ctx.get('settings');
|
|
1399
|
+
if (settings === undefined)
|
|
1400
|
+
throw new Error('the settings service is unavailable');
|
|
1401
|
+
const name = request.name === undefined ? undefined : assertValidHumanName(request.name);
|
|
1402
|
+
if (name !== undefined)
|
|
1403
|
+
this.validateHumanProfile({ name });
|
|
1404
|
+
const ops = [];
|
|
1405
|
+
if (name !== undefined)
|
|
1406
|
+
ops.push({ op: 'set', path: ['name'], value: name });
|
|
1407
|
+
if (request.avatarRef === null)
|
|
1408
|
+
ops.push({ op: 'unset', path: ['avatarRef'] });
|
|
1409
|
+
else if (request.avatarRef !== undefined)
|
|
1410
|
+
ops.push({ op: 'set', path: ['avatarRef'], value: request.avatarRef });
|
|
1411
|
+
if (ops.length !== 0) {
|
|
1412
|
+
// The settings namespace IS this Host row's id in the composition, and it
|
|
1413
|
+
// must be addressed by that name rather than by `ctx.fiber.entry` here: a
|
|
1414
|
+
// Remote call runs under its caller's context, whose fiber entry is the
|
|
1415
|
+
// RPC gateway's row (`typert-gateway`), which the settings service then
|
|
1416
|
+
// looks up as an unrelated plugin. shipping.spec.ts pins the constant to
|
|
1417
|
+
// the row `cordis.patch.yml` declares.
|
|
1418
|
+
await settings.mutate(HUMAN_PROFILE_SETTINGS_NAMESPACE, ops);
|
|
1419
|
+
}
|
|
1420
|
+
return Object.freeze({ ...this.humanProfile() });
|
|
1421
|
+
}
|
|
1321
1422
|
/** Human existing-Thread reply; unread and revision conflicts are business outcomes. */
|
|
1322
1423
|
async reply(request) {
|
|
1323
1424
|
return this.replyAs(this.humanCall(request.workspaceId), request);
|
|
@@ -1483,7 +1584,7 @@ let AgentTeam = (() => {
|
|
|
1483
1584
|
try {
|
|
1484
1585
|
const message = createUserMessage({
|
|
1485
1586
|
content: [{ type: 'text', text: this.dmRelayText(agent, recipient, request.body.trim(), result.value.receipt.occurredAt, result.value.receipt.operationId, request.workspaceId) }],
|
|
1486
|
-
source: { kind:
|
|
1587
|
+
source: { kind: AGENT_TEAM_PLUGIN_ID, form: 'relay' },
|
|
1487
1588
|
});
|
|
1488
1589
|
// An idle recipient gets one ordinary turn; a busy one is steered into
|
|
1489
1590
|
// its current turn — the same wake split subagent continuations use.
|
|
@@ -2430,12 +2531,11 @@ let AgentTeam = (() => {
|
|
|
2430
2531
|
// delivered activates the new Session with no handoff in its own
|
|
2431
2532
|
// log — never treat that as an ordinary blank Member Session. The
|
|
2432
2533
|
// operation's recorded previous Session (the lineage parent) still
|
|
2433
|
-
// holds the intent; rebuild the handoff from it.
|
|
2434
|
-
//
|
|
2435
|
-
//
|
|
2436
|
-
//
|
|
2437
|
-
|
|
2438
|
-
if (!handoffAlreadyInLog(state.boundaries, created.agent.session.ownEvents())) {
|
|
2534
|
+
// holds the intent; rebuild the handoff from it. Presence is judged
|
|
2535
|
+
// by the projection boundary alone: every handoff this Host ever
|
|
2536
|
+
// published classifies under the context source's recognizer,
|
|
2537
|
+
// including the history the read-time conversion renamed.
|
|
2538
|
+
if (!state.boundaries.some(boundary => boundary.kind === 'handoff')) {
|
|
2439
2539
|
await this.reconstructMissingHandoff(member, created.agent);
|
|
2440
2540
|
}
|
|
2441
2541
|
// Carried input redelivery binds to the committed transition target —
|
|
@@ -2609,14 +2709,6 @@ let AgentTeam = (() => {
|
|
|
2609
2709
|
}
|
|
2610
2710
|
return { class: 'activation', detail: error instanceof Error ? error.message : String(error) };
|
|
2611
2711
|
}
|
|
2612
|
-
/** Mark a session-refused activation diagnostic as proven non-remediable. */
|
|
2613
|
-
markRefusalNonRemediable(memberId) {
|
|
2614
|
-
const failures = this.memberFailures.get(memberId);
|
|
2615
|
-
const activation = failures?.activation;
|
|
2616
|
-
if (activation === undefined || activation.class !== 'session-refused')
|
|
2617
|
-
return;
|
|
2618
|
-
failures.activation = Object.freeze({ ...activation, remediable: false });
|
|
2619
|
-
}
|
|
2620
2712
|
clearMemberFailure(memberId, slot) {
|
|
2621
2713
|
const failures = this.memberFailures.get(memberId);
|
|
2622
2714
|
if (failures === undefined || failures[slot] === undefined)
|
|
@@ -2657,7 +2749,7 @@ let AgentTeam = (() => {
|
|
|
2657
2749
|
const path = this.ctx.workspaceRegistry.get(operation.data.workspaceId)?.path;
|
|
2658
2750
|
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.`;
|
|
2659
2751
|
const notice = createUserMessage({ content: [{ type: 'text', text }],
|
|
2660
|
-
source: { kind:
|
|
2752
|
+
source: { kind: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: 'Team Workspace participation changed' } });
|
|
2661
2753
|
try {
|
|
2662
2754
|
if (agent.status === 'idle' || agent.inbox.nextTurn.some(message => message.source.kind === 'user'))
|
|
2663
2755
|
agent.followup(notice);
|
|
@@ -2754,7 +2846,7 @@ let AgentTeam = (() => {
|
|
|
2754
2846
|
agent.inbox.remove(existingInboxHint.id);
|
|
2755
2847
|
const hint = createUserMessage({
|
|
2756
2848
|
content: [{ type: 'text', text: this.notificationText(notifications, member.memberId) }],
|
|
2757
|
-
source: { kind:
|
|
2849
|
+
source: { kind: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: INBOX_NOTICE_SUMMARY },
|
|
2758
2850
|
});
|
|
2759
2851
|
this.notifiedInbox.set(member.memberId, signature);
|
|
2760
2852
|
try {
|
|
@@ -2775,12 +2867,12 @@ let AgentTeam = (() => {
|
|
|
2775
2867
|
}
|
|
2776
2868
|
isInboxNotice(message) {
|
|
2777
2869
|
const source = message.source;
|
|
2778
|
-
return source
|
|
2870
|
+
return isAgentTeamSource(source)
|
|
2779
2871
|
&& source.form === 'notice' && source.summary === INBOX_NOTICE_SUMMARY;
|
|
2780
2872
|
}
|
|
2781
2873
|
isRecoveryNotice(message) {
|
|
2782
2874
|
const source = message.source;
|
|
2783
|
-
return source
|
|
2875
|
+
return isAgentTeamSource(source)
|
|
2784
2876
|
&& source.form === 'notice' && source.summary === RECOVERY_NOTICE_SUMMARY;
|
|
2785
2877
|
}
|
|
2786
2878
|
notificationText(notifications, readerId) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** The installed bundle's own manifest, read once for both facts taken from it. */
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
/**
|
|
6
|
+
* Parsed manifest of the installed bundle, or `undefined` when it cannot be
|
|
7
|
+
* read.
|
|
8
|
+
*
|
|
9
|
+
* Three levels up: `packages/agent-team/{src,lib}` sits that deep in both a
|
|
10
|
+
* `link:` checkout and a registry tarball, so a development install and a
|
|
11
|
+
* published one each state their own truth. An unreadable or malformed manifest
|
|
12
|
+
* is a broken install, not a failure of whatever asked: every caller degrades to
|
|
13
|
+
* `'unknown'` or withholds the line it would have stated, so reading this can
|
|
14
|
+
* never fail the Host boot.
|
|
15
|
+
*/
|
|
16
|
+
export function readInstalledManifest() {
|
|
17
|
+
try {
|
|
18
|
+
const manifestPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../../package.json');
|
|
19
|
+
const parsed = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
20
|
+
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
|
|
21
|
+
? parsed
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Version of the manifest this package installed from, or `'unknown'`. */
|
|
29
|
+
export function bundleVersionOf(manifest) {
|
|
30
|
+
const version = manifest?.version;
|
|
31
|
+
return typeof version === 'string' && version !== '' ? version : 'unknown';
|
|
32
|
+
}
|
|
@@ -1586,6 +1586,7 @@ export class AgentTeamLedger {
|
|
|
1586
1586
|
})),
|
|
1587
1587
|
taskNumbers: Object.freeze(visibleTasks.map(task => Object.freeze({ taskRef: task.taskRef, taskNumber: taskNumbers.get(task.taskRef) ?? 0 }))),
|
|
1588
1588
|
items: Object.freeze(items),
|
|
1589
|
+
activeTaskThreads: this.activeTaskThreads(visibleTasks, taskNumbers),
|
|
1589
1590
|
claims: this.claimsForVisibleTasks(visibleTasks),
|
|
1590
1591
|
activities: Object.freeze(selected.filter((fact) => fact.kind === 'activity').map(fact => fact.activity)),
|
|
1591
1592
|
cursor: nextCursor,
|
|
@@ -3172,6 +3173,40 @@ export class AgentTeamLedger {
|
|
|
3172
3173
|
const refs = new Set(tasks.map(task => task.taskRef));
|
|
3173
3174
|
return Object.freeze([...this.state.claims.values()].filter(claim => refs.has(claim.taskRef)));
|
|
3174
3175
|
}
|
|
3176
|
+
/**
|
|
3177
|
+
* The team_view「活跃 task thread」radar for a Workspace: every visible Task
|
|
3178
|
+
* still in flight — in_progress or in_review, the two states a live Claim
|
|
3179
|
+
* keeps a Task in — newest activity first. Unlike `recentInboxItems`, this is
|
|
3180
|
+
* not a participation slice: admission is the Task being active in a Channel
|
|
3181
|
+
* the reader can see, whether or not the reader wrote in it, and a Thread
|
|
3182
|
+
* still holding the reader's unread is not excluded. Rows carry the same
|
|
3183
|
+
* `liveClaimOwners`口径 the Inbox and Channel feed already use, so 「谁在这个
|
|
3184
|
+
* Task 上」 never gains a second definition. Archived Channels are already
|
|
3185
|
+
* absent from `visibleTasks`, so their Tasks never reach here.
|
|
3186
|
+
*/
|
|
3187
|
+
activeTaskThreads(visibleTasks, taskNumbers) {
|
|
3188
|
+
const rows = [];
|
|
3189
|
+
for (const task of visibleTasks) {
|
|
3190
|
+
if (task.status !== 'in_progress' && task.status !== 'in_review')
|
|
3191
|
+
continue;
|
|
3192
|
+
const thread = this.state.threads.get(task.threadRef);
|
|
3193
|
+
if (thread === undefined)
|
|
3194
|
+
continue;
|
|
3195
|
+
const newest = (this.state.factsByThread.get(thread.threadRef) ?? []).at(-1);
|
|
3196
|
+
if (newest === undefined)
|
|
3197
|
+
continue;
|
|
3198
|
+
const taskNumber = taskNumbers.get(task.taskRef);
|
|
3199
|
+
rows.push({
|
|
3200
|
+
row: Object.freeze({ taskRef: task.taskRef, threadRef: thread.threadRef, channelRef: task.channelRef,
|
|
3201
|
+
...(taskNumber === undefined ? {} : { taskNumber }), status: task.status,
|
|
3202
|
+
subject: boundedInboxPreview(this.threadAnchor(thread.threadRef).body),
|
|
3203
|
+
members: this.liveClaimOwners(task), lastActivityAt: newest.occurredAt }),
|
|
3204
|
+
sequence: newest.sequence,
|
|
3205
|
+
});
|
|
3206
|
+
}
|
|
3207
|
+
rows.sort((left, right) => right.sequence - left.sequence || left.row.threadRef.localeCompare(right.row.threadRef));
|
|
3208
|
+
return Object.freeze(rows.map(entry => entry.row));
|
|
3209
|
+
}
|
|
3175
3210
|
tasksForClaims(claims, projected) {
|
|
3176
3211
|
return Object.freeze([...new Set(claims.map(claim => claim.taskRef))].map(taskRef => {
|
|
3177
3212
|
const task = this.state.tasks.get(taskRef);
|
|
@@ -2,6 +2,7 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
4
4
|
import { SessionLogOffset } from '@deepseek-ai/dsh-session';
|
|
5
|
+
import { matchesProducerKind } from "./context-source.js";
|
|
5
6
|
import { memberMemoryDirectoryPath } from "./member-runtime.js";
|
|
6
7
|
export const name = 'wowyuarm-agent-team-member-context';
|
|
7
8
|
const MAX_MEMORY_BYTES = 16 * 1024;
|
|
@@ -42,8 +43,7 @@ export function apply(ctx) {
|
|
|
42
43
|
// number domains explicit (the seq = log.length contiguity contract).
|
|
43
44
|
const event = agent.session.snapshotEvents(SessionLogOffset(sequence), SessionLogOffset(sequence + 1))[0];
|
|
44
45
|
return event?.type === 'user/message'
|
|
45
|
-
&& event.data.source.kind
|
|
46
|
-
&& event.data.source.plugin === name
|
|
46
|
+
&& matchesProducerKind(event.data.source.kind, name)
|
|
47
47
|
&& event.data.content[0]?.type === 'text'
|
|
48
48
|
? [event.data.content[0].text]
|
|
49
49
|
: [];
|
|
@@ -53,7 +53,7 @@ export function apply(ctx) {
|
|
|
53
53
|
return decision;
|
|
54
54
|
const message = createUserMessage({
|
|
55
55
|
content: [{ type: 'text', text }],
|
|
56
|
-
source: { kind:
|
|
56
|
+
source: { kind: name, form: 'instructions' },
|
|
57
57
|
});
|
|
58
58
|
return { kind: 'enter', messages: [...decision.messages, message] };
|
|
59
59
|
}, { prepend: true });
|