@wowyuarm/dsh-agent-team 0.1.2 → 0.1.3

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.
Files changed (67) hide show
  1. package/README.md +1 -0
  2. package/README.zh.md +2 -0
  3. package/package.json +12 -3
  4. package/packages/agent-team/README.md +1 -1
  5. package/packages/agent-team/README.zh.md +1 -1
  6. package/packages/agent-team/lib/attachments.js +11 -12
  7. package/packages/agent-team/lib/auto-compaction.js +163 -0
  8. package/packages/agent-team/lib/index.js +214 -130
  9. package/packages/agent-team/lib/ledger.js +77 -70
  10. package/packages/agent-team/lib/recovery.js +30 -35
  11. package/packages/agent-team/lib/typert.host.js +33 -23
  12. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  13. package/packages/agent-team/lib/typert.remote-client.js +21 -21
  14. package/packages/agent-team/lib/types/attachments.d.ts +2 -2
  15. package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
  16. package/packages/agent-team/lib/types/auto-compaction.d.ts +38 -0
  17. package/packages/agent-team/lib/types/auto-compaction.d.ts.map +1 -0
  18. package/packages/agent-team/lib/types/index.d.ts +40 -12
  19. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  20. package/packages/agent-team/lib/types/ledger.d.ts +13 -0
  21. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  22. package/packages/agent-team/lib/types/recovery.d.ts +15 -16
  23. package/packages/agent-team/lib/types/recovery.d.ts.map +1 -1
  24. package/packages/agent-team/preset/team-member/agent.cordis.yml +6 -1
  25. package/packages/client-agent-team/README.md +1 -1
  26. package/packages/client-agent-team/README.zh.md +1 -1
  27. package/packages/client-agent-team/lib/client.js +942 -534
  28. package/packages/client-agent-team/lib/client.js.map +1 -1
  29. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  30. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +5 -166
  31. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  32. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +6 -20
  33. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  34. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +3 -2
  35. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  36. package/packages/client-agent-team/lib/types/client/TeamComposer.js +0 -1
  37. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts +34 -0
  38. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -0
  39. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +169 -0
  40. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts +17 -0
  41. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.d.ts.map +1 -0
  42. package/packages/client-agent-team/lib/types/client/TeamMemberSessionComposer.js +120 -0
  43. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  44. package/packages/client-agent-team/lib/types/client/TeamMessage.js +83 -43
  45. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  46. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +10 -23
  47. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  48. package/packages/client-agent-team/lib/types/client/index.js +71 -1
  49. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +22 -0
  50. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +1 -0
  51. package/packages/client-agent-team/lib/types/client/member-session-input.js +98 -0
  52. package/packages/client-agent-team/lib/types/client/requests.d.ts +16 -0
  53. package/packages/client-agent-team/lib/types/client/requests.d.ts.map +1 -0
  54. package/packages/client-agent-team/lib/types/client/requests.js +22 -0
  55. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  56. package/packages/client-agent-team/lib/types/client/task-refs.d.ts +6 -1
  57. package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/task-refs.js +19 -0
  59. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +43 -3
  60. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  61. package/packages/client-agent-team/lib/types/client/team-formatters.js +61 -4
  62. package/packages/client-agent-team/lib/types/client/team-membership.d.ts.map +1 -1
  63. package/packages/client-agent-team/lib/types/client/team-membership.js +2 -1
  64. package/packages/tool-agent-team/lib/index.js +1 -1
  65. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts +0 -13
  66. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.d.ts.map +0 -1
  67. package/packages/client-agent-team/lib/types/client/TeamInboxPanel.js +0 -90
@@ -19,6 +19,10 @@ function emptyProjection() {
19
19
  orderedFacts: [], factsByThread: new Map(), topLevelMessages: [], mentionsByMessage: new Map(), messageCountByThread: new Map(),
20
20
  attentionByThread: new Map() };
21
21
  }
22
+ /** Exhaustiveness guard for the closed operation union: adding a kind must update every dispatch. */
23
+ function assertUnhandledKind(operation) {
24
+ throw new Error(`agent-team ledger does not handle operation kind '${operation.kind}'`);
25
+ }
22
26
  /** Replay and append logic behind the Agent Team service interface. */
