@wowyuarm/dsh-agent-team 0.1.7 → 0.1.9

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 (104) hide show
  1. package/package.json +2 -1
  2. package/packages/agent-team/README.md +5 -3
  3. package/packages/agent-team/README.zh.md +5 -3
  4. package/packages/agent-team/core-skills/member-skill-manager/SKILL.md +2 -0
  5. package/packages/agent-team/lib/attachments.js +14 -4
  6. package/packages/agent-team/lib/context-management.js +379 -0
  7. package/packages/agent-team/lib/context-projection.js +574 -0
  8. package/packages/agent-team/lib/context-source.js +72 -0
  9. package/packages/agent-team/lib/index.js +1258 -54
  10. package/packages/agent-team/lib/ledger.js +357 -26
  11. package/packages/agent-team/lib/member-context.js +7 -3
  12. package/packages/agent-team/lib/member-runtime.js +159 -4
  13. package/packages/agent-team/lib/pressure-policy.js +200 -0
  14. package/packages/agent-team/lib/progress-nudge.js +320 -0
  15. package/packages/agent-team/lib/spec.js +18 -0
  16. package/packages/agent-team/lib/typert.host.js +124 -42
  17. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  18. package/packages/agent-team/lib/typert.remote-client.js +39 -25
  19. package/packages/agent-team/lib/types/attachments.d.ts +1 -1
  20. package/packages/agent-team/lib/types/attachments.d.ts.map +1 -1
  21. package/packages/agent-team/lib/types/context-management.d.ts +142 -0
  22. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -0
  23. package/packages/agent-team/lib/types/context-projection.d.ts +219 -0
  24. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -0
  25. package/packages/agent-team/lib/types/context-source.d.ts +83 -0
  26. package/packages/agent-team/lib/types/context-source.d.ts.map +1 -0
  27. package/packages/agent-team/lib/types/index.d.ts +283 -2
  28. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  29. package/packages/agent-team/lib/types/ledger.d.ts +120 -7
  30. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  31. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/member-runtime.d.ts +30 -2
  33. package/packages/agent-team/lib/types/member-runtime.d.ts.map +1 -1
  34. package/packages/agent-team/lib/types/pressure-policy.d.ts +106 -0
  35. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -0
  36. package/packages/agent-team/lib/types/progress-nudge.d.ts +136 -0
  37. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  39. package/packages/agent-team/lib/types/types/entities.d.ts +32 -1
  40. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  41. package/packages/agent-team/lib/types/types/operations.d.ts +38 -3
  42. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  43. package/packages/agent-team/lib/types/types/requests-results.d.ts +54 -1
  44. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  45. package/packages/agent-team/preset/team-member/agent.cordis.yml +10 -2
  46. package/packages/client-agent-team/lib/client.js +283 -398
  47. package/packages/client-agent-team/lib/client.js.map +1 -1
  48. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts +1 -2
  49. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  50. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +61 -41
  51. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  52. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +3 -7
  53. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +3 -1
  54. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  55. package/packages/client-agent-team/lib/types/client/TeamComposer.js +37 -27
  56. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  57. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  58. package/packages/client-agent-team/lib/types/client/TeamConversation.js +2 -2
  59. package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.d.ts.map +1 -1
  60. package/packages/client-agent-team/lib/types/client/TeamMemberAvatar.js +3 -2
  61. package/packages/client-agent-team/lib/types/client/TeamMessage.js +5 -0
  62. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +2 -2
  63. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  64. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +4 -6
  65. package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts +14 -0
  66. package/packages/client-agent-team/lib/types/client/TeamStateDot.d.ts.map +1 -0
  67. package/packages/client-agent-team/lib/types/client/TeamStateDot.js +15 -0
  68. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts +1 -0
  69. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  70. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +41 -16
  71. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  72. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  73. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +2 -2
  74. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  75. package/packages/client-agent-team/lib/types/client/index.js +36 -78
  76. package/packages/client-agent-team/lib/types/client/locales.d.ts +0 -16
  77. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  78. package/packages/client-agent-team/lib/types/client/locales.js +0 -16
  79. package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts +1 -2
  80. package/packages/client-agent-team/lib/types/client/sidebar-drag.d.ts.map +1 -1
  81. package/packages/client-agent-team/lib/types/client/slots.d.ts +8 -1
  82. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  83. package/packages/client-agent-team/lib/types/client/task-refs.d.ts +7 -1
  84. package/packages/client-agent-team/lib/types/client/task-refs.d.ts.map +1 -1
  85. package/packages/client-agent-team/lib/types/client/task-refs.js +25 -3
  86. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +11 -10
  87. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  88. package/packages/client-agent-team/lib/types/client/team-formatters.js +14 -11
  89. package/packages/tool-agent-team/README.md +8 -5
  90. package/packages/tool-agent-team/README.zh.md +8 -5
  91. package/packages/tool-agent-team/lib/context-tools.js +179 -0
  92. package/packages/tool-agent-team/lib/index.js +144 -25
  93. package/packages/tool-agent-team/lib/types/context-tools.d.ts +16 -0
  94. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -0
  95. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
  96. package/packages/agent-team/lib/auto-compaction.js +0 -201
  97. package/packages/agent-team/lib/types/auto-compaction.d.ts +0 -47
  98. package/packages/agent-team/lib/types/auto-compaction.d.ts.map +0 -1
  99. package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts +0 -12
  100. package/packages/client-agent-team/lib/types/client/TeamMemberDock.d.ts.map +0 -1
  101. package/packages/client-agent-team/lib/types/client/TeamMemberDock.js +0 -13
  102. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts +0 -20
  103. package/packages/client-agent-team/lib/types/client/member-session-input.d.ts.map +0 -1
  104. package/packages/client-agent-team/lib/types/client/member-session-input.js +0 -110
@@ -1,7 +1,44 @@
1
1
  import { AgentTeamDmDeliveryError, markAgentTeamPreset } from '@wowyuarm/dsh-agent-team/host';
