@wowyuarm/dsh-agent-team 0.1.11 → 0.1.12
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 +4 -4
- package/README.zh.md +4 -4
- package/package.json +3 -2
- package/packages/agent-team/README.md +2 -2
- package/packages/agent-team/README.zh.md +2 -2
- package/packages/agent-team/lib/context-projection.js +5 -1
- package/packages/agent-team/lib/index.js +11 -44
- package/packages/agent-team/lib/ledger.js +251 -142
- package/packages/agent-team/lib/member-runtime.js +47 -9
- package/packages/agent-team/lib/mentions.js +56 -0
- package/packages/agent-team/lib/spec.js +1 -0
- package/packages/agent-team/lib/typert.host.js +80 -31
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +71 -26
- package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +1 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +75 -17
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
- package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
- package/packages/agent-team/lib/types/mentions.d.ts +34 -0
- package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/entities.d.ts +0 -18
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +57 -15
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +48 -8
- package/packages/client-agent-team/lib/client.js +1366 -909
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +3 -3
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
- 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 +125 -13
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +10 -3
- package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamComposer.js +11 -17
- package/packages/client-agent-team/lib/types/client/TeamConversation.js +1 -1
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +9 -5
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +82 -14
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
- package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +6 -2
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +28 -10
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +3 -4
- package/packages/client-agent-team/lib/types/client/locales.d.ts +36 -16
- package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/locales.js +36 -16
- package/packages/client-agent-team/lib/types/client/slots.d.ts +0 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts +7 -1
- package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/team-changes.js +62 -31
- package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +38 -5
- 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 +54 -7
- package/packages/tool-agent-team/README.md +2 -2
- package/packages/tool-agent-team/README.zh.md +2 -2
- package/packages/tool-agent-team/lib/index.js +29 -16
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/progress-nudge.js +0 -328
- package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
- package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
- package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentTeamDmDeliveryError, markAgentTeamPreset } from '@wowyuarm/dsh-agent-team/host';
|
|
1
|
+
import { AGENT_TEAM_HUMAN_HANDLE, AgentTeamDmDeliveryError, markAgentTeamPreset } from '@wowyuarm/dsh-agent-team/host';
|
|
2
2
|
import { formatTeamTimestamp } from '@wowyuarm/dsh-agent-team/time-format';
|
|
3
3
|
import { registerContextTools } from "./context-tools.js";
|
|
4
4
|
import { member, service } from "./host-access.js";
|
|
@@ -167,7 +167,7 @@ const teamInbox = defineTool({
|
|
|
167
167
|
});
|
|
168
168
|
const teamThread = defineTool({
|
|
169
169
|
name: 'team_thread',
|
|
170
|
-
description: 'Read or manage your Attention on one Thread. read acknowledges one chronological batch of unread facts and is the only read-side source of a next-write token — and only once no unread remains; your own committed public mutations hand off the token as well. history pages older facts without changing read state; status, follow, and unfollow change or report Attention only and render no Thread timeline. Prefer threadRef; taskRef is a compatibility alias when the Thread has a Task.',
|
|
170
|
+
description: 'Read or manage your Attention on one Thread. read acknowledges one chronological batch of unread facts and is the only read-side source of a next-write token — and only once no unread remains; your own committed public mutations hand off the token as well. A read orients on the Thread anchor and that batch, never the whole Thread: a Member re-entering one it has read before gets no background at all, so the facts between are its own to page back to. history pages older facts without changing read state; status, follow, and unfollow change or report Attention only and render no Thread timeline. Prefer threadRef; taskRef is a compatibility alias when the Thread has a Task.',
|
|
171
171
|
parameters: {
|
|
172
172
|
action: { type: 'string', required: true, enum: ['status', 'follow', 'unfollow', 'read', 'history'] },
|
|
173
173
|
threadRef: { type: 'string', description: "Full branded Thread ref exactly as returned by Team tools, including the 'thread:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
|
|
@@ -178,7 +178,7 @@ const teamThread = defineTool({
|
|
|
178
178
|
schema: { type: 'object', additionalProperties: false, properties: {
|
|
179
179
|
kind: { type: 'string', required: true }, threadRef: { type: 'string', required: true }, taskRef: { type: 'string' },
|
|
180
180
|
revision: { type: 'number', required: true }, status: { type: 'string' }, resolution: { type: 'string' }, taskNumber: { type: 'number' },
|
|
181
|
-
following: { type: 'boolean', required: true }, readThroughSequence: { type: 'number' }, remainingUnreadCount: { type: 'number' }, cursor: { type: 'number' }, hasMore: { type: 'boolean' },
|
|
181
|
+
following: { type: 'boolean', required: true }, readThroughSequence: { type: 'number' }, remainingUnreadCount: { type: 'number' }, earlierFactCount: { type: 'number' }, cursor: { type: 'number' }, hasMore: { type: 'boolean' },
|
|
182
182
|
anchor: { type: 'object', required: true, additionalProperties: false, properties: {
|
|
183
183
|
messageRef: { type: 'string', required: true }, sender: { type: 'string', required: true }, body: { type: 'string', required: true }, sequence: { type: 'number', required: true }, occurredAt: { type: 'string' },
|
|
184
184
|
} },
|
|
@@ -263,6 +263,13 @@ const teamThread = defineTool({
|
|
|
263
263
|
else
|
|
264
264
|
lines.push(...facts.map(fact => factLine(fact)));
|
|
265
265
|
lines.push('', `Read through sequence ${value.readThroughSequence}; ${remaining} unread update(s) remaining${remaining > 0 ? ' — call team_thread read again.' : '.'}`);
|
|
266
|
+
// What this bounded read answered with is the newest batch; the span
|
|
267
|
+
// before the watermark is the orientation it did not supply. Rendering
|
|
268
|
+
// the count is what lets a returning reader see the size of that span
|
|
269
|
+
// instead of assuming the batch is the Thread.
|
|
270
|
+
const earlier = value.earlierFactCount ?? 0;
|
|
271
|
+
if (earlier > 0)
|
|
272
|
+
lines.push(`Earlier facts: ${earlier} — read older ones with team_thread.history.`);
|
|
266
273
|
if (value.contextAdvice !== undefined)
|
|
267
274
|
lines.push('', ...adviceLines(value.contextAdvice));
|
|
268
275
|
if (remaining === 0)
|
|
@@ -311,7 +318,7 @@ const teamThread = defineTool({
|
|
|
311
318
|
const read = await host.readThreadForAgent(agent, { requestId: requestId(agent.id, exec.callId), ...base });
|
|
312
319
|
return threadResult('read', read, read.attention, read.facts.map(entry => entry.fact.kind === 'message'
|
|
313
320
|
? { sequence: entry.fact.sequence, kind: 'message', body: entry.fact.message.body, sender: entry.fact.message.sender, mentions: [...entry.fact.mentions], unread: entry.unread, direct: entry.direct, occurredAt: entry.fact.occurredAt }
|
|
314
|
-
: activityFactView(entry.fact.sequence, entry.fact.activity, { unread: entry.unread, direct: entry.direct }, entry.fact.occurredAt)), { readThroughSequence: read.readThroughSequence, remainingUnreadCount: read.remainingUnreadCount, ...(read.contextAdvice === undefined ? {} : { contextAdvice: adviceView(read.contextAdvice) }), ...taskNumberOf(read.task) });
|
|
321
|
+
: activityFactView(entry.fact.sequence, entry.fact.activity, { unread: entry.unread, direct: entry.direct }, entry.fact.occurredAt)), { readThroughSequence: read.readThroughSequence, remainingUnreadCount: read.remainingUnreadCount, ...(read.earlierFactCount === undefined ? {} : { earlierFactCount: read.earlierFactCount }), ...(read.contextAdvice === undefined ? {} : { contextAdvice: adviceView(read.contextAdvice) }), ...taskNumberOf(read.task) });
|
|
315
322
|
},
|
|
316
323
|
});
|
|
317
324
|
/** One rendered fact line; markers are inline, never a separate ellipsis line. */
|
|
@@ -348,7 +355,7 @@ function adviceLines(advice) {
|
|
|
348
355
|
}
|
|
349
356
|
const teamMessage = markAgentTeamPreset(defineTool({
|
|
350
357
|
name: 'team_message',
|
|
351
|
-
description: 'Start a top-level Thread, reply to an existing Thread, or send a direct message (DM). Read the Thread first: a reply needs the current next-write token from a fully drained team_thread read (or your own last committed mutation), and unread work rejects before staleness is even checked. start defaults to a taskless Thread; pass asTask true to create a Task in the same send. A top-level start may mention related Agents directly; in replies, only a Human can invite
|
|
358
|
+
description: 'Start a top-level Thread, reply to an existing Thread, or send a direct message (DM). Read the Thread first: a reply needs the current next-write token from a fully drained team_thread read (or your own last committed mutation), and unread work rejects before staleness is even checked — and a mention only delivers its Message and restores Attention, never the Thread\'s earlier facts, so entering a Thread whose facts have left your context means reading back through it first. start defaults to a taskless Thread; pass asTask true to create a Task in the same send. A top-level start may mention related Agents directly; in replies, only a Human can invite a Member the Thread has never carried. Mention by writing `@Handle` in body — the `@` is required, matching ignores case, and each named Member is delivered to and renders as a mention chip; `@all` reaches every Member of the Channel. Naming a Member this Thread has never carried still commits, delivers nothing to that Member, and reports them under undeliveredMentions: ask the Human to invite them, or reach them with a dm. dm sends a private direct message to one enabled Agent Member in your Workspace: use it for quick clarifications and status syncs — never for task work, decisions, or anything that needs team visibility or traceability (use a Thread); if a DM exchange with the same Member exceeds about 3 exchanges, move it to a Thread, because every DM costs the recipient a full agent turn.',
|
|
352
359
|
parameters: {
|
|
353
360
|
action: { type: 'string', required: true, enum: ['start', 'reply', 'dm'] },
|
|
354
361
|
channelRef: { type: 'string', description: "Full branded Channel ref exactly as returned by Team tools, including the 'channel:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
|
|
@@ -356,8 +363,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
|
|
|
356
363
|
taskRef: { type: 'string', description: "Optional Task ref alias for reply on a Taskful Thread. Prefer threadRef; an unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
|
|
357
364
|
memberRef: { type: 'string', description: "Full branded Member ref exactly as returned by Team tools, including the 'member:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves. Required for dm; the Member must be an enabled Agent in your Workspace (the Human cannot be DMed)." },
|
|
358
365
|
asTask: { type: 'boolean', description: 'When true, start creates a Task with the Thread. Default false creates a taskless Thread.' },
|
|
359
|
-
body: { type: 'string', required: true, description: "Markdown body. Lead with the conclusion or state. Mention the Human only when they must know or decide
|
|
360
|
-
mentions: { type: 'array', items: { type: 'string' }, description: 'Member refs to mention. Mentioned Agents receive the Message directly; write their handles in the body (any casing, optional @) so the mention renders inline.' },
|
|
366
|
+
body: { type: 'string', required: true, description: "Markdown body. Lead with the conclusion or state. Mention the Human only when they must know or decide; when a decision is owed, say plainly what needs deciding and what happens by default if nobody answers — no fixed template. Keep it the shortest useful message for the recipients; mechanical detail follows below. Cite Team refs exactly as returned, as bare text with one colon (e.g. task:0f0a…) — never a double colon, never inside backticks or quotes. Unambiguous UUID abbreviations (first 6+ hex chars) also resolve. Mention a Member by writing `@Handle` (`@` required, case-insensitive) in the prose: that is what delivers the Message to them and renders the mention chip, and `@all` reaches the whole Channel." }, baseRevision: { type: 'number', description: "The next-write token from your latest fully drained team_thread read (or your own last committed mutation) on this Thread. Copy the explicitly rendered value verbatim; never increment, derive, compare, or cite it — it is an opaque concurrency token, not a fact about the Thread." },
|
|
361
367
|
attachments: { type: 'array', items: { type: 'string' }, description: 'Absolute file paths to share, e.g. screenshots or generated artifacts; images render as thumbnails for recipients. The Host validates each path and copies the file into the attachment cache, and members also receive one cached path per attachment; if any path fails validation the whole send is rejected.' },
|
|
362
368
|
},
|
|
363
369
|
output: {
|
|
@@ -365,6 +371,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
|
|
|
365
371
|
kind: { type: 'string', required: true }, action: { type: 'string' }, taskRef: { type: 'string' }, threadRef: { type: 'string' }, revision: { type: 'number' },
|
|
366
372
|
expectedRevision: { type: 'number' }, messageRef: { type: 'string' }, memberIds: { type: 'array', items: { type: 'string' } }, unreadCount: { type: 'number' }, directCount: { type: 'number' },
|
|
367
373
|
recipientMemberId: { type: 'string' }, recipientHandle: { type: 'string' }, delivered: { type: 'boolean' }, deliveryNote: { type: 'string' }, occurredAt: { type: 'string' },
|
|
374
|
+
undeliveredMentions: { type: 'array', items: { type: 'string' } },
|
|
368
375
|
} },
|
|
369
376
|
render: (_args, value) => {
|
|
370
377
|
if (value.kind === 'dm-sent') {
|
|
@@ -381,6 +388,9 @@ const teamMessage = markAgentTeamPreset(defineTool({
|
|
|
381
388
|
value.action === 'start' ? 'Committed — Thread created.' : 'Committed — reply added.',
|
|
382
389
|
[value.messageRef, value.threadRef, ...(value.taskRef === undefined ? [] : [value.taskRef])].join(' · '),
|
|
383
390
|
...(value.occurredAt === undefined ? [] : [`Committed at ${formatTeamTimestamp(value.occurredAt)}`]),
|
|
391
|
+
...(value.undeliveredMentions === undefined || value.undeliveredMentions.length === 0 ? [] : [
|
|
392
|
+
`Mention not delivered — ${value.undeliveredMentions.join(', ')} never took part in this Thread, so nothing reached them. Only a Human can invite a Member: reach them with a dm, or ask the Human.`,
|
|
393
|
+
]),
|
|
384
394
|
nextWriteLine(value.revision),
|
|
385
395
|
].join('\n') }];
|
|
386
396
|
}
|
|
@@ -400,7 +410,6 @@ const teamMessage = markAgentTeamPreset(defineTool({
|
|
|
400
410
|
throw new Error('team_message requires an Agent session');
|
|
401
411
|
const current = member(agent);
|
|
402
412
|
const host = service(agent);
|
|
403
|
-
const mentions = args.mentions;
|
|
404
413
|
const rawPaths = args.attachments;
|
|
405
414
|
const attachmentPaths = Array.isArray(rawPaths) ? rawPaths.filter((entry) => typeof entry === 'string' && entry.trim() !== '') : undefined;
|
|
406
415
|
const paths = attachmentPaths !== undefined && attachmentPaths.length > 0 ? { attachmentPaths } : {};
|
|
@@ -408,13 +417,13 @@ const teamMessage = markAgentTeamPreset(defineTool({
|
|
|
408
417
|
if (args.channelRef === undefined || args.taskRef !== undefined || args.threadRef !== undefined || args.baseRevision !== undefined)
|
|
409
418
|
throw new Error('start requires channelRef and does not accept threadRef, taskRef, or baseRevision');
|
|
410
419
|
const result = await host.sendMessageForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
|
|
411
|
-
channelRef: args.channelRef, body: args.body, asTask: args.asTask === true, ...
|
|
420
|
+
channelRef: args.channelRef, body: args.body, asTask: args.asTask === true, ...paths });
|
|
412
421
|
return messageOutcome(result, 'start');
|
|
413
422
|
}
|
|
414
423
|
if (args.action === 'dm') {
|
|
415
424
|
if (args.memberRef === undefined || args.channelRef !== undefined || args.threadRef !== undefined || args.taskRef !== undefined
|
|
416
|
-
|| args.baseRevision !== undefined || args.asTask !== undefined ||
|
|
417
|
-
throw new Error('dm requires memberRef and body only; it does not accept channelRef, threadRef, taskRef, baseRevision, asTask,
|
|
425
|
+
|| args.baseRevision !== undefined || args.asTask !== undefined || attachmentPaths !== undefined) {
|
|
426
|
+
throw new Error('dm requires memberRef and body only; it does not accept channelRef, threadRef, taskRef, baseRevision, asTask, or attachments');
|
|
418
427
|
}
|
|
419
428
|
try {
|
|
420
429
|
const result = await host.dmForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
|
|
@@ -435,16 +444,20 @@ const teamMessage = markAgentTeamPreset(defineTool({
|
|
|
435
444
|
const result = await host.replyForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
|
|
436
445
|
...(args.threadRef === undefined ? {} : { threadRef: args.threadRef }),
|
|
437
446
|
...(args.taskRef === undefined ? {} : { taskRef: args.taskRef }),
|
|
438
|
-
body: args.body, baseRevision,
|
|
439
|
-
...(mentions === undefined ? {} : { recipients: mentions }), ...paths });
|
|
447
|
+
body: args.body, baseRevision, ...paths });
|
|
440
448
|
return messageOutcome(result, 'reply');
|
|
441
449
|
},
|
|
442
450
|
}));
|
|
443
451
|
function messageOutcome(result, action) {
|
|
444
|
-
if (result.kind === 'committed')
|
|
452
|
+
if (result.kind === 'committed') {
|
|
453
|
+
// A start always delivers to the Members it names — they begin following the
|
|
454
|
+
// new Thread — so only a reply can report names the Thread has never carried.
|
|
455
|
+
const undelivered = 'undeliveredMentions' in result ? result.undeliveredMentions : undefined;
|
|
445
456
|
return { kind: result.kind, action, threadRef: result.thread.threadRef,
|
|
446
457
|
...(result.task === undefined ? {} : { taskRef: result.task.taskRef }),
|
|
447
|
-
revision: result.thread.revision, messageRef: result.message.messageRef, occurredAt: result.receipt.occurredAt
|
|
458
|
+
revision: result.thread.revision, messageRef: result.message.messageRef, occurredAt: result.receipt.occurredAt,
|
|
459
|
+
...(undelivered === undefined || undelivered.length === 0 ? {} : { undeliveredMentions: [...undelivered] }) };
|
|
460
|
+
}
|
|
448
461
|
if (result.kind === 'member_not_following')
|
|
449
462
|
return { kind: result.kind, memberIds: [...result.memberIds],
|
|
450
463
|
...(result.taskRef === undefined ? {} : { taskRef: result.taskRef }), ...(result.threadRef === undefined ? {} : { threadRef: result.threadRef, revision: result.revision }) };
|
|
@@ -604,7 +617,7 @@ const teamView = defineTool({
|
|
|
604
617
|
return {
|
|
605
618
|
channels: view.channels.map(channel => ({ channelRef: channel.channelRef, name: channel.name })),
|
|
606
619
|
members: [
|
|
607
|
-
{ memberId: view.humanMemberId, kind: 'human', handle:
|
|
620
|
+
{ memberId: view.humanMemberId, kind: 'human', handle: AGENT_TEAM_HUMAN_HANDLE, description: 'Human Team Member', presence: 'available' },
|
|
608
621
|
...host.members().filter(status => visibleMemberIds.has(status.member.memberId)).map(status => ({ memberId: status.member.memberId,
|
|
609
622
|
kind: 'agent', handle: status.member.handle, description: status.member.description, presence: status.presence })),
|
|
610
623
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAelD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAelD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;AAoqB/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAOxC"}
|
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Progress-visibility nudges: advisory Session notices that keep Member agents
|
|
3
|
-
* reporting progress into their Threads. Two regimes over one shared
|
|
4
|
-
* per-Member silent-tool-call counter:
|
|
5
|
-
*
|
|
6
|
-
* - Thread progress (A): a Member holding an active Claim, or following a
|
|
7
|
-
* taskless Thread, that has run many tool calls since its last committed
|
|
8
|
-
* public communication is reminded to post a brief update. The reminder
|
|
9
|
-
* ladder advances 20 → 40 → 60… per Member.
|
|
10
|
-
* - Claim suggestion (B): a Member following a still-`todo` Task it has never
|
|
11
|
-
* claimed is reminded — once per (Member, Thread) within the current Member
|
|
12
|
-
* Session — that team_claim exists.
|
|
13
|
-
*
|
|
14
|
-
* The Coordinator owns counting, thresholds, notice formatting, dedupe,
|
|
15
|
-
* in-flight revocation, and the deferred steer. It consumes only facts the
|
|
16
|
-
* Host already holds: live `tool/call`/`user/message` session events in their
|
|
17
|
-
* real `{type, seq, time, data}` envelope, the Session log for one-time
|
|
18
|
-
* recovery, committed ledger operations, and a ledger-owned eligibility
|
|
19
|
-
* projection (`progressNudgeTargets`). It never writes Team facts and never
|
|
20
|
-
* wakes idle agents on its own — a nudge rides the member's next tool call.
|
|
21
|
-
*
|
|
22
|
-
* @module @wowyuarm/dsh-agent-team/progress-nudge
|
|
23
|
-
*/
|
|
24
|
-
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
25
|
-
import { AGENT_TEAM_PLUGIN_ID, isCheckpointContinuationMessage } from "./context-source.js";
|
|
26
|
-
/** Notice summary for every nudge this Coordinator injects. */
|
|
27
|
-
export const PROGRESS_NUDGE_NOTICE_SUMMARY = 'Progress visibility reminder';
|
|
28
|
-
export const PROGRESS_NUDGE_TOOL_CALLS_START = 20;
|
|
29
|
-
export const PROGRESS_NUDGE_TOOL_CALLS_STEP = 20;
|
|
30
|
-
export const CLAIM_SUGGESTION_TOOL_CALLS = 5;
|
|
31
|
-
/** Stable line prefix marking Claim-suggestion targets inside a nudge notice; the only text this module ever parses back. */
|
|
32
|
-
const CLAIM_TARGET_LINE_PREFIX = '- Claim target: Task ';
|
|
33
|
-
const CLAIM_TARGET_LINE = /^- Claim target: Task (task:[0-9a-f-]+) — Thread (thread:[0-9a-f-]+)$/;
|
|
34
|
-
/** Ledger operation kinds that count as committed public communication and reset silence. */
|
|
35
|
-
export function isPublicCommunicationOperationKind(kind) {
|
|
36
|
-
return kind === 'team/message-sent' || kind === 'team/thread-replied'
|
|
37
|
-
|| kind === 'team/claim-created' || kind === 'team/claim-done' || kind === 'team/claim-released';
|
|
38
|
-
}
|
|
39
|
-
/** Whether one message is a nudge notice this module injected. */
|
|
40
|
-
export function isProgressNudgeNotice(message) {
|
|
41
|
-
const source = message.source;
|
|
42
|
-
return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID
|
|
43
|
-
&& source.form === 'notice' && source.summary === PROGRESS_NUDGE_NOTICE_SUMMARY;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Event-driven per-Member nudge state machine. All state is in-process and
|
|
47
|
-
* scoped to one Member Session; nothing is persisted. The Host feeds it live
|
|
48
|
-
* session events in their real envelope, committed operations, and lifecycle
|
|
49
|
-
* stop points.
|
|
50
|
-
*/
|
|
51
|
-
export class ProgressNudgeCoordinator {
|
|
52
|
-
members = new Map();
|
|
53
|
-
agentForMember;
|
|
54
|
-
targetsForMember;
|
|
55
|
-
sessionLogForMember;
|
|
56
|
-
log;
|
|
57
|
-
scheduleSteer;
|
|
58
|
-
progressThresholdStart;
|
|
59
|
-
progressThresholdStep;
|
|
60
|
-
claimSuggestionThreshold;
|
|
61
|
-
constructor(options) {
|
|
62
|
-
this.agentForMember = options.agentForMember;
|
|
63
|
-
this.targetsForMember = options.targetsForMember;
|
|
64
|
-
this.sessionLogForMember = options.sessionLogForMember;
|
|
65
|
-
this.log = options.log;
|
|
66
|
-
this.scheduleSteer = options.scheduleSteer ?? (run => { queueMicrotask(run); });
|
|
67
|
-
this.progressThresholdStart = options.progressThresholdStart ?? PROGRESS_NUDGE_TOOL_CALLS_START;
|
|
68
|
-
this.progressThresholdStep = options.progressThresholdStep ?? PROGRESS_NUDGE_TOOL_CALLS_STEP;
|
|
69
|
-
this.claimSuggestionThreshold = options.claimSuggestionThreshold ?? CLAIM_SUGGESTION_TOOL_CALLS;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* One live session event for a Member, in its real `{type, seq, time, data}`
|
|
73
|
-
* envelope. Only `tool/call` counts toward silence; a `user/message` whose
|
|
74
|
-
* source is exactly this module's own notice records that the model consumed
|
|
75
|
-
* the nudge (a Claim suggestion becomes final only then). The live `agent`
|
|
76
|
-
* is passed in by the caller because it exists at event time even before
|
|
77
|
-
* the Host finishes publishing the handle.
|
|
78
|
-
*/
|
|
79
|
-
onSessionEvent(memberId, sessionId, agent, event) {
|
|
80
|
-
if (event.type === 'user/message') {
|
|
81
|
-
if (!isProgressNudgeNotice(event.data))
|
|
82
|
-
return;
|
|
83
|
-
const state = this.members.get(memberId);
|
|
84
|
-
if (state === undefined)
|
|
85
|
-
return;
|
|
86
|
-
const notice = state.pending;
|
|
87
|
-
if (notice !== undefined && notice.messageId === event.data.id)
|
|
88
|
-
state.pending = undefined;
|
|
89
|
-
for (const threadRef of claimTargetThreadRefs(event.data))
|
|
90
|
-
state.claimSuggested.add(threadRef);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (event.type !== 'tool/call')
|
|
94
|
-
return;
|
|
95
|
-
let state = this.members.get(memberId);
|
|
96
|
-
if (state === undefined || state.sessionId !== sessionId) {
|
|
97
|
-
// First event of this Member Session (or a generation the Host did not
|
|
98
|
-
// stop explicitly): fresh tracking replaces whatever was there, and
|
|
99
|
-
// consumed one-time suggestions are recovered from the durable log so a
|
|
100
|
-
// Host restart or suspend/resume within the same Session cannot repeat
|
|
101
|
-
// them. A Human-initiated new Session has a different id and starts
|
|
102
|
-
// empty, exactly as specified.
|
|
103
|
-
this.dropState(memberId, state);
|
|
104
|
-
state = { sessionId, silentToolCalls: 0, nextProgressThreshold: this.progressThresholdStart,
|
|
105
|
-
claimSuggested: this.recoverClaimSuggestions(memberId, sessionId), };
|
|
106
|
-
this.members.set(memberId, state);
|
|
107
|
-
}
|
|
108
|
-
state.silentToolCalls += 1;
|
|
109
|
-
if (state.lastNudgeTurn === event.data.turn)
|
|
110
|
-
return;
|
|
111
|
-
this.maybeNudge(memberId, state, agent, event.data.turn);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* One ledger operation committed. A Member actor's public communication
|
|
115
|
-
* resets its silence; every commit also reconciles pending notices whose
|
|
116
|
-
* targets may have just disappeared (Task accepted, Channel archived, the
|
|
117
|
-
* Claim taken by someone else).
|
|
118
|
-
*/
|
|
119
|
-
onCommitted(operation) {
|
|
120
|
-
if (operation.actor.kind === 'member' && operation.actor.memberId !== undefined
|
|
121
|
-
&& isPublicCommunicationOperationKind(operation.kind)) {
|
|
122
|
-
const state = this.members.get(operation.actor.memberId);
|
|
123
|
-
if (state !== undefined) {
|
|
124
|
-
state.silentToolCalls = 0;
|
|
125
|
-
state.nextProgressThreshold = this.progressThresholdStart;
|
|
126
|
-
this.revokePending(operation.actor.memberId, state);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
this.reconcileAll();
|
|
130
|
-
}
|
|
131
|
-
/** Revoke one Member's queued-but-unconsumed nudge, e.g. when a higher-priority Team notice is injected. */
|
|
132
|
-
revokePendingNotice(memberId) {
|
|
133
|
-
const state = this.members.get(memberId);
|
|
134
|
-
if (state !== undefined)
|
|
135
|
-
this.revokePending(memberId, state);
|
|
136
|
-
}
|
|
137
|
-
/** Drop all tracking for one Member (suspend/archive/remove/renew/context-clear/steer failure). */
|
|
138
|
-
stopTracking(memberId) {
|
|
139
|
-
this.dropState(memberId, this.members.get(memberId));
|
|
140
|
-
this.members.delete(memberId);
|
|
141
|
-
}
|
|
142
|
-
/** Stop tracking every Member. */
|
|
143
|
-
dispose() {
|
|
144
|
-
for (const memberId of this.members.keys())
|
|
145
|
-
this.stopTracking(memberId);
|
|
146
|
-
}
|
|
147
|
-
/** Rebuild the consumed one-time suggestion set from this Session's durable log. */
|
|
148
|
-
recoverClaimSuggestions(memberId, sessionId) {
|
|
149
|
-
const suggested = new Set();
|
|
150
|
-
const log = this.sessionLogForMember(memberId, sessionId);
|
|
151
|
-
if (log === undefined)
|
|
152
|
-
return suggested;
|
|
153
|
-
for (const event of log.events) {
|
|
154
|
-
if (event.type !== 'user/message')
|
|
155
|
-
continue;
|
|
156
|
-
if (!isProgressNudgeNotice(event.data))
|
|
157
|
-
continue;
|
|
158
|
-
for (const threadRef of claimTargetThreadRefs(event.data))
|
|
159
|
-
suggested.add(threadRef);
|
|
160
|
-
}
|
|
161
|
-
return suggested;
|
|
162
|
-
}
|
|
163
|
-
dropState(memberId, state) {
|
|
164
|
-
if (state === undefined)
|
|
165
|
-
return;
|
|
166
|
-
this.revokePending(memberId, state);
|
|
167
|
-
this.members.delete(memberId);
|
|
168
|
-
}
|
|
169
|
-
revokePending(memberId, state) {
|
|
170
|
-
const notice = state.pending;
|
|
171
|
-
if (notice !== undefined) {
|
|
172
|
-
notice.canceled = true;
|
|
173
|
-
if (notice.steered) {
|
|
174
|
-
const agent = this.agentForMember(memberId);
|
|
175
|
-
const pending = agent === undefined ? undefined
|
|
176
|
-
: [...agent.inbox.nextStep, ...agent.inbox.nextTurn].find(message => message.id === notice.messageId);
|
|
177
|
-
// A just-consumed notice is simply gone; remove() returning false is expected.
|
|
178
|
-
if (pending !== undefined)
|
|
179
|
-
agent.inbox.remove(pending.id);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
state.pending = undefined;
|
|
183
|
-
}
|
|
184
|
-
/** Re-check every live Member's pending notice against the targets it actually listed. */
|
|
185
|
-
reconcileAll() {
|
|
186
|
-
for (const [memberId, state] of this.members) {
|
|
187
|
-
const notice = state.pending;
|
|
188
|
-
if (notice === undefined)
|
|
189
|
-
continue;
|
|
190
|
-
const agent = this.agentForMember(memberId);
|
|
191
|
-
if (agent === undefined) {
|
|
192
|
-
this.dropState(memberId, state);
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
const targets = this.targetsForMember(memberId);
|
|
196
|
-
// The notice is stale when ANY target it listed is no longer eligible:
|
|
197
|
-
// the body names threads whose work may be finished, so a partial
|
|
198
|
-
// survival must not keep the whole stale notice alive.
|
|
199
|
-
const progressAlive = notice.progressThreadRefs.length === 0
|
|
200
|
-
|| notice.progressThreadRefs.every(threadRef => targets.progress.some(target => target.threadRef === threadRef));
|
|
201
|
-
const claimAlive = notice.claimThreadRefs.length === 0
|
|
202
|
-
|| notice.claimThreadRefs.every(threadRef => targets.claim.some(target => target.threadRef === threadRef));
|
|
203
|
-
if (!progressAlive || !claimAlive)
|
|
204
|
-
this.revokePending(memberId, state);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
maybeNudge(memberId, state, agent, turn) {
|
|
208
|
-
const targets = this.targetsForMember(memberId);
|
|
209
|
-
const progressDue = state.silentToolCalls >= state.nextProgressThreshold && targets.progress.length > 0;
|
|
210
|
-
const freshClaimTargets = targets.claim
|
|
211
|
-
.filter(target => !state.claimSuggested.has(target.threadRef) && state.pending?.claimThreadRefs.includes(target.threadRef) !== true);
|
|
212
|
-
const claimDue = state.silentToolCalls >= this.claimSuggestionThreshold && freshClaimTargets.length > 0;
|
|
213
|
-
if (!progressDue && !claimDue)
|
|
214
|
-
return;
|
|
215
|
-
if (this.hasBlockingNotice(agent))
|
|
216
|
-
return;
|
|
217
|
-
const progressTargets = progressDue ? targets.progress : [];
|
|
218
|
-
const claimTargets = claimDue ? freshClaimTargets : [];
|
|
219
|
-
const notice = createUserMessage({
|
|
220
|
-
content: [{ type: 'text', text: nudgeNoticeText(state.silentToolCalls, progressTargets, claimTargets) }],
|
|
221
|
-
source: { kind: 'plugin', plugin: AGENT_TEAM_PLUGIN_ID, form: 'notice', summary: PROGRESS_NUDGE_NOTICE_SUMMARY },
|
|
222
|
-
});
|
|
223
|
-
const pending = {
|
|
224
|
-
messageId: notice.id,
|
|
225
|
-
progressThreadRefs: progressTargets.map(target => target.threadRef),
|
|
226
|
-
claimThreadRefs: claimTargets.map(target => target.threadRef),
|
|
227
|
-
steered: false,
|
|
228
|
-
canceled: false,
|
|
229
|
-
};
|
|
230
|
-
// Record intent first: the scheduled steer, its cancellation check, and
|
|
231
|
-
// its failure handling all live on this single PendingNotice object, so a
|
|
232
|
-
// revoke between queueing and the microtask leaves no orphan injection.
|
|
233
|
-
// lastNudgeTurn stays as the same-turn intent guard, but the A threshold
|
|
234
|
-
// only commits after the real steer succeeds — a canceled or failed
|
|
235
|
-
// schedule leaves the rung due so the next tool call retries it.
|
|
236
|
-
state.pending = pending;
|
|
237
|
-
state.lastNudgeTurn = turn;
|
|
238
|
-
this.scheduleSteer(() => {
|
|
239
|
-
if (pending.canceled)
|
|
240
|
-
return;
|
|
241
|
-
try {
|
|
242
|
-
agent.steer(notice);
|
|
243
|
-
}
|
|
244
|
-
catch (error) {
|
|
245
|
-
this.log?.(`progress nudge steer failed for member '${memberId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
246
|
-
pending.canceled = true;
|
|
247
|
-
if (state.pending === pending)
|
|
248
|
-
state.pending = undefined;
|
|
249
|
-
this.stopTracking(memberId);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
pending.steered = true;
|
|
253
|
-
if (pending.progressThreadRefs.length > 0) {
|
|
254
|
-
// Advance the ladder past the count at real success in one move: a
|
|
255
|
-
// long silence held back by higher-priority notices must not replay
|
|
256
|
-
// every skipped rung on successive tool calls after the blocker
|
|
257
|
-
// clears.
|
|
258
|
-
while (state.nextProgressThreshold <= state.silentToolCalls)
|
|
259
|
-
state.nextProgressThreshold += this.progressThresholdStep;
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Recovery, Inbox, and pre-compaction notices outrank a progress nudge. If
|
|
265
|
-
* one is already pending, this nudge stays due and retries on the next tool
|
|
266
|
-
* call; a DM relay is not a notice and never blocks.
|
|
267
|
-
*/
|
|
268
|
-
hasBlockingNotice(agent) {
|
|
269
|
-
for (const message of [...agent.inbox.nextStep, ...agent.inbox.nextTurn]) {
|
|
270
|
-
const source = message.source;
|
|
271
|
-
if (source.kind !== 'plugin' || source.plugin !== AGENT_TEAM_PLUGIN_ID)
|
|
272
|
-
continue;
|
|
273
|
-
// A queued checkpoint continuation is a pending wake that outranks a
|
|
274
|
-
// nudge exactly as the notice families above do. It rides the snapshot
|
|
275
|
-
// form (it must carry its checkpoint ref in a section), so it cannot be
|
|
276
|
-
// recognized by the notice summary check below.
|
|
277
|
-
if (isCheckpointContinuationMessage(message))
|
|
278
|
-
return true;
|
|
279
|
-
if (source.form !== 'notice')
|
|
280
|
-
continue;
|
|
281
|
-
if (source.summary !== PROGRESS_NUDGE_NOTICE_SUMMARY)
|
|
282
|
-
return true;
|
|
283
|
-
}
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/** Extract the threadRefs this module itself wrote as Claim targets in one notice. */
|
|
288
|
-
function claimTargetThreadRefs(message) {
|
|
289
|
-
const refs = [];
|
|
290
|
-
for (const block of message.content) {
|
|
291
|
-
if (block.type !== 'text')
|
|
292
|
-
continue;
|
|
293
|
-
for (const line of block.text.split('\n')) {
|
|
294
|
-
const match = CLAIM_TARGET_LINE.exec(line);
|
|
295
|
-
if (match !== null)
|
|
296
|
-
refs.push(match[2]);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return refs;
|
|
300
|
-
}
|
|
301
|
-
function nudgeNoticeText(silentToolCalls, progress, claim) {
|
|
302
|
-
const sections = [];
|
|
303
|
-
if (progress.length > 0) {
|
|
304
|
-
sections.push([
|
|
305
|
-
'Progress visibility reminder',
|
|
306
|
-
'',
|
|
307
|
-
`You have made ${silentToolCalls} tool calls since your last visible Team update. Please briefly update the relevant Thread(s): what you confirmed, what remains, and any blocker. Read the Thread first if needed, then continue working.`,
|
|
308
|
-
'',
|
|
309
|
-
...progress.map(target => target.reason === 'active-claim'
|
|
310
|
-
? `- Task ${target.taskRef} — Thread ${target.threadRef}`
|
|
311
|
-
: `- Taskless Thread ${target.threadRef} (reply only if your current work relates to it)`),
|
|
312
|
-
].join('\n'));
|
|
313
|
-
}
|
|
314
|
-
if (claim.length > 0) {
|
|
315
|
-
sections.push([
|
|
316
|
-
'Claim visibility reminder',
|
|
317
|
-
'',
|
|
318
|
-
'You have been working while following the Task(s) below, but you have never claimed a direction there.',
|
|
319
|
-
'',
|
|
320
|
-
...claim.map(target => `${CLAIM_TARGET_LINE_PREFIX}${target.taskRef} — Thread ${target.threadRef}`),
|
|
321
|
-
'',
|
|
322
|
-
'If your current work belongs to one of these Tasks, briefly state your direction in its Thread and consider team_claim. If it does not, no action is required. This is advisory, not a claim requirement.',
|
|
323
|
-
].join('\n'));
|
|
324
|
-
}
|
|
325
|
-
if (progress.length > 0)
|
|
326
|
-
sections.push('This is advisory; do not stop useful work merely to produce a long status report.');
|
|
327
|
-
return sections.join('\n\n');
|
|
328
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Progress-visibility nudges: advisory Session notices that keep Member agents
|
|
3
|
-
* reporting progress into their Threads. Two regimes over one shared
|
|
4
|
-
* per-Member silent-tool-call counter:
|
|
5
|
-
*
|
|
6
|
-
* - Thread progress (A): a Member holding an active Claim, or following a
|
|
7
|
-
* taskless Thread, that has run many tool calls since its last committed
|
|
8
|
-
* public communication is reminded to post a brief update. The reminder
|
|
9
|
-
* ladder advances 20 → 40 → 60… per Member.
|
|
10
|
-
* - Claim suggestion (B): a Member following a still-`todo` Task it has never
|
|
11
|
-
* claimed is reminded — once per (Member, Thread) within the current Member
|
|
12
|
-
* Session — that team_claim exists.
|
|
13
|
-
*
|
|
14
|
-
* The Coordinator owns counting, thresholds, notice formatting, dedupe,
|
|
15
|
-
* in-flight revocation, and the deferred steer. It consumes only facts the
|
|
16
|
-
* Host already holds: live `tool/call`/`user/message` session events in their
|
|
17
|
-
* real `{type, seq, time, data}` envelope, the Session log for one-time
|
|
18
|
-
* recovery, committed ledger operations, and a ledger-owned eligibility
|
|
19
|
-
* projection (`progressNudgeTargets`). It never writes Team facts and never
|
|
20
|
-
* wakes idle agents on its own — a nudge rides the member's next tool call.
|
|
21
|
-
*
|
|
22
|
-
* @module @wowyuarm/dsh-agent-team/progress-nudge
|
|
23
|
-
*/
|
|
24
|
-
import { type UserMessage } from '@deepseek-ai/dsh-llm';
|
|
25
|
-
import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session';
|
|
26
|
-
import type { AgentTeamMemberId, AgentTeamProgressNudgeTargets } from './types.ts';
|
|
27
|
-
/** Notice summary for every nudge this Coordinator injects. */
|
|
28
|
-
export declare const PROGRESS_NUDGE_NOTICE_SUMMARY = "Progress visibility reminder";
|
|
29
|
-
export declare const PROGRESS_NUDGE_TOOL_CALLS_START = 20;
|
|
30
|
-
export declare const PROGRESS_NUDGE_TOOL_CALLS_STEP = 20;
|
|
31
|
-
export declare const CLAIM_SUGGESTION_TOOL_CALLS = 5;
|
|
32
|
-
/** Minimal Agent surface the Coordinator depends on; real Agents satisfy it, tests fake it. */
|
|
33
|
-
export interface ProgressNudgeAgent {
|
|
34
|
-
readonly inbox: {
|
|
35
|
-
readonly nextStep: readonly UserMessage[];
|
|
36
|
-
readonly nextTurn: readonly UserMessage[];
|
|
37
|
-
remove(messageId: UserMessage['id']): boolean;
|
|
38
|
-
};
|
|
39
|
-
steer(message: UserMessage): void;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Read-only view of one Session log used to recover consumed one-time Claim
|
|
43
|
-
* suggestions when a Member Session's tracking is (re)established.
|
|
44
|
-
*/
|
|
45
|
-
export interface ProgressNudgeSessionLog {
|
|
46
|
-
/** Durable events in sequence order; the real `Session.ownEvents()`. */
|
|
47
|
-
readonly events: readonly SessionEvent[];
|
|
48
|
-
}
|
|
49
|
-
/** Minimal operation fact the Coordinator consumes; the ledger's full record satisfies it structurally. */
|
|
50
|
-
export interface ProgressNudgeOperation {
|
|
51
|
-
readonly actor: {
|
|
52
|
-
readonly kind: string;
|
|
53
|
-
readonly memberId?: AgentTeamMemberId | undefined;
|
|
54
|
-
};
|
|
55
|
-
readonly kind: string;
|
|
56
|
-
}
|
|
57
|
-
export interface ProgressNudgeCoordinatorOptions {
|
|
58
|
-
/** Live Agent lookup for revocation and injection. */
|
|
59
|
-
readonly agentForMember: (memberId: AgentTeamMemberId) => ProgressNudgeAgent | undefined;
|
|
60
|
-
/** Current eligibility projection from the ledger. */
|
|
61
|
-
readonly targetsForMember: (memberId: AgentTeamMemberId) => AgentTeamProgressNudgeTargets;
|
|
62
|
-
/** Durable Session log lookup for one-time recovery on (re)activation. */
|
|
63
|
-
readonly sessionLogForMember: (memberId: AgentTeamMemberId, sessionId: SessionId) => ProgressNudgeSessionLog | undefined;
|
|
64
|
-
/** Log one line when steer fails; the Host wires its logger. */
|
|
65
|
-
readonly log?: (message: string) => void;
|
|
66
|
-
/**
|
|
67
|
-
* Schedule the actual steer past an in-flight session append publication.
|
|
68
|
-
* The default defers one microtask; tests may substitute a synchronous or
|
|
69
|
-
* manually triggered scheduler. The callback runs the real steer.
|
|
70
|
-
*/
|
|
71
|
-
readonly scheduleSteer?: (run: () => void) => void;
|
|
72
|
-
/** Initial ladder start; tests override to keep runs small. */
|
|
73
|
-
readonly progressThresholdStart?: number;
|
|
74
|
-
/** Ladder step; tests override to keep runs small. */
|
|
75
|
-
readonly progressThresholdStep?: number;
|
|
76
|
-
/** Claim-suggestion threshold; tests override to keep runs small. */
|
|
77
|
-
readonly claimSuggestionThreshold?: number;
|
|
78
|
-
}
|
|
79
|
-
/** Ledger operation kinds that count as committed public communication and reset silence. */
|
|
80
|
-
export declare function isPublicCommunicationOperationKind(kind: string): boolean;
|
|
81
|
-
/** Whether one message is a nudge notice this module injected. */
|
|
82
|
-
export declare function isProgressNudgeNotice(message: UserMessage): boolean;
|
|
83
|
-
/**
|
|
84
|
-
* Event-driven per-Member nudge state machine. All state is in-process and
|
|
85
|
-
* scoped to one Member Session; nothing is persisted. The Host feeds it live
|
|
86
|
-
* session events in their real envelope, committed operations, and lifecycle
|
|
87
|
-
* stop points.
|
|
88
|
-
*/
|
|
89
|
-
export declare class ProgressNudgeCoordinator {
|
|
90
|
-
private readonly members;
|
|
91
|
-
private readonly agentForMember;
|
|
92
|
-
private readonly targetsForMember;
|
|
93
|
-
private readonly sessionLogForMember;
|
|
94
|
-
private readonly log;
|
|
95
|
-
private readonly scheduleSteer;
|
|
96
|
-
private readonly progressThresholdStart;
|
|
97
|
-
private readonly progressThresholdStep;
|
|
98
|
-
private readonly claimSuggestionThreshold;
|
|
99
|
-
constructor(options: ProgressNudgeCoordinatorOptions);
|
|
100
|
-
/**
|
|
101
|
-
* One live session event for a Member, in its real `{type, seq, time, data}`
|
|
102
|
-
* envelope. Only `tool/call` counts toward silence; a `user/message` whose
|
|
103
|
-
* source is exactly this module's own notice records that the model consumed
|
|
104
|
-
* the nudge (a Claim suggestion becomes final only then). The live `agent`
|
|
105
|
-
* is passed in by the caller because it exists at event time even before
|
|
106
|
-
* the Host finishes publishing the handle.
|
|
107
|
-
*/
|
|
108
|
-
onSessionEvent(memberId: AgentTeamMemberId, sessionId: SessionId, agent: ProgressNudgeAgent, event: SessionEvent): void;
|
|
109
|
-
/**
|
|
110
|
-
* One ledger operation committed. A Member actor's public communication
|
|
111
|
-
* resets its silence; every commit also reconciles pending notices whose
|
|
112
|
-
* targets may have just disappeared (Task accepted, Channel archived, the
|
|
113
|
-
* Claim taken by someone else).
|
|
114
|
-
*/
|
|
115
|
-
onCommitted(operation: ProgressNudgeOperation): void;
|
|
116
|
-
/** Revoke one Member's queued-but-unconsumed nudge, e.g. when a higher-priority Team notice is injected. */
|
|
117
|
-
revokePendingNotice(memberId: AgentTeamMemberId): void;
|
|
118
|
-
/** Drop all tracking for one Member (suspend/archive/remove/renew/context-clear/steer failure). */
|
|
119
|
-
stopTracking(memberId: AgentTeamMemberId): void;
|
|
120
|
-
/** Stop tracking every Member. */
|
|
121
|
-
dispose(): void;
|
|
122
|
-
/** Rebuild the consumed one-time suggestion set from this Session's durable log. */
|
|
123
|
-
private recoverClaimSuggestions;
|
|
124
|
-
private dropState;
|
|
125
|
-
private revokePending;
|
|
126
|
-
/** Re-check every live Member's pending notice against the targets it actually listed. */
|
|
127
|
-
private reconcileAll;
|
|
128
|
-
private maybeNudge;
|
|
129
|
-
/**
|
|
130
|
-
* Recovery, Inbox, and pre-compaction notices outrank a progress nudge. If
|
|
131
|
-
* one is already pending, this nudge stays due and retries on the next tool
|
|
132
|
-
* call; a DM relay is not a notice and never blocks.
|
|
133
|
-
*/
|
|
134
|
-
private hasBlockingNotice;
|
|
135
|
-
}
|
|
136
|
-
//# sourceMappingURL=progress-nudge.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"progress-nudge.d.ts","sourceRoot":"","sources":["../../src/progress-nudge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,6BAA6B,EAAsB,MAAM,YAAY,CAAA;AAGtG,+DAA+D;AAC/D,eAAO,MAAM,6BAA6B,iCAAiC,CAAA;AAE3E,eAAO,MAAM,+BAA+B,KAAK,CAAA;AACjD,eAAO,MAAM,8BAA8B,KAAK,CAAA;AAChD,eAAO,MAAM,2BAA2B,IAAI,CAAA;AAK5C,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAA;QACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAA;QACzC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,OAAO,CAAA;KAC9C,CAAA;IACD,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;CACzC;AAED,2GAA2G;AAC3G,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAA;KAAE,CAAA;IAC5F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,+BAA+B;IAC9C,sDAAsD;IACtD,QAAQ,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,kBAAkB,GAAG,SAAS,CAAA;IACxF,sDAAsD;IACtD,QAAQ,CAAC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,6BAA6B,CAAA;IACzF,0EAA0E;IAC1E,QAAQ,CAAC,mBAAmB,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,KAAK,uBAAuB,GAAG,SAAS,CAAA;IACxH,gEAAgE;IAChE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;IAClD,+DAA+D;IAC/D,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAA;IACxC,sDAAsD;IACtD,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IACvC,qEAAqE;IACrE,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAA;CAC3C;AA2BD,6FAA6F;AAC7F,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGxE;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAInE;AAED;;;;;GAKG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IACzE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmD;IAClF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqD;IACtF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAwD;IAC5F,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAyC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IACzD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAQ;IAC/C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAQ;gBAErC,OAAO,EAAE,+BAA+B;IAWpD;;;;;;;OAOG;IACH,cAAc,CAAC,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IA6BvH;;;;;OAKG;IACH,WAAW,CAAC,SAAS,EAAE,sBAAsB,GAAG,IAAI;IAapD,4GAA4G;IAC5G,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAKtD,mGAAmG;IACnG,YAAY,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAK/C,kCAAkC;IAClC,OAAO,IAAI,IAAI;IAIf,oFAAoF;IACpF,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,aAAa;IAerB,0FAA0F;IAC1F,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,UAAU;IAmDlB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAc1B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TeamSettings.d.ts","sourceRoot":"","sources":["../../../src/client/TeamSettings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAGnD,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,iBAAiB,+BAE5E"}
|