agents-can-communicate 0.1.16 → 0.1.17

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-claude-code",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-codex",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-gemini-cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-kimi",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -73,14 +73,18 @@ to the command that answers it:
73
73
  - [request_stalled] message_x you asked and nobody is there -> ask someone else
74
74
  ```
75
75
 
76
- A turn is written to a byte budget, so it can end with
76
+ A turn is written to a byte budget, so it can end with one of these:
77
77
 
78
78
  ```text
79
79
  - +2 not shown, over budget; read them with `acc sync --scope full --json`
80
+ - ⚠ 1 message(s) addressed to you did not fit; run `acc sync --scope full --json`
80
81
  ```
81
82
 
82
- Run that. Two things were addressed to you and the turn had no room for them; they are
83
- not gone, and nobody will repeat them.
83
+ Run the sync. Both mean something addressed to you had no room this turn; it is not gone,
84
+ and nobody will repeat it. The `⚠` line is the one that has cost the most - a peer's
85
+ message, sometimes the very decision that unblocks you, held behind a reminder about your
86
+ own lapsed claim. When you see it, pull before anything else. And never tell your human you
87
+ are blocked on a peer without pulling first: the answer may already be queued.
84
88
 
85
89
  ## Work someone asked of you
86
90
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/adapter-sdk",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -6,7 +6,10 @@ const DEFAULT_BUDGET_BYTES = 6_000;
6
6
  // said only that something had been withheld, and nothing anywhere - not the
7
7
  // skills, not the docs - said how to see it. A turn that reports a thing the
8
8
  // reader cannot reach is how an agent ends up inventing its own way in.
9
- const NOTE_RESERVE = 80;
9
+ // Enough for the longest over-budget note - the escalated "message did not fit"
10
+ // line, which is longer than the plain "+N not shown" it replaces. Kept small
11
+ // enough that the note still fits beside a header at the smallest budgets.
12
+ const NOTE_RESERVE = 90;
10
13
  const FENCE = "```";
11
14
  // A peer cannot close a block it cannot name. The fence carries a marker that
12
15
  // is stripped from peer content, so forged delimiters stay inside the block.
@@ -167,11 +170,24 @@ export function projectContext(sync, { budgetBytes = DEFAULT_BUDGET_BYTES } = {}
167
170
  const claims = sync.claims ?? [];
168
171
 
169
172
  // Every entry is a group that appears whole or not at all. Single-line groups
170
- // may still be truncated - there is no fence in them to leave open.
173
+ // may still be truncated - there is no fence in them to leave open. `message`
174
+ // is carried so a dropped message can be counted apart from a dropped
175
+ // reminder: the two are not the same news.
176
+ //
177
+ // A peer message sits after "act now" attention (a direct request, an imminent
178
+ // conflict: priority <= 2) and ahead of standing reminders. The order is the
179
+ // fix for a real starvation: an expired-claim line (priority 6) regenerates
180
+ // from state every turn, while a message is delivered once and its receipt
181
+ // then stops it appearing - so a reminder that never clears must not keep
182
+ // pushing a one-time message into the over-budget overflow, turn after turn,
183
+ // where two agents each lost their most important message to it.
184
+ const urgent = attention.filter(item => item.priority <= 2);
185
+ const info = attention.filter(item => item.priority > 2);
171
186
  const required = [
172
- ...attentionLines(attention).map(line => [line]),
173
- ...claimLines(claims).map(line => [line]),
174
- ...peerBlocks(messages),
187
+ ...attentionLines(urgent).map(line => ({ lines: [line], message: false })),
188
+ ...peerBlocks(messages).map(block => ({ lines: block, message: true })),
189
+ ...attentionLines(info).map(line => ({ lines: [line], message: false })),
190
+ ...claimLines(claims).map(line => ({ lines: [line], message: false })),
175
191
  ];
176
192
  // Solo costs nothing: a lone session pays no visible price, and "no peers" is
177
193
  // still a cost when injected into every turn. But this is decided after the
@@ -198,27 +214,51 @@ export function projectContext(sync, { budgetBytes = DEFAULT_BUDGET_BYTES } = {}
198
214
  // Reserved so the note below always fits. Without it the projection could run
199
215
  // out of room to say that it ran out of room.
200
216
  const ceiling = budgetBytes - NOTE_RESERVE;
201
- let dropped = 0;
217
+ let droppedOther = 0;
218
+ let droppedMessages = 0;
219
+ const drop = group => { if (group.message) droppedMessages += 1; else droppedOther += 1; };
202
220
  for (const group of required) {
203
- if (group.length === 1) {
204
- const candidate = truncate(group[0], Math.max(0, ceiling - used - 1));
205
- if (candidate === "" || used + bytes(candidate) + 1 > ceiling) { dropped += 1; continue; }
221
+ const block = group.lines;
222
+ if (block.length === 1) {
223
+ const candidate = truncate(block[0], Math.max(0, ceiling - used - 1));
224
+ if (candidate === "" || used + bytes(candidate) + 1 > ceiling) { drop(group); continue; }
206
225
  lines.push(candidate);
207
226
  used += bytes(candidate) + 1;
208
227
  continue;
209
228
  }
210
- const size = group.reduce((total, line) => total + bytes(line) + 1, 0);
229
+ const size = block.reduce((total, line) => total + bytes(line) + 1, 0);
211
230
  // Skipped rather than stopped at: the groups are ordered by priority, and a
212
231
  // large message must not hide the shorter ones behind it.
213
- if (used + size > ceiling) { dropped += 1; continue; }
214
- lines.push(...group);
232
+ if (used + size > ceiling) { drop(group); continue; }
233
+ lines.push(...block);
215
234
  used += size;
216
235
  }
217
- if (dropped > 0) {
218
- const note = `- +${dropped} not shown, over budget; read them with `
219
- + "`acc sync --scope full --json`";
220
- lines.push(note);
221
- used += bytes(note) + 1;
236
+ // A dropped message is louder than a dropped reminder: "+N not shown" read as
237
+ // noise to two agents who each lost their most important message to it, so a
238
+ // message that did not fit says so specifically and names the command that
239
+ // recovers it. One note either way, escalated when a message is among the loss.
240
+ // The note is guarded against the budget, not merely reserved for: at a
241
+ // pathologically small budget the header alone can leave less room than the
242
+ // note needs, and a projection that overran the very budget it exists to
243
+ // respect is the bug this whole function is careful about. If the full note
244
+ // will not fit, the shortest imperative that does is still not silence.
245
+ const pushNote = note => {
246
+ const short = "- ⚠ over budget; `acc sync --scope full --json`";
247
+ for (const candidate of [note, short]) {
248
+ if (used + bytes(candidate) + 1 <= budgetBytes) {
249
+ lines.push(candidate);
250
+ used += bytes(candidate) + 1;
251
+ return;
252
+ }
253
+ }
254
+ };
255
+ if (droppedMessages > 0) {
256
+ // No count of the other drops: `--scope full` recovers everything.
257
+ pushNote(`- ⚠ ${droppedMessages} message(s) addressed to you did not fit; `
258
+ + "run `acc sync --scope full --json`");
259
+ } else if (droppedOther > 0) {
260
+ pushNote(`- +${droppedOther} not shown, over budget; read them with `
261
+ + "`acc sync --scope full --json`");
222
262
  }
223
263
 
224
264
  let shown = 0;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/core",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/hook-runner",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/installer",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": { ".": "./src/index.mjs" },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/mcp-server",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/protocol",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agents-can-communicate/storage-filesystem",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-can-communicate",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "description": "Local-first coordination for independently opened AI agent sessions.",
6
6
  "keywords": [