2
+ import { registerContextTools } from "./context-tools.js";
2
3
  import { defineTool } from '@deepseek-ai/dsh-tools';
3
4
  export const name = 'wowyuarm-agent-team-tools';
4
5
  export const inject = ['tools'];
6
+ function activityFactView(sequence, activity, markers) {
7
+ return {
8
+ sequence, kind: 'activity', activity: activity.kind, actor: activity.actor, taskRef: activity.taskRef,
9
+ ...(activity.claimRef === undefined ? {} : { claimRef: activity.claimRef }),
10
+ ...(activity.claimRefs === undefined || activity.claimRefs.length === 0 ? {} : { claimRefs: [...activity.claimRefs] }),
11
+ ...(activity.completedClaimRefs === undefined || activity.completedClaimRefs.length === 0 ? {} : { completedClaimRefs: [...activity.completedClaimRefs] }),
12
+ ...(activity.acceptedClaimRefs === undefined || activity.acceptedClaimRefs.length === 0 ? {} : { acceptedClaimRefs: [...activity.acceptedClaimRefs] }),
13
+ ...(activity.releasedClaimRefs === undefined || activity.releasedClaimRefs.length === 0 ? {} : { releasedClaimRefs: [...activity.releasedClaimRefs] }),
14
+ ...(markers === undefined ? {} : { unread: markers.unread, direct: markers.direct }),
15
+ };
16
+ }
17
+ function adviceView(advice) {
18
+ return {
19
+ ...(advice.usageTokens === undefined ? {} : { usageTokens: advice.usageTokens }),
20
+ ...(advice.taskBoundaryThreshold === undefined ? {} : { taskBoundaryThreshold: advice.taskBoundaryThreshold }),
21
+ ...(advice.handoffAt === undefined ? {} : { handoffAt: advice.handoffAt }),
22
+ ...(advice.hardLimit === undefined ? {} : { hardLimit: advice.hardLimit }),
23
+ action: advice.action, guidance: advice.guidance,
24
+ };
25
+ }
26
+ /** Render one structured activity fact as a self-describing decision-surface line. */
27
+ function activityLine(fact) {
28
+ const segments = [`${fact.sequence}`, fact.actor, fact.activity];
29
+ segments.push(`Task ${fact.taskRef}`);
30
+ if (fact.claimRef !== undefined)
31
+ segments.push(`Claim ${fact.claimRef}`);
32
+ if (fact.claimRefs !== undefined)
33
+ segments.push(`claims released ${fact.claimRefs.join(', ')}`);
34
+ if (fact.completedClaimRefs !== undefined)
35
+ segments.push(`completed claims ${fact.completedClaimRefs.join(', ')}`);
36
+ if (fact.acceptedClaimRefs !== undefined)
37
+ segments.push(`accepted claims ${fact.acceptedClaimRefs.join(', ')}`);
38
+ if (fact.releasedClaimRefs !== undefined)
39
+ segments.push(`released claims ${fact.releasedClaimRefs.join(', ')}`);
40
+ return segments.join(' ');
41
+ }
5
42
  function service(agent) {
6
43
  const host = agent.ctx.get('agentTeam');
7
44
  if (host === undefined)
@@ -30,8 +67,9 @@ const teamInbox = defineTool({
30
67
  taskNumber: { type: 'number' },
31
68
  } } },
32
69
  } },
