@wowyuarm/dsh-agent-team 0.1.10 → 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.
Files changed (135) hide show
  1. package/README.md +17 -4
  2. package/README.zh.md +17 -4
  3. package/package.json +53 -47
  4. package/packages/agent-team/README.md +6 -4
  5. package/packages/agent-team/README.zh.md +6 -4
  6. package/packages/agent-team/lib/context-management.js +40 -50
  7. package/packages/agent-team/lib/context-projection.js +15 -1
  8. package/packages/agent-team/lib/index.js +244 -154
  9. package/packages/agent-team/lib/invariant.js +38 -4
  10. package/packages/agent-team/lib/ledger.js +775 -383
  11. package/packages/agent-team/lib/member-context.js +6 -2
  12. package/packages/agent-team/lib/member-runtime.js +47 -9
  13. package/packages/agent-team/lib/member-time-context.js +20 -5
  14. package/packages/agent-team/lib/mentions.js +56 -0
  15. package/packages/agent-team/lib/pressure-policy.js +33 -9
  16. package/packages/agent-team/lib/session-event-cursor.js +116 -0
  17. package/packages/agent-team/lib/session-remediation.js +38 -26
  18. package/packages/agent-team/lib/spec.js +47 -34
  19. package/packages/agent-team/lib/stored-session-reader.js +138 -0
  20. package/packages/agent-team/lib/typert.host.js +157 -41
  21. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  22. package/packages/agent-team/lib/typert.remote-client.js +129 -32
  23. package/packages/agent-team/lib/types/context-management.d.ts +7 -0
  24. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/context-projection.d.ts +8 -0
  26. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  27. package/packages/agent-team/lib/types/index.d.ts +77 -7
  28. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  29. package/packages/agent-team/lib/types/invariant.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/ledger.d.ts +251 -20
  31. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  33. package/packages/agent-team/lib/types/member-runtime.d.ts +2 -1
  34. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  35. package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
  36. package/packages/agent-team/lib/types/mentions.d.ts +34 -0
  37. package/packages/agent-team/lib/types/mentions.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/pressure-policy.d.ts +18 -0
  39. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
  40. package/packages/agent-team/lib/types/session-event-cursor.d.ts +119 -0
  41. package/packages/agent-team/lib/types/session-event-cursor.d.ts.map +1 -0
  42. package/packages/agent-team/lib/types/session-remediation.d.ts +23 -0
  43. package/packages/agent-team/lib/types/session-remediation.d.ts.map +1 -1
  44. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  45. package/packages/agent-team/lib/types/stored-session-reader.d.ts +92 -0
  46. package/packages/agent-team/lib/types/stored-session-reader.d.ts.map +1 -0
  47. package/packages/agent-team/lib/types/types/entities.d.ts +28 -20
  48. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  49. package/packages/agent-team/lib/types/types/operations.d.ts +45 -19
  50. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  51. package/packages/agent-team/lib/types/types/requests-results.d.ts +87 -4
  52. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  53. package/packages/agent-team/preset/team-member/agent.cordis.yml +49 -7
  54. package/packages/client-agent-team/README.md +1 -1
  55. package/packages/client-agent-team/README.zh.md +1 -1
  56. package/packages/client-agent-team/lib/client.js +2357 -1207
  57. package/packages/client-agent-team/lib/client.js.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  59. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +27 -7
  60. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts +18 -0
  61. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.d.ts.map +1 -0
  62. package/packages/client-agent-team/lib/types/client/TeamAvatarStack.js +22 -0
  63. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts +3 -1
  64. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  65. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +167 -35
  66. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  67. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +23 -27
  68. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +11 -5
  69. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/TeamComposer.js +26 -26
  71. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  72. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  73. package/packages/client-agent-team/lib/types/client/TeamConversation.js +9 -2
  74. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts +20 -0
  75. package/packages/client-agent-team/lib/types/client/TeamCountBadge.d.ts.map +1 -0
  76. package/packages/client-agent-team/lib/types/client/TeamCountBadge.js +25 -0
  77. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +25 -0
  78. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -0
  79. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +139 -0
  80. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +8 -24
  82. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts +43 -0
  83. package/packages/client-agent-team/lib/types/client/TeamMemberRow.d.ts.map +1 -0
  84. package/packages/client-agent-team/lib/types/client/TeamMemberRow.js +27 -0
  85. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts +2 -2
  86. package/packages/client-agent-team/lib/types/client/TeamMembersAction.d.ts.map +1 -1
  87. package/packages/client-agent-team/lib/types/client/TeamMembersAction.js +2 -2
  88. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +9 -2
  89. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  90. package/packages/client-agent-team/lib/types/client/TeamMessage.js +11 -4
  91. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +8 -0
  92. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  93. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +21 -1
  94. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  95. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +108 -30
  96. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  97. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  98. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +68 -7
  99. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  100. package/packages/client-agent-team/lib/types/client/index.js +19 -9
  101. package/packages/client-agent-team/lib/types/client/locales.d.ts +40 -2
  102. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  103. package/packages/client-agent-team/lib/types/client/locales.js +40 -2
  104. package/packages/client-agent-team/lib/types/client/navigation.d.ts +10 -0
  105. package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
  106. package/packages/client-agent-team/lib/types/client/navigation.js +18 -7
  107. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +41 -0
  108. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +1 -0
  109. package/packages/client-agent-team/lib/types/client/scope-coverage.js +64 -0
  110. package/packages/client-agent-team/lib/types/client/slots.d.ts +7 -2
  111. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  112. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +33 -2
  113. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  114. package/packages/client-agent-team/lib/types/client/team-changes.js +107 -25
  115. package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts +20 -0
  116. package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts.map +1 -0
  117. package/packages/client-agent-team/lib/types/client/team-dialog-save.js +36 -0
  118. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +43 -1
  119. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  120. package/packages/client-agent-team/lib/types/client/team-formatters.js +81 -6
  121. package/packages/tool-agent-team/README.md +2 -2
  122. package/packages/tool-agent-team/README.zh.md +2 -2
  123. package/packages/tool-agent-team/lib/context-tools.js +18 -14
  124. package/packages/tool-agent-team/lib/host-access.js +20 -0
  125. package/packages/tool-agent-team/lib/index.js +44 -32
  126. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
  127. package/packages/tool-agent-team/lib/types/host-access.d.ts +14 -0
  128. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -0
  129. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  130. package/packages/agent-team/lib/progress-nudge.js +0 -328
  131. package/packages/agent-team/lib/types/progress-nudge.d.ts +0 -136
  132. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +0 -1
  133. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts +0 -3
  134. package/packages/client-agent-team/lib/types/client/TeamSettings.d.ts.map +0 -1
  135. package/packages/client-agent-team/lib/types/client/TeamSettings.js +0 -5