23
27
  export class AgentTeamLedger {
24
28
  table;
@@ -310,19 +314,14 @@ export class AgentTeamLedger {
310
314
  return this.resolved(this.replyResult(existing));
311
315
  }
312
316
  const actor = this.assertActorForWorkspace(request.actor, request.workspaceId);
313
- const task = this.requireTask(request.workspaceId, request.taskRef);
314
- const thread = this.requireThread(task.threadRef);
315
- if (actor.kind === 'member')
316
- this.requireMemberChannel(this.requireMember(actor.memberId), task.channelRef);
317
+ const { task, thread } = this.threadForActor(actor, request.workspaceId, request.taskRef);
317
318
  const body = request.body.trim();
318
319
  if (body === '')
319
320
  throw new Error('message body must not be empty');
320
321
  this.assertMentionTargets(this.requireChannel(request.workspaceId, task.channelRef), recipients);
321
- const unread = this.unreadFor(actor.memberId, thread.threadRef);
322
- if (unread.length > 0)
323
- return this.resolved(this.unreadRequired(task, thread, unread));
324
- if (request.baseRevision !== thread.revision)
325
- return this.resolved(this.staleRevision(task, thread, request.baseRevision));
322
+ const deferred = this.deferredThreadWrite(actor.memberId, task, thread, request.baseRevision);
323
+ if (deferred !== undefined)
324
+ return this.resolved(deferred);
326
325
  if (task.resolution === 'closed')
327
326
  throw new Error(`Task '${task.taskRef}' is closed; reopen it before replying`);
328
327
  const unfollowedAgents = recipients.filter(memberId => this.state.members.has(memberId) && !this.isFollowing(thread.threadRef, memberId));
@@ -364,15 +363,10 @@ export class AgentTeamLedger {
364
363
  return this.resolved(this.claimResult(existing));
365
364
  }
366
365
  const actor = this.assertActorForWorkspace(request.actor, request.workspaceId);
367
- const task = this.requireTask(request.workspaceId, request.taskRef);
368
- const thread = this.requireThread(task.threadRef);
369
- if (actor.kind === 'member')
370
- this.requireMemberChannel(this.requireMember(actor.memberId), task.channelRef);
371
- const unread = this.unreadFor(actor.memberId, thread.threadRef);
372
- if (unread.length > 0)
373
- return this.resolved(this.unreadRequired(task, thread, unread));
374
- if (request.baseRevision !== thread.revision)
375
- return this.resolved(this.staleRevision(task, thread, request.baseRevision));
366
+ const { task, thread } = this.threadForActor(actor, request.workspaceId, request.taskRef);
367
+ const deferred = this.deferredThreadWrite(actor.memberId, task, thread, request.baseRevision);
368
+ if (deferred !== undefined)
369
+ return this.resolved(deferred);
376
370
  if (task.resolution !== 'open')
377
371
  throw new Error(`Task '${task.taskRef}' is ${task.status}; reopen it before changing Claims`);
378
372
  if (actor.kind !== 'member')
@@ -441,13 +435,10 @@ export class AgentTeamLedger {
441
435
  return this.resolved(this.taskResult(existing));
442
436
  }
443
437
  this.assertHumanActor(request.actor);
444
- const task = this.requireTask(request.workspaceId, request.taskRef);
445
- const thread = this.requireThread(task.threadRef);
446
- const unread = this.unreadFor(request.actor.memberId, thread.threadRef);
447
- if (unread.length > 0)
448
- return this.resolved(this.unreadRequired(task, thread, unread));
449
- if (request.baseRevision !== thread.revision)
450
- return this.resolved(this.staleRevision(task, thread, request.baseRevision));
438
+ const { task, thread } = this.threadForActor(request.actor, request.workspaceId, request.taskRef);
439
+ const deferred = this.deferredThreadWrite(request.actor.memberId, task, thread, request.baseRevision);
440
+ if (deferred !== undefined)
441
+ return this.resolved(deferred);
451
442
  if (request.action === 'accept' && task.resolution !== 'open')
452
443
  throw new Error(`Task '${task.taskRef}' is already ${task.resolution}`);
453
444
  if (request.action === 'close' && task.resolution === 'closed')
@@ -535,10 +526,7 @@ export class AgentTeamLedger {
535
526
  return this.resolved(this.attentionResult(existing));
536
527
  }
537
528
  const actor = this.assertActorForWorkspace(request.actor, request.workspaceId);
538
- const task = this.requireTask(request.workspaceId, request.taskRef);
539
- const thread = this.requireThread(task.threadRef);
540
- if (actor.kind === 'member')
541
- this.requireMemberChannel(this.requireMember(actor.memberId), task.channelRef);
529
+ const { task, thread } = this.threadForActor(actor, request.workspaceId, request.taskRef);
542
530
  const current = this.attentionFor(actor.memberId, thread.threadRef);
543
531
  if (request.action === 'follow') {
544
532
  if (task.resolution === 'closed')
@@ -571,10 +559,7 @@ export class AgentTeamLedger {
571
559
  }
572
560
  attentionStatus(actor, request) {
573
561
  const authorized = this.assertActorForWorkspace(actor, request.workspaceId);
574
- const task = this.requireTask(request.workspaceId, request.taskRef);
575
- if (authorized.kind === 'member')
576
- this.requireMemberChannel(this.requireMember(authorized.memberId), task.channelRef);
577
- const thread = this.requireThread(task.threadRef);
562
+ const { task, thread } = this.threadForActor(authorized, request.workspaceId, request.taskRef);
578
563
  const attention = this.attentionFor(authorized.memberId, thread.threadRef);
579
564
  return attention === undefined
580
565
  ? Object.freeze({ task, thread })
@@ -675,22 +660,9 @@ export class AgentTeamLedger {
675
660
  }
676
661
  return Object.freeze({ items: Object.freeze(observations.slice(-limit)) });
677
662
  }
663
+ /** Every operation carrying an inbox delta drives the Inbox projection; the payload shape decides, not a per-kind list. */
678
664
  attentionDelta(operation) {
679
- switch (operation.kind) {
680
- case 'team/channel-member-removed':
681
- case 'team/message-sent':
682
- case 'team/thread-replied':
683
- case 'team/claim-created':
684
- case 'team/claim-done':
685
- case 'team/claim-released':
686
- case 'team/task-changed':
687
- case 'team/thread-attention-changed':
688
- case 'team/thread-read':
689
- case 'team/member-removed':
690
- return operation.data.inbox;
691
- default:
692
- return undefined;
693
- }
665
+ return 'inbox' in operation.data ? operation.data.inbox : undefined;
694
666
  }
695
667
  /** Attachment ids referenced by any stored Message — the GC's keep-set oracle. */
696
668
  referencedAttachmentIds() {
@@ -705,10 +677,7 @@ export class AgentTeamLedger {
705
677
  }
706
678
  threadHistory(actor, request) {
707
679
  const authorized = this.assertActorForWorkspace(actor, request.workspaceId);
708
- const task = this.requireTask(request.workspaceId, request.taskRef);
709
- if (authorized.kind === 'member')
710
- this.requireMemberChannel(this.requireMember(authorized.memberId), task.channelRef);
711
- const thread = this.requireThread(task.threadRef);
680
+ const { task, thread } = this.threadForActor(authorized, request.workspaceId, request.taskRef);
712
681
  const limit = request.limit ?? 20;
713
682
  if (!Number.isInteger(limit) || limit < 1 || limit > 100)
714
683
  throw new Error('history limit must be an integer between 1 and 100');
@@ -724,10 +693,8 @@ export class AgentTeamLedger {
724
693
  }
725
694
  listClaims(actor, request) {
726
695
  const authorized = this.assertActorForWorkspace(actor, request.workspaceId);
727
- const task = this.requireTask(request.workspaceId, request.taskRef);
728
- if (authorized.kind === 'member')
729
- this.requireMemberChannel(this.requireMember(authorized.memberId), task.channelRef);
730
- return Object.freeze({ task, thread: this.requireThread(task.threadRef), claims: this.claimsForTask(task.taskRef) });
696
+ const { task, thread } = this.threadForActor(authorized, request.workspaceId, request.taskRef);
697
+ return Object.freeze({ task, thread, claims: this.claimsForTask(task.taskRef) });
731
698
  }
732
699
  getTask(taskRef) {
733
700
  return this.state.tasks.get(taskRef);
@@ -796,7 +763,7 @@ export class AgentTeamLedger {
796
763
  const visibleTasks = [...this.state.tasks.values()].filter(task => channelRefs.has(task.channelRef)
797
764
  && (request.channelRef === undefined || task.channelRef === request.channelRef)
798
765
  && (request.threadRef === undefined || task.threadRef === request.threadRef));
799
- const taskNumbers = this.taskNumbers(request.workspaceId, request.channelRef);
766
+ const taskNumbers = this.taskNumbers(request.workspaceId);
800
767
  const items = selected.filter((fact) => fact.kind === 'message').map(fact => {
801
768
  const message = fact.message;
802
769
  const task = this.requireTask(request.workspaceId, message.taskRef);
@@ -883,6 +850,8 @@ export class AgentTeamLedger {
883
850
  // A read advances only the reader's private watermark; no projection
884
851
  // visible to other participants changes, so nobody is woken.
885
852
  return [];
853
+ default:
854
+ return assertUnhandledKind(operation);
886
855
  }
887
856
  }
888
857
  /** Members whose Inbox projection may have changed; the Host notifies only live ones. */
@@ -925,8 +894,19 @@ export class AgentTeamLedger {
925
894
  case 'team/channel-member-removed':
926
895
  case 'team/member-removed':
927
896
  return operation.data.activities.map(activity => activity.threadRef);
928
- default:
897
+ case 'team/initialized':
898
+ case 'team/channel-created':
899
+ case 'team/channel-updated':
900
+ case 'team/member-added':
901
+ case 'team/member-suspended':
902
+ case 'team/member-resumed':
903
+ case 'team/member-session-restarted':
904
+ case 'team/member-updated':
905
+ case 'team/channel-member-added':
906
+ case 'team/thread-read':
929
907
  return [];
908
+ default:
909
+ return assertUnhandledKind(operation);
930
910
  }
931
911
  }
932
912
  replay() {
@@ -1243,6 +1223,7 @@ export class AgentTeamLedger {
1243
1223
  this.validateInboxDelta(operation.data.inbox, projection, refs, [], [], [activity]);
1244
1224
  return;
1245
1225
  }
1226
+ assertUnhandledKind(operation);
1246
1227
  }
1247
1228
  validateInboxDelta(delta, projection, _refs, additionalThreadRefs = [], additionalMessages = [], additionalActivities = []) {
1248
1229
  const attentionKeys = new Set();
@@ -1492,7 +1473,9 @@ export class AgentTeamLedger {
1492
1473
  }
1493
1474
  if (operation.kind === 'team/thread-attention-changed' || operation.kind === 'team/thread-read') {
1494
1475
  this.applyInboxDelta(target, operation.data.inbox);
1476
+ return;
1495
1477
  }
1478
+ assertUnhandledKind(operation);
1496
1479
  }
1497
1480
  /** Facts arrive in ledger sequence order, so global and per-thread lists stay sorted by append only. */
1498
1481
  appendMessageFact(target, message, mentions) {
@@ -1816,6 +1799,29 @@ export class AgentTeamLedger {
1816
1799
  return Object.freeze({ ...task, status: this.deriveResolvedTaskStatus(task, projected.values()) });
1817
1800
  }));
1818
1801
  }
1802
+ /** Resolve one Task's Thread for a workspace-authorized actor; Member actors must belong to the Task's Channel. */
1803
+ threadForActor(actor, workspaceId, taskRef) {
1804
+ const task = this.requireTask(workspaceId, taskRef);
1805
+ const thread = this.requireThread(task.threadRef);
1806
+ if (actor.kind === 'member')
1807
+ this.requireMemberChannel(this.requireMember(actor.memberId), task.channelRef);
1808
+ return { task, thread };
1809
+ }
1810
+ /** Business outcomes that defer a thread write: unread work first, then a stale revision. */
1811
+ deferredThreadWrite(actorMemberId, task, thread, baseRevision) {
1812
+ const unread = this.unreadFor(actorMemberId, thread.threadRef);
1813
+ if (unread.length > 0)
1814
+ return this.unreadRequired(task, thread, unread);
1815
+ if (baseRevision !== thread.revision)
1816
+ return this.staleRevision(task, thread, baseRevision);
1817
+ return undefined;
1818
+ }
1819
+ /** Commit projections shared by the Message-sent and Thread-replied results. */
1820
+ committedMessageResult(operation) {
1821
+ return { kind: 'committed', receipt: this.receipt(operation), message: operation.data.message,
1822
+ task: operation.data.task, thread: operation.data.thread, attention: operation.data.inbox.attention.set,
1823
+ directMarkers: operation.data.inbox.directMarkers.added };
1824
+ }
1819
1825
  threadAnchor(task) {
1820
1826
  return this.threadAnchorFrom(this.state, task);
1821
1827
  }
@@ -1828,16 +1834,21 @@ export class AgentTeamLedger {
1828
1834
  threadFactKey(fact) {
1829
1835
  return fact.kind === 'message' ? `message:${fact.message.messageRef}` : `activity:${fact.activity.activityRef}`;
1830
1836
  }
1831
- taskNumbers(workspaceId, channelRef) {
1837
+ /**
1838
+ * Display numbers for Tasks: one counter per home Channel, in creation
1839
+ * order. This is the single numbering authority — Channel cards, Thread
1840
+ * headings, cross-channel ref resolution, and inbox renders all show the
1841
+ * ordinal the Task holds inside its own Channel.
1842
+ */
1843
+ taskNumbers(workspaceId) {
1832
1844
  const numbers = new Map();
1833
- let next = 1;
1845
+ const next = new Map();
1834
1846
  for (const message of this.state.topLevelMessages) {
1835
1847
  if (this.state.channels.get(message.channelRef)?.workspaceId !== workspaceId)
1836
1848
  continue;
1837
- if (channelRef !== undefined && message.channelRef !== channelRef)
1838
- continue;
1839
- numbers.set(message.taskRef, next);
1840
- next += 1;
1849
+ const ordinal = (next.get(message.channelRef) ?? 0) + 1;
1850
+ next.set(message.channelRef, ordinal);
1851
+ numbers.set(message.taskRef, ordinal);
1841
1852
  }
1842
1853
  return numbers;
1843
1854
  }
@@ -2153,14 +2164,10 @@ export class AgentTeamLedger {
2153
2164
  releasedClaims: operation.data.claims, removedAttention: operation.data.inbox.attention.removed });
2154
2165
  }
2155
2166
  messageResult(operation) {
2156
- return Object.freeze({ kind: 'committed', receipt: this.receipt(operation), message: operation.data.message,
2157
- task: operation.data.task, thread: operation.data.thread, attention: operation.data.inbox.attention.set,
2158
- directMarkers: operation.data.inbox.directMarkers.added });
2167
+ return Object.freeze(this.committedMessageResult(operation));
2159
2168
  }
2160
2169
  replyResult(operation) {
2161
- return Object.freeze({ kind: 'committed', receipt: this.receipt(operation), message: operation.data.message,
2162
- task: operation.data.task, thread: operation.data.thread, attention: operation.data.inbox.attention.set,
2163
- directMarkers: operation.data.inbox.directMarkers.added });
2170
+ return Object.freeze(this.committedMessageResult(operation));
2164
2171
  }
2165
2172
  claimResult(operation) {
2166
2173
  const attention = operation.data.inbox.attention.set.find(candidate => candidate.memberId === operation.data.claim.owner);
@@ -8,59 +8,55 @@ export function classifyRecoverableError(message) {
8
8
  return undefined;
9
9
  }
10
10
  export const RECOVERY_DELAY_MS = 120_000;
11
- export const RECOVERY_MAX_ATTEMPTS = 3;
11
+ export const RECOVERY_MAX_CONSECUTIVE_ERRORS = 3;
12
12
  /**
13
- * Per-member automatic recovery episodes. One episode covers a run of
14
- * identical errors; a changed error string starts a fresh one, and any clean
15
- * turn end clears the slate. After `maxAttempts` injections of the same error
16
- * the coordinator stands down and leaves the Member in error for the operator.
13
+ * Per-member automatic recovery episodes. An episode is every recoverable
14
+ * `agent/error` occurrence until a clean turn end, regardless of error text
15
+ * or family. Each of the first two occurrences schedules its own wakeup.
17
16
  */
18
17
  export class RecoveryCoordinator {
19
18
  episodes = new Map();
20
- inject;
19
+ wake;
21
20
  onStandDown;
22
21
  delayMs;
23
- maxAttempts;
22
+ maxConsecutiveErrors;
24
23
  constructor(options) {
25
- this.inject = options.inject;
24
+ this.wake = options.wake;
26
25
  this.onStandDown = options.onStandDown;
27
26
  this.delayMs = options.delayMs ?? RECOVERY_DELAY_MS;
28
- this.maxAttempts = options.maxAttempts ?? RECOVERY_MAX_ATTEMPTS;
27
+ this.maxConsecutiveErrors = options.maxConsecutiveErrors ?? RECOVERY_MAX_CONSECUTIVE_ERRORS;
29
28
  }
30
- /** Observe one error occurrence for a Member. */
29
+ /** Observe one `agent/error` occurrence for a Member. */
31
30
  onError(memberId, errorMessage) {
32
- const kind = classifyRecoverableError(errorMessage);
33
- if (kind === undefined) {
34
- // A non-retryable failure cancels anything pending: retrying cannot help.
31
+ if (classifyRecoverableError(errorMessage) === undefined) {
32
+ // A non-recoverable failure cancels anything pending: retrying cannot help.
35
33
  this.stopTracking(memberId);
36
34
  return;
37
35
  }
38
36
  let episode = this.episodes.get(memberId);
39
- if (episode === undefined || episode.lastError !== errorMessage) {
40
- this.cancelTimer(episode);
41
- episode = { kind, lastError: errorMessage, attempts: 0 };
37
+ if (episode === undefined) {
38
+ episode = { consecutiveFailures: 0, timers: new Set() };
42
39
  this.episodes.set(memberId, episode);
43
40
  }
44
- else if (episode.attempts >= this.maxAttempts) {
45
- // The same error survived every allowed injection — stand down once.
46
- if (episode.stoodDown !== true) {
47
- episode.stoodDown = true;
48
- this.onStandDown?.(memberId, episode.attempts);
49
- }
41
+ if (episode.stoodDown === true)
50
42
  return;
51
- }
52
- if (episode.timer !== undefined)
43
+ episode.consecutiveFailures += 1;
44
+ if (episode.consecutiveFailures >= this.maxConsecutiveErrors) {
45
+ this.cancelTimers(episode);
46
+ episode.stoodDown = true;
47
+ this.onStandDown?.(memberId, episode.consecutiveFailures);
53
48
  return;
54
- episode.timer = setTimeout(() => {
55
- episode.timer = undefined;
56
- episode.attempts += 1;
49
+ }
50
+ const timer = setTimeout(() => {
51
+ episode.timers.delete(timer);
57
52
  try {
58
- this.inject(memberId, episode.attempts, kind);
53
+ this.wake(memberId);
59
54
  }
60
55
  catch {
61
56
  this.stopTracking(memberId);
62
57
  }
63
58
  }, this.delayMs);
59
+ episode.timers.add(timer);
64
60
  }
65
61
  /** A turn ended cleanly (running→idle without an error): the episode is over. */
66
62
  onCleanTurnEnd(memberId) {
@@ -70,18 +66,17 @@ export class RecoveryCoordinator {
70
66
  const episode = this.episodes.get(memberId);
71
67
  if (episode === undefined)
72
68
  return;
73
- this.cancelTimer(episode);
69
+ this.cancelTimers(episode);
74
70
  this.episodes.delete(memberId);
75
71
  }
76
72
  dispose() {
77
73
  for (const episode of this.episodes.values())
78
- this.cancelTimer(episode);
74
+ this.cancelTimers(episode);
79
75
  this.episodes.clear();
80
76
  }
81
- cancelTimer(episode) {
82
- if (episode?.timer === undefined)
83
- return;
84
- clearTimeout(episode.timer);
85
- episode.timer = undefined;
77
+ cancelTimers(episode) {
78
+ for (const timer of episode.timers)
79
+ clearTimeout(timer);
80
+ episode.timers.clear();
86
81
  }
87
82
  }
@@ -928,7 +928,7 @@ export const TYPERT = {
928
928
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamMemberResult',
929
929
  schema: _wowyuarm_dsh_agent_team_agentTeam_addMember_result$schema,
930
930
  },
931
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":342,"column":9},
931
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":378,"column":9},
932
932
  },
933
933
  {
934
934
  id: '@wowyuarm/dsh-agent-team#agentTeam/changeAttention',
@@ -953,7 +953,7 @@ export const TYPERT = {
953
953
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamThreadAttentionResult',
954
954
  schema: _wowyuarm_dsh_agent_team_agentTeam_changeAttention_result$schema,
955
955
  },
956
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":644,"column":9},
956
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":641,"column":9},
957
957
  },
958
958
  {
959
959
  id: '@wowyuarm/dsh-agent-team#agentTeam/changes',
@@ -979,7 +979,7 @@ export const TYPERT = {
979
979
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamChangesResult',
980
980
  schema: _wowyuarm_dsh_agent_team_agentTeam_changes_result$schema,
981
981
  },
982
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":279,"column":9},
982
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":315,"column":9},
983
983
  },
984
984
  {
985
985
  id: '@wowyuarm/dsh-agent-team#agentTeam/changeTask',
@@ -1004,7 +1004,7 @@ export const TYPERT = {
1004
1004
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamTaskResult',
1005
1005
  schema: _wowyuarm_dsh_agent_team_agentTeam_changeTask_result$schema,
1006
1006
  },
1007
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":524,"column":9},
1007
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":541,"column":9},
1008
1008
  },
1009
1009
  {
1010
1010
  id: '@wowyuarm/dsh-agent-team#agentTeam/createChannel',
@@ -1029,7 +1029,7 @@ export const TYPERT = {
1029
1029
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamCreateChannelResult',
1030
1030
  schema: _wowyuarm_dsh_agent_team_agentTeam_createChannel_result$schema,
1031
1031
  },
1032
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":320,"column":9},
1032
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":356,"column":9},
1033
1033
  },
1034
1034
  {
1035
1035
  id: '@wowyuarm/dsh-agent-team#agentTeam/getAttachment',
@@ -1054,7 +1054,7 @@ export const TYPERT = {
1054
1054
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamGetAttachmentResult',
1055
1055
  schema: _wowyuarm_dsh_agent_team_agentTeam_getAttachment_result$schema,
1056
1056
  },
1057
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":621,"column":9},
1057
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":627,"column":9},
1058
1058
  },
1059
1059
  {
1060
1060
  id: '@wowyuarm/dsh-agent-team#agentTeam/inbox',
@@ -1079,7 +1079,7 @@ export const TYPERT = {
1079
1079
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamInbox',
1080
1080
  schema: _wowyuarm_dsh_agent_team_agentTeam_inbox_result$schema,
1081
1081
  },
1082
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":654,"column":3},
1082
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":650,"column":3},
1083
1083
  },
1084
1084
  {
1085
1085
  id: '@wowyuarm/dsh-agent-team#agentTeam/joinChannel',
@@ -1104,7 +1104,7 @@ export const TYPERT = {
1104
1104
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamJoinChannelResult',
1105
1105
  schema: _wowyuarm_dsh_agent_team_agentTeam_joinChannel_result$schema,
1106
1106
  },
1107
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":534,"column":9},
1107
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":551,"column":9},
1108
1108
  },
1109
1109
  {
1110
1110
  id: '@wowyuarm/dsh-agent-team#agentTeam/members',
@@ -1130,7 +1130,7 @@ export const TYPERT = {
1130
1130
  typeSymbol: '@wowyuarm/dsh-agent-team#agentTeam/members:result',
1131
1131
  schema: _wowyuarm_dsh_agent_team_agentTeam_members_result$schema,
1132
1132
  },
1133
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":270,"column":3},
1133
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":306,"column":3},
1134
1134
  },
1135
1135
  {
1136
1136
  id: '@wowyuarm/dsh-agent-team#agentTeam/putAttachment',
@@ -1155,7 +1155,7 @@ export const TYPERT = {
1155
1155
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamPutAttachmentResult',
1156
1156
  schema: _wowyuarm_dsh_agent_team_agentTeam_putAttachment_result$schema,
1157
1157
  },
1158
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":608,"column":9},
1158
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":614,"column":9},
1159
1159
  },
1160
1160
  {
1161
1161
  id: '@wowyuarm/dsh-agent-team#agentTeam/readThread',
@@ -1180,7 +1180,7 @@ export const TYPERT = {
1180
1180
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamThreadReadResult',
1181
1181
  schema: _wowyuarm_dsh_agent_team_agentTeam_readThread_result$schema,
1182
1182
  },
1183
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":661,"column":9},
1183
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":657,"column":9},
1184
1184
  },
1185
1185
  {
1186
1186
  id: '@wowyuarm/dsh-agent-team#agentTeam/recoverMember',
@@ -1205,7 +1205,7 @@ export const TYPERT = {
1205
1205
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamRecoverMemberResult',
1206
1206
  schema: _wowyuarm_dsh_agent_team_agentTeam_recoverMember_result$schema,
1207
1207
  },
1208
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":400,"column":9},
1208
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":429,"column":9},
1209
1209
  },
1210
1210
  {
1211
1211
  id: '@wowyuarm/dsh-agent-team#agentTeam/removeChannelMember',
@@ -1230,7 +1230,7 @@ export const TYPERT = {
1230
1230
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamRemoveChannelMemberResult',
1231
1231
  schema: _wowyuarm_dsh_agent_team_agentTeam_removeChannelMember_result$schema,
1232
1232
  },
1233
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":546,"column":9},
1233
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":562,"column":9},
1234
1234
  },
1235
1235
  {
1236
1236
  id: '@wowyuarm/dsh-agent-team#agentTeam/reply',
@@ -1255,7 +1255,7 @@ export const TYPERT = {
1255
1255
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamReplyResult',
1256
1256
  schema: _wowyuarm_dsh_agent_team_agentTeam_reply_result$schema,
1257
1257
  },
1258
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":629,"column":9},
1258
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":635,"column":9},
1259
1259
  },
1260
1260
  {
1261
1261
  id: '@wowyuarm/dsh-agent-team#agentTeam/resolveTaskRefs',
@@ -1280,7 +1280,7 @@ export const TYPERT = {
1280
1280
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamResolveTaskRefsResult',
1281
1281
  schema: _wowyuarm_dsh_agent_team_agentTeam_resolveTaskRefs_result$schema,
1282
1282
  },
1283
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":258,"column":3},
1283
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":293,"column":3},
1284
1284
  },
1285
1285
  {
1286
1286
  id: '@wowyuarm/dsh-agent-team#agentTeam/sendMessage',
@@ -1305,7 +1305,7 @@ export const TYPERT = {
1305
1305
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamSendMessageResult',
1306
1306
  schema: _wowyuarm_dsh_agent_team_agentTeam_sendMessage_result$schema,
1307
1307
  },
1308
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":556,"column":9},
1308
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":571,"column":9},
1309
1309
  },
1310
1310
  {
1311
1311
  id: '@wowyuarm/dsh-agent-team#agentTeam/threadHistory',
@@ -1330,7 +1330,7 @@ export const TYPERT = {
1330
1330
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamThreadHistory',
1331
1331
  schema: _wowyuarm_dsh_agent_team_agentTeam_threadHistory_result$schema,
1332
1332
  },
1333
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":678,"column":3},
1333
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":673,"column":3},
1334
1334
  },
1335
1335
  {
1336
1336
  id: '@wowyuarm/dsh-agent-team#agentTeam/threadObservations',
@@ -1355,7 +1355,7 @@ export const TYPERT = {
1355
1355
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamThreadObservations',
1356
1356
  schema: _wowyuarm_dsh_agent_team_agentTeam_threadObservations_result$schema,
1357
1357
  },
1358
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":671,"column":3},
1358
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":666,"column":3},
1359
1359
  },
1360
1360
  {
1361
1361
  id: '@wowyuarm/dsh-agent-team#agentTeam/updateChannel',
@@ -1380,7 +1380,7 @@ export const TYPERT = {
1380
1380
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamUpdateChannelResult',
1381
1381
  schema: _wowyuarm_dsh_agent_team_agentTeam_updateChannel_result$schema,
1382
1382
  },
1383
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":332,"column":9},
1383
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":368,"column":9},
1384
1384
  },
1385
1385
  {
1386
1386
  id: '@wowyuarm/dsh-agent-team#agentTeam/updateMember',
@@ -1405,7 +1405,7 @@ export const TYPERT = {
1405
1405
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamMemberResult',
1406
1406
  schema: _wowyuarm_dsh_agent_team_agentTeam_updateMember_result$schema,
1407
1407
  },
1408
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":487,"column":9},
1408
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":511,"column":9},
1409
1409
  },
1410
1410
  {
1411
1411
  id: '@wowyuarm/dsh-agent-team#agentTeam/view',
@@ -1430,7 +1430,7 @@ export const TYPERT = {
1430
1430
  typeSymbol: '@wowyuarm/dsh-agent-team/types#AgentTeamView',
1431
1431
  schema: _wowyuarm_dsh_agent_team_agentTeam_view_result$schema,
1432
1432
  },
1433
- sourceLocation: {"file":"packages/agent-team/src/index.ts","line":685,"column":3},
1433
+ sourceLocation: {"file":"packages/agent-team/src/index.ts","line":680,"column":3},
1434
1434
  },
1435
1435
  ],
1436
1436
  model: {
@@ -1467,7 +1467,9 @@ export const TYPERT = {
1467
1467
  {
1468
1468
  "kind": "method",
1469
1469
  "name": "membersForClient",
1470
- "signature": "@Remote('members') membersForClient(request: AgentTeamMembersRequest): readonly AgentTeamClientMemberStatus[]"
1470
+ "signature": "@Remote('members') membersForClient(request: AgentTeamMembersRequest): readonly AgentTeamClientMemberStatus[]",
1471
+ "summary": "Return only this Workspace's current Member projection to the Client.",
1472
+ "jsDoc": "/** Return only this Workspace's current Member projection to the Client. */"
1471
1473
  },
1472
1474
  {
1473
1475
  "kind": "method",
@@ -2137,6 +2139,14 @@ export const TYPERT = {
2137
2139
  "name": "CodeDispatchStartEventData",
2138
2140
  "declaration": "export interface CodeDispatchStartEventData {\n rootCallId: CallId;\n parentCallId: CallId;\n subCallId: CallId;\n name: string;\n arguments: unknown;\n}"
2139
2141
  },
2142
+ {
2143
+ "name": "CommandId",
2144
+ "declaration": "export type CommandId = Branded<'CommandId'>;"
2145
+ },
2146
+ {
2147
+ "name": "CompactionId",
2148
+ "declaration": "export type CompactionId = Branded<'CompactionId'>;"
2149
+ },
2140
2150
  {
2141
2151
  "name": "ContentBlock",
2142
2152
  "declaration": "export type ContentBlock = ContentBlockMap[ContentBlockType];"
@@ -2263,7 +2273,7 @@ export const TYPERT = {
2263
2273
  },
2264
2274
  {
2265
2275
  "name": "SessionEventMap",
2266
- "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record<string, never>;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'agent-preset/selected': { agentPreset: string; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n}"
2276
+ "declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true; };\n 'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; }; meta?: JsonValue; };\n 'todo/write': { todos: TodoItem[]; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; };\n 'request/context': RequestContext;\n 'session/end-seed': Record<string, never>;\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: number; end: number; }; shadowedSeqs: number[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: number; end: number; }; shadowedSeqs: number[]; shadowedTokenCount: number; };\n 'agent-preset/selected': { agentPreset: string; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/code-dispatch-start': CodeDispatchStartEventData;\n 'tool/code-dispatch': CodeDispatchEventData;\n}"
2267
2277
  },
2268
2278
  {
2269
2279
  "name": "SessionEventType",
@@ -1 +1 @@
1
- {"version":3,"file":"typert.remote-client.d.ts","names":["addMember","changeAttention","changes","changeTask","createChannel","getAttachment","inbox","joinChannel","members","putAttachment","readThread","recoverMember","removeChannelMember","reply","resolveTaskRefs","sendMessage","threadHistory","threadObservations","updateChannel","updateMember","view"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;IAqVQA,S;IA8SAC,e;IA7WAC,O;IAqPAC,U;IA5MAC,a;IA6SAC,a;IAiCNC,K;IAxHMC,W;IAxQNC,O;IAkVMC,a;IAqDAC,U;IArQAC,a;IAkJAC,mB;IAmFAC,K;IAnXNC,e;IA0SMC,W;IA0HNC,a;IAPAC,kB;IAnVMC,a;IA2JAC,Y;IAsMNC,I;;;IAvVMpB,qB;IA8SAC,2B;IA7WAC,mB;IAqPAC,sB;IA5MAC,yB;IA6SAC,yB;IAiCNC,iB;IAxHMC,uB;IAxQNC,mB;IAkVMC,yB;IAqDAC,sB;IArQAC,yB;IAkJAC,+B;IAmFAC,iB;IAnXNC,2B;IA0SMC,uB;IA0HNC,yB;IAPAC,8B;IAnVMC,yB;IA2JAC,wB;IAsMNC,gB","ignoreList":[]}
1
+ {"version":3,"file":"typert.remote-client.d.ts","names":["addMember","changeAttention","changes","changeTask","createChannel","getAttachment","inbox","joinChannel","members","putAttachment","readThread","recoverMember","removeChannelMember","reply","resolveTaskRefs","sendMessage","threadHistory","threadObservations","updateChannel","updateMember","view"],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":";;;;;;;;;IAyXQA,S;IAuQAC,e;IAtUAC,O;IAkOAC,U;IAzLAC,a;IA+QAC,a;IAuBNC,K;IAnGMC,W;IArPNC,O;IAoTMC,a;IA2CAC,U;IApOAC,a;IAqIAC,mB;IAyEAC,K;IAtVNC,e;IAsRMC,W;IAsGNC,a;IAPAC,kB;IA1SMC,a;IA+IAC,Y;IAyKNC,I;;;IA9SMpB,qB;IAuQAC,2B;IAtUAC,mB;IAkOAC,sB;IAzLAC,yB;IA+QAC,yB;IAuBNC,iB;IAnGMC,uB;IArPNC,mB;IAoTMC,yB;IA2CAC,sB;IApOAC,yB;IAqIAC,+B;IAyEAC,iB;IAtVNC,2B;IAsRMC,uB;IAsGNC,yB;IAPAC,8B;IA1SMC,yB;IA+IAC,wB;IAyKNC,gB","ignoreList":[]}