33
- render: (_args, value) => [{ type: 'text', text: value.items.length === 0 ? 'No unread Team work.'
34
- : value.items.map(item => `${item.threadRef}${item.taskRef === undefined ? '' : ` · ${item.taskRef}`}${item.taskNumber === undefined ? '' : ` (#${item.taskNumber})`} · ${item.directCount > 0 ? 'direct' : 'unread'}, ${item.unreadCount} update(s), revision ${item.revision}`).join('\n') }],
70
+ render: (_args, value) => [{ type: 'text', text: value.items.length === 0 ? `No unread Team work.${value.totalUnreadCount > 0 ? ` (${value.totalUnreadCount} unread on Threads beyond this bounded list — call again with a larger limit.)` : ''}`
71
+ : [`${value.totalUnreadCount} unread update(s) total, ${value.totalDirectCount} direct, across ${value.items.length} Thread(s) shown${value.totalUnreadCount > value.items.reduce((sum, item) => sum + item.unreadCount, 0) ? ' more exist beyond this bounded list' : ''}`,
72
+ ...value.items.map(item => `${item.threadRef}${item.channelRef === undefined ? '' : ` · ${item.channelRef}`}${item.taskRef === undefined ? '' : ` · ${item.taskRef}`}${item.taskNumber === undefined ? '' : ` (#${item.taskNumber})`}${item.status === undefined ? '' : ` (${item.status})`} · ${item.unreadCount} unread, ${item.directCount} direct, revision ${item.revision}`)].join('\n') }],
35
73
  },
36
74
  async execute(args, exec) {
37
75
  const agent = exec.agent;
@@ -59,7 +97,7 @@ const teamThread = defineTool({
59
97
  description: 'Read or manage your Attention on one Thread. read acknowledges one chronological batch; history does not change read state. Prefer threadRef; taskRef is a compatibility alias when the Thread has a Task.',
60
98
  parameters: {
61
99
  action: { type: 'string', required: true, enum: ['status', 'follow', 'unfollow', 'read', 'history'] },
62
- threadRef: { type: 'string', description: "Full branded Thread ref exactly as returned by Team tools, including the 'thread:' prefix." },
100
+ 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." },
63
101
  taskRef: { type: 'string', description: "Optional Task ref alias for released clients. Prefer threadRef; if both are given they must identify the same Thread." },
64
102
  beforeSequence: { type: 'number' }, limit: { type: 'number' },
65
103
  },
@@ -75,14 +113,56 @@ const teamThread = defineTool({
75
113
  claimRef: { type: 'string', required: true }, direction: { type: 'string', required: true }, state: { type: 'string', required: true }, owner: { type: 'string', required: true },
76
114
  } } },
77
115
  facts: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: {
78
- sequence: { type: 'number', required: true }, kind: { type: 'string', required: true }, body: { type: 'string' }, sender: { type: 'string' }, mentions: { type: 'array', items: { type: 'string' } }, activity: { type: 'string' }, unread: { type: 'boolean' }, direct: { type: 'boolean' },
116
+ sequence: { type: 'number', required: true }, kind: { type: 'string', required: true }, body: { type: 'string' }, sender: { type: 'string' }, mentions: { type: 'array', items: { type: 'string' } }, activity: { type: 'string' }, actor: { type: 'string' }, taskRef: { type: 'string' }, claimRef: { type: 'string' }, claimRefs: { type: 'array', items: { type: 'string' } }, completedClaimRefs: { type: 'array', items: { type: 'string' } }, acceptedClaimRefs: { type: 'array', items: { type: 'string' } }, releasedClaimRefs: { type: 'array', items: { type: 'string' } }, unread: { type: 'boolean' }, direct: { type: 'boolean' },
79
117
  } } },
118
+ contextAdvice: { type: 'object', additionalProperties: false, properties: {
119
+ usageTokens: { type: 'number' }, taskBoundaryThreshold: { type: 'number' }, handoffAt: { type: 'number' }, hardLimit: { type: 'number' },
120
+ action: { type: 'string', required: true }, guidance: { type: 'string', required: true },
121
+ } },
80
122
  } },
81
- render: (_args, value) => [{ type: 'text', text: value.facts.length === 0
82
- ? `${value.threadRef} · revision ${value.revision}, following=${value.following}`
83
- : [`revision ${value.revision}`, ...value.facts.map(fact => fact.kind === 'message'
84
- ? `${fact.sequence} [${fact.sender ?? 'unknown sender'}] ${fact.body}`
85
- : `${fact.sequence} ${fact.activity}`)].join('\n') }],
123
+ // Renders are the only channel a tool result reaches the model through:
124
+ // the header states the Thread ref and the Task's standing, each activity
125
+ // line names the actor and every Claim the activity concluded, message
126
+ // facts carry their unread/direct markers so a bounded batch can be
127
+ // re-read discriminately, an acceptance the reader just acknowledged
128
+ // carries one context-guidance section, and read/history footers state
129
+ // what remains or whether older facts exist.
130
+ render: (_args, value) => {
131
+ // The header always identifies the Thread first — the ref the model
132
+ // must echo in its next team_message reply — then the Task's standing
133
+ // when the Thread is taskful. An empty-facts status/follow result
134
+ // still carries the same identifying surface.
135
+ const header = [
136
+ value.threadRef,
137
+ value.taskRef === undefined ? '' : `${value.taskRef} · ${value.status}${value.resolution === undefined ? '' : `/${value.resolution}`}`,
138
+ `revision ${value.revision}, following=${value.following}`,
139
+ ].filter(part => part !== '').join(' · ');
140
+ const lines = [header];
141
+ // The Claims snapshot is the collision surface: another Member's
142
+ // active Claim on this Task is invisible while facts alone render,
143
+ // yet exactly what the model must see before claiming its own angle.
144
+ for (const claim of value.claims)
145
+ lines.push(`Claim ${claim.claimRef} · ${claim.state} — ${claim.owner}: ${claim.direction}`);
146
+ // The anchor is the Thread's root task statement. Render it whenever
147
+ // it is not already among the facts, so a model reading a Thread for
148
+ // the first time never loses the original ask.
149
+ if (!value.facts.some(fact => fact.sequence === value.anchor.sequence))
150
+ lines.push(`Anchor ${value.anchor.sequence} [${value.anchor.sender}] ${value.anchor.body}`);
151
+ for (const fact of value.facts) {
152
+ lines.push(fact.kind === 'message'
153
+ ? `${fact.sequence} [${fact.sender ?? 'unknown sender'}]${fact.unread === undefined ? '' : fact.direct === true ? ' [direct]' : fact.unread === true ? ' [unread]' : ''} ${fact.body}`
154
+ : activityLine(fact));
155
+ if (fact.kind !== 'message' && fact.unread === true)
156
+ lines.push(`${fact.sequence} … (unread activity)`);
157
+ }
158
+ if (value.kind === 'read')
159
+ lines.push(`Read through sequence ${value.readThroughSequence}; ${value.remainingUnreadCount ?? 0} unread update(s) remaining — call team_thread read again${(value.remainingUnreadCount ?? 0) > 0 ? '' : ' when new work arrives'}.`);
160
+ if (value.kind === 'history')
161
+ lines.push(`History cursor ${value.cursor}; hasMore=${value.hasMore ? 'true' : 'false'}${value.hasMore ? ' — older facts exist; page again with beforeSequence set to the cursor.' : ' — no older facts remain.'}`);
162
+ if (value.kind === 'read' && value.contextAdvice !== undefined)
163
+ lines.push(...adviceLines(value.contextAdvice));
164
+ return [{ type: 'text', text: lines.join('\n') }];
165
+ },
86
166
  },
87
167
  async execute(args, exec) {
88
168
  const agent = exec.agent;
@@ -112,14 +192,14 @@ const teamThread = defineTool({
112
192
  const status = host.attentionStatusForAgent(agent, base);
113
193
  return threadResult('history', history, status.attention, history.facts.map(fact => fact.kind === 'message'
114
194
  ? { sequence: fact.sequence, kind: 'message', body: fact.message.body, sender: fact.message.sender, mentions: [...fact.mentions] }
115
- : { sequence: fact.sequence, kind: 'activity', activity: fact.activity.kind }), { cursor: history.cursor, hasMore: history.hasMore });
195
+ : activityFactView(fact.sequence, fact.activity)), { cursor: history.cursor, hasMore: history.hasMore });
116
196
  }
117
197
  if (args.beforeSequence !== undefined || args.limit !== undefined)
118
198
  throw new Error('read does not accept history arguments');
119
199
  const read = await host.readThreadForAgent(agent, { requestId: requestId(agent.id, exec.callId), ...base });
120
200
  return threadResult('read', read, read.attention, read.facts.map(entry => entry.fact.kind === 'message'
121
201
  ? { 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 }
122
- : { sequence: entry.fact.sequence, kind: 'activity', activity: entry.fact.activity.kind, unread: entry.unread, direct: entry.direct }), { readThroughSequence: read.readThroughSequence, remainingUnreadCount: read.remainingUnreadCount });
202
+ : activityFactView(entry.fact.sequence, entry.fact.activity, { unread: entry.unread, direct: entry.direct })), { readThroughSequence: read.readThroughSequence, remainingUnreadCount: read.remainingUnreadCount, ...(read.contextAdvice === undefined ? {} : { contextAdvice: adviceView(read.contextAdvice) }) });
123
203
  },
124
204
  });