@@ -9,18 +9,7 @@
9
9
  * @module @wowyuarm/dsh-agent-team/context-tools
10
10
  */
11
11
  import { defineTool } from '@deepseek-ai/dsh-tools';
12
- function service(agent) {
13
- const host = agent.ctx.get('agentTeam');
14
- if (host === undefined)
15
- throw new Error('Agent Team Host is unavailable');
16
- return host;
17
- }
18
- function member(agent) {
19
- const current = service(agent).memberForAgent(agent);
20
- if (current === undefined)
21
- throw new Error('team tool requires an active Team Member');
22
- return current;
23
- }
12
+ import { member, service } from "./host-access.js";
24
13
  const MAX_HANDOFF_CHARS = 32 * 1024;
25
14
  const MAX_RELATED_FILES = 32;
26
15
  const contextRollover = defineTool({
@@ -139,13 +128,19 @@ const contextTimeline = defineTool({
139
128
  reason: { type: 'string' },
140
129
  sourceSessionId: { type: 'string' },
141
130
  } } },
131
+ incompleteFrom: { type: 'object', additionalProperties: false, properties: {
132
+ sessionId: { type: 'string', required: true },
133
+ reason: { type: 'string', required: true },
134
+ } },
142
135
  } },
143
136
  // The item list is the whole decision surface: without each anchor's
144
137
  // ref, label, source, size estimates, affected Threads, and
145
138
  // restorable/reason verdict, the model cannot pick a `checkpointRef` for
146
139
  // `context_rollover` — the summary line alone left the tool unusable for
147
140
  // seeded returns. The Host bounds items (default 12, at most 24), so this
