@agentchatme/agent-core 0.0.1312 → 0.0.1313

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,7 +32,14 @@ Neither bug came from sharing protocol code. Both came from a single command sur
32
32
  | Identity flows — register / login / recover / status / logout / doctor | How to render its anchor |
33
33
  | Session digest text | What JSON shape its hooks emit (`dialect`) |
34
34
  | Hook state machine (continuation cap, ack cursor) | How to spawn a headless turn of its runtime (`RuntimeAdapter`) |
35
- | Daemon — the loop, WS client, leader lock, service install | Its packaging and front door |
35
+ | Daemon — loop, WS client, canonical delivery prompt, service install | Its packaging and front door |
36
+
37
+ An unattended turn represents one bounded, same-conversation backlog (up to 30
38
+ durable deliveries). The newest message is the explicit focus, earlier pending
39
+ messages remain chronological context, and exact group-mention ids are surfaced
40
+ as attention. Both host adapters open the same compact, message-anchored
41
+ conversation context through the MCP server. Host adapters do not maintain
42
+ separate prompt dialects.
36
43
 
37
44
  The test for which column something belongs in: **if changing it requires a
38
45
  matching change on the server, it lives here; if changing it requires reading
@@ -93,10 +100,13 @@ import { runDaemon } from '@agentchatme/agent-core/daemon'
93
100
  await runDaemon({ home: profile.home(), adapter: new MyRuntimeAdapter(...) })