125
205
  function threadResult(kind, snapshot, attention, facts, extra = {}) {
@@ -134,17 +214,25 @@ function threadResult(kind, snapshot, attention, facts, extra = {}) {
134
214
  facts,
135
215
  };
136
216
  }
217
+ /** Render one read-time acceptance advice; unavailable never prints a fabricated number. */
218
+ function adviceLines(advice) {
219
+ const measured = advice.usageTokens !== undefined && advice.taskBoundaryThreshold !== undefined && advice.handoffAt !== undefined && advice.hardLimit !== undefined;
220
+ const summary = measured
221
+ ? `${advice.usageTokens.toLocaleString('en-US')} tokens used; Task-boundary threshold ${advice.taskBoundaryThreshold.toLocaleString('en-US')}; normal handoff at ${advice.handoffAt.toLocaleString('en-US')}; hard limit ${advice.hardLimit.toLocaleString('en-US')}.`
222
+ : 'Context usage could not be measured for this acceptance.';
223
+ return [`Context guidance — ${summary}`, `Action: ${advice.action}. ${advice.guidance}`];
224
+ }
137
225
  const teamMessage = markAgentTeamPreset(defineTool({
138
226
  name: 'team_message',
139
227
  description: 'Start a top-level Thread, reply to an existing Thread, or send a direct message (DM). start defaults to a taskless Thread; pass asTask true to create a Task in the same send. Read the Thread first; replies require its current revision (an internal concurrency token carried by baseRevision, never quoted in bodies). 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.',
140
228
  parameters: {
141
229
  action: { type: 'string', required: true, enum: ['start', 'reply', 'dm'] },
142
- channelRef: { type: 'string', description: "Full branded Channel ref exactly as returned by Team tools, including the 'channel:' prefix." },
143
- threadRef: { type: 'string', description: "Full branded Thread ref exactly as returned by Team tools, including the 'thread:' prefix." },
144
- taskRef: { type: 'string', description: "Optional Task ref alias for reply on a Taskful Thread. Prefer threadRef." },
145
- memberRef: { type: 'string', description: "Full branded Member ref exactly as returned by Team tools, including the 'member:' prefix. Required for dm; the Member must be an enabled Agent in your Workspace (the Human cannot be DMed)." },
230
+ 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." },
231
+ 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." },
232
+ 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." },
233
+ 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)." },
146
234
  asTask: { type: 'boolean', description: 'When true, start creates a Task with the Thread. Default false creates a taskless Thread.' },
147
- 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. Spell each mentioned Member's handle in the prose so the mention renders inline." }, baseRevision: { type: 'number', description: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Thread. The revision is an internal concurrency token, not a citable fact." },
235
+ 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: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Thread. The revision is an internal concurrency token, not a citable fact." },
148
236
  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.' },
149
237
  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.' },
150
238
  },
@@ -155,8 +243,18 @@ const teamMessage = markAgentTeamPreset(defineTool({
155
243
  recipientMemberId: { type: 'string' }, recipientHandle: { type: 'string' }, delivered: { type: 'boolean' }, deliveryNote: { type: 'string' },
156
244
  } },
157
245
  render: (_args, value) => [{ type: 'text', text: value.kind === 'dm-sent' ? `DM ${value.delivered === false ? 'recorded but not delivered' : 'delivered'} to @${value.recipientHandle} (${value.recipientMemberId})${value.deliveryNote === undefined ? '' : `: ${value.deliveryNote}`}`
158
- : value.kind === 'committed' ? `Message ${value.messageRef} committed at revision ${value.revision}.`
159
- : `${value.kind}: ${value.memberIds?.join(', ') ?? `${value.threadRef ?? ''}${value.taskRef === undefined ? '' : ` · Task ${value.taskRef}`} revision ${value.revision ?? ''}`}` }],
246
+ : value.kind === 'committed' ? `Message ${value.messageRef} committed at revision ${value.revision} on ${value.threadRef}${value.taskRef === undefined ? '' : ` (${value.taskRef})`}.`
247
+ : value.kind === 'unread_required' ? `unread_required: ${value.threadRef}${value.taskRef === undefined ? '' : ` (${value.taskRef})`} has ${value.unreadCount} unread update(s), ${value.directCount} direct at revision ${value.revision}. Read the pending updates (team_thread read) before retrying this send.`
248
+ : value.kind === 'stale_revision' ? `stale_revision: your baseRevision ${value.expectedRevision} is obsolete; ${value.threadRef}${value.taskRef === undefined ? '' : ` (${value.taskRef})`} is now at revision ${value.revision}. Read the Thread, then retry with baseRevision ${value.revision}.`
249
+ : value.kind === 'member_not_following' ? `member_not_following: ${(value.memberIds ?? []).join(', ')} not following; the message was not committed. Only a Human can invite an unfollowed Agent — retry without mentioning them, or ask the Human.`
250
+ : `${value.kind}: ${value.memberIds?.join(', ') ?? `${value.threadRef ?? ''}${value.taskRef === undefined ? '' : ` · Task ${value.taskRef}`} revision ${value.revision ?? ''}`}` }],
251
+ // Minimal durable projection for the Host's context timeline: the
252
+ // structured outcome identity (never the render text). The effect-anchor
253
+ // fold reads `kind === 'committed'` + threadRef from the persisted
254
+ // tool/result meta — a start's Thread is born here, in the result.
255
+ presentationMeta: (_args, value) => value.kind === 'committed' && value.threadRef !== undefined
256
+ ? { kind: value.kind, threadRef: value.threadRef, ...(value.taskRef === undefined ? {} : { taskRef: value.taskRef }) }
257
+ : { kind: value.kind },
160
258
  },