148
- // list cannot grow unbounded.
141
+ // list cannot grow unbounded. `incompleteFrom` states where and why the
142
+ // lineage walk stopped early, so history read up to that ancestor is
143
+ // known to be a truncation, not everything that exists.
149
144
  render: (_args, value) => {
150
145
  const lines = [`Context timeline: ${value.usageTokens} tokens used (handoff at ${value.handoffAt}, hard limit ${value.hardLimit}). ${value.items.length} item(s):`];
151
146
  for (const item of value.items) {
@@ -156,6 +151,9 @@ const contextTimeline = defineTool({
156
151
  : `not restorable — ${item.reason ?? 'no reason given'}`;
157
152
  lines.push(`- ${item.name} [source: ${item.source}] (${size}; ${threads}) — ${restorable}`);
158
153
  }
154
+ if (value.incompleteFrom !== undefined) {
155
+ lines.push(`History incomplete: the lineage walk stopped at Session ${value.incompleteFrom.sessionId} (${value.incompleteFrom.reason}); ancestors before it could not be read and are not reflected above.`);
156
+ }
159
157
  return [{ type: 'text', text: lines.join('\n') }];
160
158
  },
161
159
  },
@@ -169,7 +167,13 @@ const contextTimeline = defineTool({
169
167
  const result = await host.contextTimelineForAgent(agent, { memberId: current.memberId, ...(limit === undefined ? {} : { limit }) });
170
168
  // The Host result is deeply immutable; the tool output contract carries
171
169
  // plain arrays, so re-shape without any semantic change.
172
- return { usageTokens: result.usageTokens, hardLimit: result.hardLimit, handoffAt: result.handoffAt, items: result.items.map(item => ({ ...item, affectedThreads: [...item.affectedThreads] })) };
170
+ return {
171
+ usageTokens: result.usageTokens,
172
+ hardLimit: result.hardLimit,
173
+ handoffAt: result.handoffAt,
174
+ items: result.items.map(item => ({ ...item, affectedThreads: [...item.affectedThreads] })),
175
+ ...(result.incompleteFrom === undefined ? {} : { incompleteFrom: result.incompleteFrom }),
176
+ };
173
177
  },
174
178
  });