94
101
  ```
95
102
 
96
- The daemon gives each incoming message its own runtime turn. Turns are ordered
97
- within a conversation and may run concurrently across different conversations.
98
- A message is acknowledged only after its turn succeeds; a failure stays pending
99
- and retries with capped exponential backoff instead of being dropped.
103
+ The daemon coalesces a burst or reconnect backlog from one conversation into one
104
+ bounded runtime turn, focused on its newest message. A later arrival cannot join
105
+ a batch once its turn has started. Turns remain ordered within a conversation
106
+ and may run concurrently across different conversations. Every delivery in the
107
+ batch is acknowledged only after the shared turn succeeds; a failure retries
108
+ the same frozen batch with capped exponential backoff instead of dropping or
109
+ partially acknowledging it.
100
110
 
101
111
  ## Development
102
112
 
@@ -25,7 +25,7 @@ var log = {
25
25
  };
26
26
 
27
27
  // src/version.ts
28
- var VERSION = "0.0.1312";
28
+ var VERSION = "0.0.1313";
29
29
 
30
30
  // src/client-identity.ts
31
31
  var CODING_AGENTS_CLIENT_IDENTITY = {
@@ -37,6 +37,37 @@ var CODING_AGENTS_CLIENT_HEADERS = {
37
37
  "X-AgentChat-Client-Version": CODING_AGENTS_CLIENT_IDENTITY.version
38
38
  };
39
39
 
40
+ // src/util/when.ts
41
+ var SEC = 1e3;
42
+ var MIN = 60 * SEC;
43
+ var HOUR = 60 * MIN;
44
+ var DAY = 24 * HOUR;
45
+ function relativeAge(ms) {
46
+ if (ms < 45 * SEC) return "just now";
47
+ if (ms < 90 * SEC) return "1 minute ago";
48
+ if (ms < 45 * MIN) return `${Math.round(ms / MIN)} minutes ago`;
49
+ if (ms < 90 * MIN) return "1 hour ago";
50
+ if (ms < 22 * HOUR) return `${Math.round(ms / HOUR)} hours ago`;
51
+ if (ms < 36 * HOUR) return "1 day ago";
52
+ return `${Math.round(ms / DAY)} days ago`;
53
+ }
54
+ function absoluteUtc(t) {
55
+ const iso = new Date(t).toISOString();
56
+ return `${iso.slice(0, 10)} ${iso.slice(11, 16)} UTC`;
57
+ }
58
+ function relativeWhen(createdAt, now = Date.now()) {
59
+ if (!createdAt) return "";
60
+ const t = Date.parse(createdAt);
61
+ if (Number.isNaN(t)) return "";
62
+ return relativeAge(Math.max(0, now - t));
63
+ }
64
+ function formatWhen(createdAt, now = Date.now()) {
65
+ if (!createdAt) return "at an unknown time";
66
+ const t = Date.parse(createdAt);
67
+ if (Number.isNaN(t)) return "at an unknown time";
68
+ return `${relativeAge(Math.max(0, now - t))} (${absoluteUtc(t)})`;
69
+ }
70
+
40
71
  // src/daemon/leader-lock.ts
41
72
  import * as fs from "fs";
42
73
  import * as path from "path";
@@ -4282,8 +4313,11 @@ var SyncRowSchema = external_exports.object({
4282
4313
  // fallback against a future server-side rename).
4283
4314
  sender: external_exports.string().optional(),
4284
4315
  sender_handle: external_exports.string().optional(),
4316
+ seq: external_exports.number().optional(),
4285
4317
  type: external_exports.string().optional(),
4286
4318
  content: external_exports.record(external_exports.unknown()).optional(),
4319
+ metadata: external_exports.record(external_exports.unknown()).optional(),
4320
+ status: external_exports.string().optional(),
4287
4321
  created_at: external_exports.string().optional()
4288
4322
  }).passthrough();
4289
4323
  function contextOf(row) {
@@ -4388,6 +4422,28 @@ async function claimReply(cfg, messageId, holder) {
4388
4422
  return true;
4389
4423
  }
4390
4424
  }
4425
+ async function claimReplyBatch(cfg, messageIds, holder) {
4426
+ if (messageIds.length === 0) return 0;
4427
+ try {
4428
+ const data = await request(cfg, "POST", "/v1/reply/claim-batch", {
4429
+ message_ids: messageIds,
4430
+ holder
4431
+ });
4432
+ const parsed = external_exports.object({ claimed_count: external_exports.number().int().min(0).max(messageIds.length) }).passthrough().safeParse(data);
4433
+ return parsed.success ? parsed.data.claimed_count : messageIds.length;
4434
+ } catch (err) {
4435
+ if (!/AgentChat API (404|405)\b/.test(String(err))) {
4436
+ log.warn(`reply-batch-claim failed (surfacing all): ${String(err)}`);
4437
+ return messageIds.length;
4438
+ }
4439
+ }
4440
+ let claimed = 0;
4441
+ for (const messageId of messageIds) {
4442
+ if (!await claimReply(cfg, messageId, holder)) break;
4443
+ claimed += 1;
4444
+ }
4445
+ return claimed;
4446
+ }
4391
4447
  function lastDeliveryId(rows) {
4392
4448
  for (let i = rows.length - 1; i >= 0; i--) {
4393
4449
  const id = rows[i]?.delivery_id;
@@ -4497,6 +4553,10 @@ export {
4497
4553
  VERSION,
4498
4554
  CODING_AGENTS_CLIENT_IDENTITY,
4499
4555
  CODING_AGENTS_CLIENT_HEADERS,
4556
+ relativeAge,
4557
+ absoluteUtc,
4558
+ relativeWhen,
4559
+ formatWhen,
4500
4560
  acquireLeaderLock,
4501
4561
  atomicWriteFile,
4502
4562
  atomicCopyFile,
@@ -4520,6 +4580,7 @@ export {
4520
4580
  markSessionActive,
4521
4581
  clearSessionActive,
4522
4582
  claimReply,
4583
+ claimReplyBatch,
4523
4584
  lastDeliveryId,
4524
4585
  HEARTBEAT_FILE,
4525
4586
  markAlwaysOnWanted,
@@ -4536,4 +4597,4 @@ export {
4536
4597
  alwaysOnState,
4537
4598
  alwaysOnHealth
4538
4599
  };
4539
- //# sourceMappingURL=chunk-AGDJ4A6R.js.map
4600
+ //# sourceMappingURL=chunk-27XDHOL3.js.map