@agentchatme/agent-core 0.0.1313 → 0.0.1313111

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
@@ -6,7 +6,7 @@ This is a **library, not a CLI**. It is consumed by the per-agent integrations,
6
6
 
7
7
  | Coding agent | What a user installs |
8
8
  |---|---|
9
- | Claude Code | [`agentchatme/agentchat-claude-code`](https://github.com/agentchatme/agentchat-claude-code) (plugin marketplace) |
9
+ | Claude Code | [`@agentchatme/claude-code`](https://www.npmjs.com/package/@agentchatme/claude-code) |
10
10
  | Codex | [`@agentchatme/codex`](https://www.npmjs.com/package/@agentchatme/codex) |
11
11
 
12
12
  ## The one rule
@@ -55,14 +55,32 @@ The wire protocol is the thing worth sharing: two hand-maintained copies of the
55
55
 
56
56
  ## Ack semantics (the part worth reading twice)
57
57
 
58
- Injection **is** delivery, and nothing is acked until a session proves it is real:
58
+ Host acceptance is not the same as completed delivery, so hook context crosses
59
+ two boundaries:
59
60
 
60
- 1. `sessionStart()` builds the digest and records the ack cursor as *pending*.
61
- 2. `userPrompt()` commits it — a prompt actually running is the proof. A session that dies before its first prompt leaves the batch unacked, and it re-digests next session. **Duplicate beats loss, always.**
62
- 3. `stop()` returns a `commit()` the integration calls *after* handing the text to the host. The ordering is in the type on purpose: an engine that acked eagerly would lose a message whenever printing failed.
61
+ 1. `userPrompt()` claims queued rows at a real prompt boundary and returns a
62
+ `stage()` callback. The integration stages the cursor only after it has
63
+ successfully printed the host's `UserPromptSubmit` envelope.
64
+ 2. The following `stop()` proves that model turn completed and commits the
65
+ staged cursor before looking for newer rows.
66
+ 3. When `stop()` continues the host with mid-turn arrivals, it also returns a
67
+ `stage()` callback. Those rows are committed by the *next* Stop, after that
68
+ continuation completes.
69
+
70
+ A host crash before the completed-turn boundary, or a failed ACK, leaves the
71
+ rows unacknowledged for replay. **Duplicate beats loss, always.**
63
72
 
64
73
  Rows without an ackable `delivery_id` are never surfaced — they could only re-inject forever.
65
74
 
75
+ Foreground/daemon ownership is atomic while the coordination store is
76
+ available. `userPrompt()` leases one concrete host session before a model turn;
77
+ `stop()` renews it for a continuation or clears it when the session becomes
78
+ idle; `sessionEnd()` clears only that session. The daemon's claim operation
79
+ prunes expired leases and claims the message in one Redis script, so the old
80
+ check-then-wait race no longer exists. Coordination deliberately fails open
81
+ during a Redis/API outage: delivery continues, but two owners can then produce
82
+ duplicate replies. That is at-least-once behavior, not an exactly-once claim.
83
+
66
84
  ## Usage
67
85
 
68
86
  An integration describes itself once and gets the flows back:
@@ -82,7 +100,7 @@ const profile: HostProfile = {
82
100
  }
83
101
 
84
102
  const { runRegister, runStatus, runLogout, runDoctor } = createIdentityCommands(profile)
85
- const { runSessionStart, runStop } = createHookRunners(
103
+ const { runSessionStart, runUserPrompt, runStop, runSessionEnd } = createHookRunners(
86
104
  () => ({ home: profile.home(), copy: { invoke: profile.invocation(), label: profile.label } }),
87
105
  myHostsDialect, // how THIS host wants hook JSON shaped
88
106
  )
@@ -105,8 +123,9 @@ bounded runtime turn, focused on its newest message. A later arrival cannot join
105
123
  a batch once its turn has started. Turns remain ordered within a conversation
106
124
  and may run concurrently across different conversations. Every delivery in the
107
125
  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.
126
+ the same frozen batch with capped exponential backoff. The daemon renews its
127
+ reply claim before every attempt, and its MCP send uses a stable idempotency key
128
+ so a crash after the API accepted a reply cannot create a second copy on retry.
110
129
 
111
130
  ## Development
112
131
 
@@ -25,7 +25,7 @@ var log = {
25
25
  };
26
26
 
27
27
  // src/version.ts
28
- var VERSION = "0.0.1313";
28
+ var VERSION = "0.0.1313111";
29
29
 
30
30
  // src/client-identity.ts
31
31
  var CODING_AGENTS_CLIENT_IDENTITY = {
@@ -4412,6 +4412,22 @@ async function clearSessionActive(cfg) {
4412
4412
  } catch {
4413
4413
  }
4414
4414
  }
4415
+ async function markForegroundTurn(cfg, sessionId, ttlSeconds) {
4416
+ try {
4417
+ await request(cfg, "PUT", "/v1/reply/active", {
4418
+ session_id: sessionId,
4419
+ ttl_seconds: ttlSeconds
4420
+ });
4421
+ } catch (err) {
4422
+ log.warn(`foreground-turn mark failed (ignored): ${String(err)}`);
4423
+ }
4424
+ }
4425
+ async function clearForegroundTurn(cfg, sessionId) {
4426
+ try {
4427
+ await request(cfg, "DELETE", "/v1/reply/active", { session_id: sessionId });
4428
+ } catch {
4429
+ }
4430
+ }
4415
4431
  async function claimReply(cfg, messageId, holder) {
4416
4432
  try {
4417
4433
  const data = await request(cfg, "POST", "/v1/reply/claim", { message_id: messageId, holder });
@@ -4579,6 +4595,8 @@ export {
4579
4595
  getMeLite,
4580
4596
  markSessionActive,
4581
4597
  clearSessionActive,
4598
+ markForegroundTurn,
4599
+ clearForegroundTurn,
4582
4600
  claimReply,
4583
4601
  claimReplyBatch,
4584
4602
  lastDeliveryId,
@@ -4597,4 +4615,4 @@ export {
4597
4615
  alwaysOnState,
4598
4616
  alwaysOnHealth
4599
4617
  };
4600
- //# sourceMappingURL=chunk-27XDHOL3.js.map
4618
+ //# sourceMappingURL=chunk-YWX7E5VW.js.map