161
259
  async execute(args, exec) {
162
260
  const agent = exec.agent;
@@ -225,9 +323,9 @@ const teamClaim = defineTool({
225
323
  description: 'List or mutate your Direction Claims. Read the Thread first; every mutation uses the current Thread revision. A Claim is your one-sentence direction statement on a Task — "the angle I am taking" — so others can spot collisions and track progress: Tasks define scope (owned by Humans), Claims declare the angle (owned by you). Good direction: "Unify the four form dialogs on shared field components before wiring submits." Bad direction: a multi-paragraph plan with step order, file lists, or acceptance criteria — those belong in Thread messages, not the Claim.',
226
324
  parameters: {
227
325
  action: { type: 'string', required: true, enum: ['list', 'claim', 'done', 'release'] },
228
- taskRef: { type: 'string', required: true, description: "Full branded Task ref exactly as returned by Team tools, including the 'task:' prefix." },
326
+ taskRef: { type: 'string', required: true, description: "Full branded Task ref exactly as returned by Team tools, including the 'task:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
229
327
  baseRevision: { type: 'number', description: "Positive integer; use the current Thread revision as shown by the latest team_inbox or team_thread result for this Task. The revision is an internal concurrency token, not a citable fact." }, direction: { type: 'string' },
230
- claimRef: { type: 'string', description: "Full branded Claim ref exactly as returned by team_claim, including the 'claim:' prefix." },
328
+ claimRef: { type: 'string', description: "Full branded Claim ref exactly as returned by team_claim, including the 'claim:' prefix. An unambiguous abbreviation of the first 6+ UUID hex characters also resolves." },
231
329
  },
232
330
  output: {
233
331
  schema: { type: 'object', additionalProperties: false, properties: {
@@ -236,8 +334,14 @@ const teamClaim = defineTool({
236
334
  unreadCount: { type: 'number' }, directCount: { type: 'number' },
237
335
  claims: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: { claimRef: { type: 'string', required: true }, direction: { type: 'string', required: true }, state: { type: 'string', required: true }, owner: { type: 'string', required: true } } } },
238
336
  } },
239
- render: (_args, value) => [{ type: 'text', text: [`${value.kind}: ${value.taskRef} · ${value.status}, revision ${value.revision}`,
240
- ...value.claims.map(claim => `${claim.claimRef} · ${claim.state} — ${claim.owner}: ${claim.direction}`)].join('\n') }],
337
+ render: (_args, value) => [{ type: 'text', text: [
338
+ value.kind === 'unread_required'
339
+ ? `unread_required: ${value.taskRef} (${value.threadRef}) has ${value.unreadCount} unread update(s), ${value.directCount} direct at revision ${value.revision}. Read the pending updates (team_thread read) before retrying this Claim mutation.`
340
+ : value.kind === 'stale_revision'
341
+ ? `stale_revision: your baseRevision ${value.expectedRevision} is obsolete; ${value.taskRef} (${value.threadRef}) is now at revision ${value.revision}. Read the Thread, then retry with baseRevision ${value.revision}.`
342
+ : `${value.kind}: ${value.taskRef} (${value.threadRef}) · ${value.status}, revision ${value.revision}`,
343
+ ...value.claims.map(claim => `${claim.claimRef} · ${claim.state} — ${claim.owner}: ${claim.direction}`)
344
+ ].join('\n') }],
241
345
  },
242
346
  async execute(args, exec) {
243
347
  const agent = exec.agent;
@@ -276,9 +380,9 @@ const teamClaim = defineTool({
276
380
  });
277
381
  const teamView = defineTool({
278
382
  name: 'team_view',
279
- description: 'Discover authorized Team Channels, Tasks, and Members. It is not a substitute for team_thread reading.',
383
+ description: 'Discover authorized Team Channels, top-level Threads, Tasks, and Members. It is not a substitute for team_thread reading.',
280
384
  parameters: {
281
- channelRef: { type: 'string', description: "Full branded Channel ref exactly as returned by Team tools, including the 'channel:' prefix." },
385
+ 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." },
282
386
  limit: { type: 'number' }, cursor: { type: 'number' },
283
387
  },
284
388
  output: {
@@ -287,15 +391,23 @@ const teamView = defineTool({
287
391
  members: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: {
288
392
  memberId: { type: 'string', required: true }, kind: { type: 'string', required: true }, handle: { type: 'string', required: true }, description: { type: 'string', required: true }, presence: { type: 'string', required: true },
289
393
  } } },
394
+ threads: { type: 'array', required: true, items: { type: 'object', additionalProperties: false, properties: {
395
+ threadRef: { type: 'string', required: true }, channelRef: { type: 'string', required: true }, revision: { type: 'number', required: true }, messageCount: { type: 'number', required: true },
396
+ taskRef: { type: 'string' }, status: { type: 'string' }, taskNumber: { type: 'number' },
397
+ } } },
290
398
  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 } } } },
291
399
  cursor: { type: 'number', required: true }, hasMore: { type: 'boolean', required: true },
292
400
  } },
293
401
  render: (_args, value) => [{ type: 'text', text: [
294
402
  ...value.channels.map(channel => `${channel.channelRef} · ${channel.name}`),
295
403
  ...value.members.map(m => `${m.memberId} · ${m.handle} (${m.kind}, ${m.presence})${m.description === '' ? '' : ` — ${m.description}`}`),
404
+ ...(value.threads.length > 0
405
+ ? value.threads.map(thread => `${thread.threadRef} · ${thread.channelRef}${thread.taskRef === undefined ? '' : ` · ${thread.taskRef}${thread.taskNumber === undefined ? '' : ` (#${thread.taskNumber})`} (${thread.status})`} · ${thread.messageCount} message(s), revision ${thread.revision}`)
406
+ : ['No Team Threads.']),
296
407
  ...(value.tasks.length > 0
297
- ? value.tasks.map(task => `${task.taskRef} · ${task.status}`)
408
+ ? value.tasks.map(task => `${task.taskRef} · ${task.threadRef} · ${task.channelRef} · ${task.status}, revision ${task.revision}`)
298
409
  : ['No Team Tasks.']),
410
+ `cursor ${value.cursor}, hasMore=${value.hasMore ? 'true' : 'false'}${value.hasMore ? ' — more items exist; call team_view again with cursor set to this value.' : ' — no further pages.'}`,
299
411
  ].join('\n') }],
300
412
  },
301
413
  async execute(args, exec) {
@@ -313,6 +425,12 @@ const teamView = defineTool({
313
425
  ...host.members().filter(status => visibleMemberIds.has(status.member.memberId)).map(status => ({ memberId: status.member.memberId,
314
426
  kind: 'agent', handle: status.member.handle, description: status.member.description, presence: status.presence })),
315
427
  ],
428
+ threads: view.items.map(item => {
429
+ const thread = item.thread;
430
+ const task = item.task;
431
+ return { threadRef: thread.threadRef, channelRef: item.message.channelRef, revision: thread.revision, messageCount: item.messageCount,
432
+ ...(task === undefined ? {} : { taskRef: task.taskRef, status: task.status, ...(item.taskNumber === undefined ? {} : { taskNumber: item.taskNumber }) }) };
433
+ }),
316
434
  tasks: view.tasks.map(task => ({ taskRef: task.taskRef, threadRef: task.threadRef, channelRef: task.channelRef,
317
435
  status: task.status, revision: view.threads.find(thread => thread.threadRef === task.threadRef)?.revision ?? 0 })),
318
436
  cursor: view.cursor, hasMore: view.hasMore,
@@ -325,4 +443,5 @@ export function apply(ctx) {
325
443
  ctx.tools.register(teamMessage);
326
444
  ctx.tools.register(teamClaim);
327
445
  ctx.tools.register(teamView);
446
+ registerContextTools(ctx);
328
447
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Model-facing context-management tools for Team Members. Thin adapters
3
+ * only: validation runs in the Host adapter, the successful result is the
4
+ * durable intent, and every lifecycle side effect — generation swap, Session
5
+ * creation, inbox handling — happens in the Host coordinator after the
6
+ * result is durably appended. `concludeTurn()` rides the success result of
7
+ * `context_rollover` and `context_checkpoint`, so sibling calls settle in model
8
+ * order before the turn closes.
9
+ * @module @wowyuarm/dsh-agent-team/context-tools
10
+ */
11
+ export declare function registerContextTools(ctx: {
12
+ readonly tools: {
13
+ register(tool: unknown): void;
14
+ };
15
+ }): void;
16
+ //# sourceMappingURL=context-tools.d.ts.map
@@ -0,0 +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 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAWlD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;AAwT/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAMxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAalD,eAAO,MAAM,IAAI,8BAA8B,CAAA;AAC/C,eAAO,MAAM,MAAM,UAAY,CAAA;AAmd/B,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAOxC"}
@@ -1,201 +0,0 @@
1
- import { ManualCompactionError } from '@deepseek-ai/dsh-compaction';
2
- /** Strict threshold: 200K exactly does not compact. */
3
- export const AUTO_COMPACTION_TOKEN_LIMIT = 200_000;
4
- /**
5
- * Suggested summary marker of the pre-compaction memory hint. Same shape as
6
- * the inbox and recovery notices so future turns can recognize it.
7
- */
8
- export const PRE_COMPACTION_NOTICE_SUMMARY = 'Compaction is imminent; consider persisting key conclusions.';
9
- /** Suggested pre-compaction hint body; writing is the Agent's own call. */
10
- export function preCompactionNoticeText() {
11
- return 'This session is about to be compacted, which will summarize away the current conversation detail. If there are durable conclusions worth keeping — validated facts, decisions, or reusable details — consider writing them to your memory or notes now. This is only a reminder: decide yourself whether anything is worth persisting, and do nothing if not. Do not start new work because of this message.';
12
- }
13
- /** Claim owners of a durable Human acceptance, including early-completed ones. */
14
- export function acceptedTaskCompactionMembers(operation) {
15
- if (operation.kind !== 'team/task-changed' || operation.actor.kind !== 'human' || operation.data.activity.kind !== 'accept')
16
- return undefined;
17
- return [...new Set(operation.data.claims.map(claim => claim.owner))];
18
- }
19
- /**
20
- * Small Host-side accepted-Task follow-up. This is deliberately not a generic
21
- * workflow/state-machine: a pending set deduplicates Members, an error map is
22
- * owned by the Host, and each worker is only whenIdle → measure → compactNow.
23
- */
24
- export class AutoCompactionCoordinator {
25
- options;
26
- pending = new Set();
27
- workers = new Map();
28
- controller = new AbortController();
29
- constructor(options) {
30
- this.options = options;
31
- }
32
- /** Queue all unique claim owners; unavailable Members stay pending. */
33
- schedule(memberIds) {
34
- for (const memberId of new Set(memberIds)) {
35
- this.pending.add(memberId);
36
- this.start(memberId);
37
- }
38
- }
39
- /** Activation/recovery calls this after a live handle becomes available. */
40
- activated(memberId) {
41
- this.start(memberId);
42
- }
43
- async dispose() {
44
- this.controller.abort();
45
- await Promise.all([...this.workers.values()].map(worker => worker.catch(() => { })));
46
- this.workers.clear();
47
- this.pending.clear();
48
- }
49
- start(memberId) {
50
- if (this.controller.signal.aborted || this.workers.has(memberId) || !this.pending.has(memberId))
51
- return;
52
- // No live handle is not a failure: member activation/recovery calls activated().
53
- if (this.options.agentForMember(memberId) === undefined)
54
- return;
55
- const worker = this.work(memberId).finally(() => { this.workers.delete(memberId); });
56
- this.workers.set(memberId, worker);
57
- }
58
- async work(memberId) {
59
- let reactivated = false;
60
- while (!this.controller.signal.aborted && this.pending.has(memberId)) {
61
- const agent = this.options.agentForMember(memberId);
62
- if (agent === undefined)
63
- return;
64
- try {
65
- if (!(await waitForIdleOrAbort(agent, this.controller.signal)))
66
- return;
67
- }
68
- catch (error) {
69
- this.fail(memberId, agent, `automatic compaction idle wait failed: ${describe(error)}`);
70
- return;
71
- }
72
- // A restart can replace the handle while it waited; restart the turn on
73
- // the current agent so measurement and compactNow share one scope.
74
- if (this.options.agentForMember(memberId) !== agent)
75
- continue;
76
- const meter = agent.ctx.get('tokenMeter');
77
- if (meter === undefined) {
78
- this.fail(memberId, agent, 'automatic compaction failed: tokenMeter is unavailable in the Member scope');
79
- return;
80
- }
81
- let before = meter.measure(agent.session).totalTokens;
82
- if (before <= AUTO_COMPACTION_TOKEN_LIMIT) {
83
- this.complete(memberId, agent);
84
- return;
85
- }
86
- // The session is over the threshold and about to be compacted: steer one
87
- // advisory hint so the Agent can persist its own key conclusions first.
88
- // The hint turn itself is ordinary agent work — its failure is contained
89
- // by the agent loop and never blocks compaction; only the fresh idle
90
- // boundary is awaited before the final measurement and compactNow.
91
- if (this.options.steerPreCompaction !== undefined) {
92
- try {
93
- this.options.steerPreCompaction(agent);
94
- }
95
- catch (error) {
96
- this.options.log(`pre-compaction memory hint failed: ${describe(error)} (member ${memberId}, session ${agent.id})`);
97
- }
98
- try {
99
- if (!(await waitForIdleOrAbort(agent, this.controller.signal)))
100
- return;
101
- }
102
- catch (error) {
103
- this.options.log(`pre-compaction hint idle wait failed: ${describe(error)} (member ${memberId}, session ${agent.id})`);
104
- }
105
- if (this.controller.signal.aborted)
106
- return;
107
- if (this.options.agentForMember(memberId) !== agent)
108
- continue;
109
- before = meter.measure(agent.session).totalTokens;
110
- if (before <= AUTO_COMPACTION_TOKEN_LIMIT) {
111
- this.complete(memberId, agent);
112
- return;
113
- }
114
- }
115
- const engine = this.options.compactionForAgent(agent);
116
- if (engine === undefined) {
117
- // A roster-subtree teardown (bundle-row reload, config hot-apply)
118
- // prunes the standing mount while this agent's scope binding still
119
- // names the dead key, so resolution can never succeed again for this
120
- // handle. One in-place re-activation rebuilds the binding from the
121
- // live roster; a preset that mounts no compaction row keeps failing
122
- // and lands in the terminal diagnostic below.
123
- if (!reactivated && await this.tryReactivate(memberId)) {
124
- reactivated = true;
125
- continue;
126
- }
127
- this.fail(memberId, agent, 'automatic compaction failed: compaction is unavailable in the Member scope');
128
- return;
129
- }
130
- try {
131
- const result = await engine.compactNow(agent, this.controller.signal);
132
- if (this.controller.signal.aborted)
133
- return;
134
- if (result === null) {
135
- this.fail(memberId, agent, `automatic compaction returned no compactable range above ${AUTO_COMPACTION_TOKEN_LIMIT} tokens`);
136
- return;
137
- }
138
- }
139
- catch (error) {
140
- if (this.controller.signal.aborted)
141
- return;
142
- if (error instanceof ManualCompactionError && error.code === 'busy')
143
- continue;
144
- this.fail(memberId, agent, `automatic compaction failed: ${describe(error)}`);
145
- return;
146
- }
147
- const after = meter.measure(agent.session).totalTokens;
148
- if (after >= before) {
149
- this.fail(memberId, agent, `automatic compaction did not reduce context (${before} → ${after} tokens)`);
150
- return;
151
- }
152
- this.options.cleared(memberId, agent.id);
153
- // Still over the strict threshold: next iteration waits at a fresh idle
154
- // boundary before attempting another compactNow.
155
- }
156
- }
157
- complete(memberId, agent) {
158
- this.pending.delete(memberId);
159
- this.options.cleared(memberId, agent.id);
160
- }
161
- tryReactivate(memberId) {
162
- return this.options.reactivate(memberId).catch(error => {
163
- this.options.log(`automatic compaction re-activation failed: ${describe(error)} (member ${memberId})`);
164
- return false;
165
- });
166
- }
167
- fail(memberId, agent, diagnostic) {
168
- this.pending.delete(memberId);
169
- this.options.log(`${diagnostic} (member ${memberId}, session ${agent.id})`);
170
- this.options.failed(memberId, agent.id, diagnostic);
171
- }
172
- }
173
- /** Abortable idle wait; the Agent owns its idle promise and is never cancelled. */
174
- function waitForIdleOrAbort(agent, signal) {
175
- const idle = agent.whenIdle();
176
- if (signal.aborted) {
177
- // The agent may settle or reject after teardown; keep that late outcome
178
- // observed without making it a coordinator failure.
179
- void idle.catch(() => { });
180
- return Promise.resolve(false);
181
- }
182
- return new Promise((resolve, reject) => {
183
- let settled = false;
184
- const finish = (outcome, error) => {
185
- if (settled)
186
- return;
187
- settled = true;
188
- signal.removeEventListener('abort', onAbort);
189
- if (outcome === 'error')
190
- reject(error);
191
- else
192
- resolve(outcome === 'idle');
193
- };
194
- const onAbort = () => { finish('aborted'); };
195
- signal.addEventListener('abort', onAbort, { once: true });
196
- idle.then(() => { finish('idle'); }, error => { finish('error', error); });
197
- });
198
- }
199
- function describe(error) {
200
- return error instanceof Error ? error.message : String(error);
201
- }
@@ -1,47 +0,0 @@
1
- import type { Agent } from '@deepseek-ai/dsh-agent';
2
- import { type CompactionEngine } from '@deepseek-ai/dsh-compaction';
3
- import type { AgentTeamMemberId, AgentTeamOperation } from './types.ts';
4
- /** Strict threshold: 200K exactly does not compact. */
5
- export declare const AUTO_COMPACTION_TOKEN_LIMIT = 200000;
6
- /**
7
- * Suggested summary marker of the pre-compaction memory hint. Same shape as
8
- * the inbox and recovery notices so future turns can recognize it.
9
- */
10
- export declare const PRE_COMPACTION_NOTICE_SUMMARY = "Compaction is imminent; consider persisting key conclusions.";
11
- /** Suggested pre-compaction hint body; writing is the Agent's own call. */
12
- export declare function preCompactionNoticeText(): string;
13
- /** Claim owners of a durable Human acceptance, including early-completed ones. */
14
- export declare function acceptedTaskCompactionMembers(operation: AgentTeamOperation): readonly AgentTeamMemberId[] | undefined;
15
- /**
16
- * Small Host-side accepted-Task follow-up. This is deliberately not a generic
17
- * workflow/state-machine: a pending set deduplicates Members, an error map is
18
- * owned by the Host, and each worker is only whenIdle → measure → compactNow.
19
- */
20
- export declare class AutoCompactionCoordinator {
21
- private readonly options;
22
- private readonly pending;
23
- private readonly workers;
24
- private readonly controller;
25
- constructor(options: {
26
- readonly agentForMember: (memberId: AgentTeamMemberId) => Agent | undefined;
27
- readonly compactionForAgent: (agent: Agent) => CompactionEngine | undefined;
28
- /** Rebuild one enabled Member in place from its persisted Session; false when it stays unusable. */
29
- readonly reactivate: (memberId: AgentTeamMemberId) => Promise<boolean>;
30
- readonly failed: (memberId: AgentTeamMemberId, sessionId: Agent['id'], diagnostic: string) => void;
31
- readonly cleared: (memberId: AgentTeamMemberId, sessionId: Agent['id']) => void;
32
- readonly log: (message: string) => void;
33
- /** Steer the pre-compaction memory hint; absent skips the hint entirely. */
34
- readonly steerPreCompaction?: (agent: Agent) => void;
35
- });
36
- /** Queue all unique claim owners; unavailable Members stay pending. */
37
- schedule(memberIds: readonly AgentTeamMemberId[]): void;
38
- /** Activation/recovery calls this after a live handle becomes available. */
39
- activated(memberId: AgentTeamMemberId): void;
40
- dispose(): Promise<void>;
41
- private start;
42
- private work;
43
- private complete;
44
- private tryReactivate;
45
- private fail;
46
- }
47
- //# sourceMappingURL=auto-compaction.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auto-compaction.d.ts","sourceRoot":"","sources":["../../src/auto-compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAG1F,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEvE,uDAAuD;AACvD,eAAO,MAAM,2BAA2B,SAAU,CAAA;AAElD;;;GAGG;AACH,eAAO,MAAM,6BAA6B,iEAAiE,CAAA;AAE3G,2EAA2E;AAC3E,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,kFAAkF;AAClF,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,kBAAkB,GAAG,SAAS,iBAAiB,EAAE,GAAG,SAAS,CAGrH;AAED;;;;GAIG;AACH,qBAAa,yBAAyB;IAKxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;IACtE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;gBAEtB,OAAO,EAAE;QACpC,QAAQ,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,KAAK,GAAG,SAAS,CAAA;QAC3E,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,gBAAgB,GAAG,SAAS,CAAA;QAC3E,oGAAoG;QACpG,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;QACtE,QAAQ,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;QAClG,QAAQ,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;QAC/E,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;QACvC,4EAA4E;QAC5E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KACrD;IAED,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,iBAAiB,EAAE,GAAG,IAAI;IAOvD,4EAA4E;IAC5E,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAItC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B,OAAO,CAAC,KAAK;YAQC,IAAI;IAuFlB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,IAAI;CAKb"}
@@ -1,12 +0,0 @@
1
- import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
- /** Public input-dock slot currency for the Member Session strip. */
3
- export type TeamMemberDockProps = PropsRuntime<'conversation.input.dock'> & PropsLocale<'team'>;
4
- /**
5
- * Team-owned strip above the shipped composer while a Member Session is
6
- * embedded. The shipped InputBar keeps the whole input surface (draft,
7
- * trigger menus, submit); this dock only carries what the shipped bar cannot
8
- * know — the Member-Session vocabulary hint and the Member turn's prompt
9
- * error, read through the standard useSession hook.
10
- */
11
- export declare function TeamMemberDock({ t, useSession }: TeamMemberDockProps): import("react").JSX.Element;
12
- //# sourceMappingURL=TeamMemberDock.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TeamMemberDock.d.ts","sourceRoot":"","sources":["../../../src/client/TeamMemberDock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAGjF,oEAAoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,yBAAyB,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAA;AAE/F;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,mBAAmB,+BAQpE"}
@@ -1,13 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import css from './composer.module.css';
3
- /**
4
- * Team-owned strip above the shipped composer while a Member Session is
5
- * embedded. The shipped InputBar keeps the whole input surface (draft,
6
- * trigger menus, submit); this dock only carries what the shipped bar cannot
7
- * know — the Member-Session vocabulary hint and the Member turn's prompt
8
- * error, read through the standard useSession hook.
9
- */
10
- export function TeamMemberDock({ t, useSession }) {
11
- const promptError = useSession(state => state.promptError ?? null);
12
- return _jsxs("div", { className: css.memberSessionDock, "data-team-member-dock": "true", children: [_jsx("span", { className: css.memberSessionHint, children: t('memberSessionHint') }), promptError !== null && (_jsx("p", { className: css.memberSessionStatus, role: "alert", children: promptError.error.message }))] });
13
- }