175
179
  export function registerContextTools(ctx) {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared Host accessors for every Team tool module. `agent.ctx.get` is the
3
+ * one resolution path a tool row has — the preset mounts these tools beside
4
+ * the Host, so a missing service or an inactive Member is a model-visible
5
+ * rejection rather than a silent no-op. Both messages are user-facing text.
6
+ */
7
+ /** Resolve the Team Host service, or reject the tool call. */
8
+ export function service(agent) {
9
+ const host = agent.ctx.get('agentTeam');
10
+ if (host === undefined)
11
+ throw new Error('Agent Team Host is unavailable');
12
+ return host;
13
+ }
14
+ /** Resolve the calling Team Member, or reject the tool call. */
15
+ export function member(agent) {
16
+ const current = service(agent).memberForAgent(agent);
17
+ if (current === undefined)
18
+ throw new Error('team tool requires an active Team Member');
19
+ return current;
20
+ }
@@ -1,6 +1,7 @@
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
+ import { member, service } from "./host-access.js";
4
5
  import { defineTool } from '@deepseek-ai/dsh-tools';
5
6
  export const name = 'wowyuarm-agent-team-tools';
6
7
  export const inject = ['tools'];
@@ -76,18 +77,6 @@ function taskStanding(value) {
76
77
  return '';
77
78
  return `${value.taskRef}${value.taskNumber === undefined ? '' : ` (#${value.taskNumber})`}${value.status === undefined ? '' : `, ${value.status}${value.resolution === undefined ? '' : `/${value.resolution}`}`}`;
78
79
  }
79
- function service(agent) {
80
- const host = agent.ctx.get('agentTeam');
81
- if (host === undefined)
82
- throw new Error('Agent Team Host is unavailable');
83
- return host;
84
- }
85
- function member(agent) {
86
- const current = service(agent).memberForAgent(agent);
87
- if (current === undefined)
88
- throw new Error('team tool requires an active Team Member');
89
- return current;
90
- }
91
80
  function requestId(agentId, callId) {
92
81
  return `agent-team:tool:${agentId}:${callId}`;
93
82
  }
@@ -178,7 +167,7 @@ const teamInbox = defineTool({
178
167
  });
179
168
  const teamThread = defineTool({
180
169
  name: 'team_thread',
181
- 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.',
182
171
  parameters: {
183
172
  action: { type: 'string', required: true, enum: ['status', 'follow', 'unfollow', 'read', 'history'] },
184
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." },
@@ -189,7 +178,7 @@ const teamThread = defineTool({
189
178
  schema: { type: 'object', additionalProperties: false, properties: {
190
179
  kind: { type: 'string', required: true }, threadRef: { type: 'string', required: true }, taskRef: { type: 'string' },
191
180
  revision: { type: 'number', required: true }, status: { type: 'string' }, resolution: { type: 'string' }, taskNumber: { type: 'number' },
192
- 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' },
193
182
  anchor: { type: 'object', required: true, additionalProperties: false, properties: {
194
183
  messageRef: { type: 'string', required: true }, sender: { type: 'string', required: true }, body: { type: 'string', required: true }, sequence: { type: 'number', required: true }, occurredAt: { type: 'string' },
195
184
  } },
@@ -243,8 +232,12 @@ const teamThread = defineTool({
243
232
  const facts = value.facts;
244
233
  const acknowledged = facts.filter(fact => fact.unread === true).length;
245
234
  const remaining = value.remainingUnreadCount ?? 0;
235
+ // A read with nothing unread writes no durable operation, so the opening
236
+ // line claims a commit only when unread facts were actually acknowledged.
246
237
  const lines = [
247
- `Read committed — ${acknowledged === 0 ? `no unread updates on ${value.threadRef}; nothing remains` : `acknowledged ${acknowledged} unread update(s) on ${value.threadRef}; ${remaining} remain`}.`,
238
+ acknowledged === 0
239
+ ? `Read — no unread updates on ${value.threadRef}; nothing remains.`
240
+ : `Read committed — acknowledged ${acknowledged} unread update(s) on ${value.threadRef}; ${remaining} remain.`,
248
241
  `${value.threadRef}${standing === '' ? '' : ` · ${standing}`} · ${value.following ? 'following' : 'not following'}`,
249
242
  ];
250
243
  // Orientation: A the anchor is one of the returned facts (renders as
@@ -270,6 +263,13 @@ const teamThread = defineTool({
270
263
  else
271
264
  lines.push(...facts.map(fact => factLine(fact)));
272
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.`);
273
273
  if (value.contextAdvice !== undefined)
274
274
  lines.push('', ...adviceLines(value.contextAdvice));
275
275
  if (remaining === 0)
@@ -318,7 +318,7 @@ const teamThread = defineTool({
318
318
  const read = await host.readThreadForAgent(agent, { requestId: requestId(agent.id, exec.callId), ...base });
319
319
  return threadResult('read', read, read.attention, read.facts.map(entry => entry.fact.kind === 'message'
320
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 }
321
- : 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) });
322
322
  },
323
323
  });
324
324
  /** One rendered fact line; markers are inline, never a separate ellipsis line. */
@@ -355,7 +355,7 @@ function adviceLines(advice) {
355
355
  }
356
356
  const teamMessage = markAgentTeamPreset(defineTool({
357
357
  name: 'team_message',
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. 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 an unfollowed Agent. Pass Member refs in mentions and spell their handles inside the body; only mentioned Members render as mention chips. 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.',
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.',
359
359
  parameters: {
360
360
  action: { type: 'string', required: true, enum: ['start', 'reply', 'dm'] },
361
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." },
@@ -363,8 +363,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
363
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." },
364
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)." },
365
365
  asTask: { type: 'boolean', description: 'When true, start creates a Task with the Thread. Default false creates a taskless Thread.' },
366
- body: { type: 'string', required: true, description: "Markdown body. 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. Spell each mentioned Member's handle in the prose so the mention renders inline." }, 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." },
367
- 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." },
368
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.' },
369
368
  },
370
369
  output: {
@@ -372,6 +371,7 @@ const teamMessage = markAgentTeamPreset(defineTool({
372
371
  kind: { type: 'string', required: true }, action: { type: 'string' }, taskRef: { type: 'string' }, threadRef: { type: 'string' }, revision: { type: 'number' },
373
372
  expectedRevision: { type: 'number' }, messageRef: { type: 'string' }, memberIds: { type: 'array', items: { type: 'string' } }, unreadCount: { type: 'number' }, directCount: { type: 'number' },
374
373
  recipientMemberId: { type: 'string' }, recipientHandle: { type: 'string' }, delivered: { type: 'boolean' }, deliveryNote: { type: 'string' }, occurredAt: { type: 'string' },
374
+ undeliveredMentions: { type: 'array', items: { type: 'string' } },
375
375
  } },
376
376
  render: (_args, value) => {
377
377
  if (value.kind === 'dm-sent') {
@@ -388,6 +388,9 @@ const teamMessage = markAgentTeamPreset(defineTool({
388
388
  value.action === 'start' ? 'Committed — Thread created.' : 'Committed — reply added.',
389
389
  [value.messageRef, value.threadRef, ...(value.taskRef === undefined ? [] : [value.taskRef])].join(' · '),
390
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
+ ]),
391
394
  nextWriteLine(value.revision),
392
395
  ].join('\n') }];
393
396
  }
@@ -407,7 +410,6 @@ const teamMessage = markAgentTeamPreset(defineTool({
407
410
  throw new Error('team_message requires an Agent session');
408
411
  const current = member(agent);
409
412
  const host = service(agent);
410
- const mentions = args.mentions;
411
413
  const rawPaths = args.attachments;
412
414
  const attachmentPaths = Array.isArray(rawPaths) ? rawPaths.filter((entry) => typeof entry === 'string' && entry.trim() !== '') : undefined;
413
415
  const paths = attachmentPaths !== undefined && attachmentPaths.length > 0 ? { attachmentPaths } : {};
@@ -415,13 +417,13 @@ const teamMessage = markAgentTeamPreset(defineTool({
415
417
  if (args.channelRef === undefined || args.taskRef !== undefined || args.threadRef !== undefined || args.baseRevision !== undefined)
416
418
  throw new Error('start requires channelRef and does not accept threadRef, taskRef, or baseRevision');
417
419
  const result = await host.sendMessageForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
418
- channelRef: args.channelRef, body: args.body, asTask: args.asTask === true, ...(mentions === undefined ? {} : { recipients: mentions }), ...paths });
420
+ channelRef: args.channelRef, body: args.body, asTask: args.asTask === true, ...paths });
419
421
  return messageOutcome(result, 'start');
420
422
  }
421
423
  if (args.action === 'dm') {
422
424
  if (args.memberRef === undefined || args.channelRef !== undefined || args.threadRef !== undefined || args.taskRef !== undefined
423
- || args.baseRevision !== undefined || args.asTask !== undefined || mentions !== undefined || attachmentPaths !== undefined) {
424
- throw new Error('dm requires memberRef and body only; it does not accept channelRef, threadRef, taskRef, baseRevision, asTask, mentions, or attachments');
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');
425
427
  }
426
428
  try {
427
429
  const result = await host.dmForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
@@ -442,16 +444,20 @@ const teamMessage = markAgentTeamPreset(defineTool({
442
444
  const result = await host.replyForAgent(agent, { requestId: requestId(agent.id, exec.callId), workspaceId: current.workspaceId,
443
445
  ...(args.threadRef === undefined ? {} : { threadRef: args.threadRef }),
444
446
  ...(args.taskRef === undefined ? {} : { taskRef: args.taskRef }),
445
- body: args.body, baseRevision,
446
- ...(mentions === undefined ? {} : { recipients: mentions }), ...paths });
447
+ body: args.body, baseRevision, ...paths });
447
448
  return messageOutcome(result, 'reply');
448
449
  },
449
450
  }));
450
451
  function messageOutcome(result, action) {
451
- 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;
452
456
  return { kind: result.kind, action, threadRef: result.thread.threadRef,
453
457
  ...(result.task === undefined ? {} : { taskRef: result.task.taskRef }),
454
- 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
+ }
455
461
  if (result.kind === 'member_not_following')
456
462
  return { kind: result.kind, memberIds: [...result.memberIds],
457
463
  ...(result.taskRef === undefined ? {} : { taskRef: result.taskRef }), ...(result.threadRef === undefined ? {} : { threadRef: result.threadRef, revision: result.revision }) };
@@ -563,7 +569,7 @@ const teamView = defineTool({
563
569
  threadRef: { type: 'string', required: true }, channelRef: { type: 'string', required: true }, revision: { type: 'number', required: true }, messageCount: { type: 'number', required: true }, subject: { type: 'string', required: true },
564
570
  taskRef: { type: 'string' }, status: { type: 'string' }, taskNumber: { type: 'number' }, lastActivityAt: { type: 'string' },
565
571
  } } },
566
- tasks: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { taskRef: { type: 'string', required: true }, threadRef: { type: 'string', required: true }, channelRef: { type: 'string', required: true }, status: { type: 'string', required: true }, revision: { type: 'number', required: true } } } },
572
+ tasks: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { taskRef: { type: 'string', required: true }, threadRef: { type: 'string', required: true }, channelRef: { type: 'string', required: true }, status: { type: 'string', required: true }, revision: { type: 'number' } } } },
567
573
  cursor: { type: 'number', required: true }, hasMore: { type: 'boolean', required: true }, page: { type: 'string' },
568
574
  } },
569
575
  // Address book, newest Thread first: labelled sections, one bounded
@@ -611,7 +617,7 @@ const teamView = defineTool({
611
617
  return {
612
618
  channels: view.channels.map(channel => ({ channelRef: channel.channelRef, name: channel.name })),
613
619
  members: [
614
- { memberId: view.humanMemberId, kind: 'human', handle: 'human', description: 'Human Team Member', presence: 'available' },
620
+ { memberId: view.humanMemberId, kind: 'human', handle: AGENT_TEAM_HUMAN_HANDLE, description: 'Human Team Member', presence: 'available' },
615
621
  ...host.members().filter(status => visibleMemberIds.has(status.member.memberId)).map(status => ({ memberId: status.member.memberId,
616
622
  kind: 'agent', handle: status.member.handle, description: status.member.description, presence: status.presence })),
617
623
  ],
@@ -622,8 +628,14 @@ const teamView = defineTool({
622
628
  subject: boundedSubject(item.message.body), lastActivityAt: item.lastActivityAt,
623
629
  ...(task === undefined ? {} : { taskRef: task.taskRef, status: task.status, ...(item.taskNumber === undefined ? {} : { taskNumber: item.taskNumber }) }) };
624
630
  }),
625
- tasks: view.tasks.map(task => ({ taskRef: task.taskRef, threadRef: task.threadRef, channelRef: task.channelRef,
626
- status: task.status, revision: view.threads.find(thread => thread.threadRef === task.threadRef)?.revision ?? 0 })),
631
+ // A Task's revision is its Thread's; it is omitted rather than reported as
632
+ // `0` when the Task's Thread is outside this directory page's scope. A
633
+ // fabricated revision would read as "this Thread has never been written".
634
+ tasks: view.tasks.map(task => {
635
+ const revision = view.threads.find(thread => thread.threadRef === task.threadRef)?.revision;
636
+ return { taskRef: task.taskRef, threadRef: task.threadRef, channelRef: task.channelRef, status: task.status,
637
+ ...(revision === undefined ? {} : { revision }) };
638
+ }),
627
639
  cursor: view.cursor, hasMore: view.hasMore,
628
640
  ...(args.cursor === undefined ? {} : { page: 'threads' }),
629
641
  };
@@ -1 +1 @@
1
- {"version":3,"file":"context-tools.d.ts","sourceRoot":"","sources":["../../src/context-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoKH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,CAIrG"}
1
+ {"version":3,"file":"context-tools.d.ts","sourceRoot":"","sources":["../../src/context-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuKH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,CAIrG"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Shared Host accessors for every Team tool module. `agent.ctx.get` is the
3
+ * one resolution path a tool row has — the preset mounts these tools beside
4
+ * the Host, so a missing service or an inactive Member is a model-visible
5
+ * rejection rather than a silent no-op. Both messages are user-facing text.
6
+ */
7
+ import AgentTeam from '@wowyuarm/dsh-agent-team/host';
8
+ /** The Agent shape every Team tool receives. */
9
+ export type TeamToolAgent = NonNullable<Parameters<AgentTeam['memberForAgent']>[0]>;
10
+ /** Resolve the Team Host service, or reject the tool call. */
11
+ export declare function service(agent: TeamToolAgent): AgentTeam;
12
+ /** Resolve the calling Team Member, or reject the tool call. */
13
+ export declare function member(agent: TeamToolAgent): import("@wowyuarm/dsh-agent-team/types").AgentTeamAgentMember;
14
+ //# sourceMappingURL=host-access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-access.d.ts","sourceRoot":"","sources":["../../src/host-access.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,SAAS,MAAM,+BAA+B,CAAA;AAErD,gDAAgD;AAChD,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAEnF,8DAA8D;AAC9D,wBAAgB,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAIvD;AAED,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,KAAK,EAAE,aAAa,iEAI1C"}
@@ -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;AAclD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;AAypB/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAOxC"}
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"}