@cotal-ai/connector-core 0.41.4 → 0.43.0

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/dist/agent.d.ts CHANGED
@@ -139,6 +139,16 @@ export declare class MeshAgent extends EventEmitter {
139
139
  * to presence for peers. An absent key ⇒ that channel follows the global {@link _attention}. Reset
140
140
  * on restart (rebuilt from config; presence sweep clears the mirror). */
141
141
  private channelModes;
142
+ /** The turn relay's seat-side intake: every pulled-and-unyielded run turn, by goal id. Fed by
143
+ * {@link pollTurns}; surfaced into host context by {@link surfacePendingTurns}; drained by
144
+ * {@link yieldTurn} (explicit) and the working→idle boundary in {@link setStatus} (automatic
145
+ * `done`). The poll is also the reconciler: a turn settled elsewhere (deadline, another yield
146
+ * path) vanishes from `turn-pending` and is dropped here on the next pull. */
147
+ private activeTurns;
148
+ private turnPollTimer?;
149
+ /** The last pull failure this seat reported, so one that keeps failing is said once. */
150
+ private pullTrouble?;
151
+ private turnPollBusy;
142
152
  private _contextId;
143
153
  /** Chat-stream frontier captured when this agent entered `focus` — recall surfaces ambient
144
154
  * published after it ("since you entered focus"). Undefined unless in focus. */
@@ -466,6 +476,47 @@ export declare class MeshAgent extends EventEmitter {
466
476
  despawn(name?: string, opts?: {
467
477
  graceful?: boolean;
468
478
  }): Promise<ControlReply>;
479
+ private ensureTurnPoll;
480
+ /** Pull this seat's pending run turns from the manager (`turn-pending`, self-mode). New turns
481
+ * request a wake so the payload surfaces on the next injectable frame; turns gone from the
482
+ * reply were settled elsewhere (deadline, agent-down, a competing yield path) and are dropped.
483
+ * A seat with no manager in its space, or no self-service reach, gets a refused invoke and
484
+ * simply has no relay — silence, not an error, because most joined sessions are exactly that. */
485
+ private pollTurns;
486
+ /**
487
+ * A pull that did not come back, said ONCE.
488
+ *
489
+ * The poll runs every few seconds for the life of the session, so a line per failure would be a
490
+ * torrent and there was none at all instead: a seat whose relay had gone quiet looked exactly
491
+ * like a seat with no relay, and neither the operator nor the agent could tell which. The
492
+ * ordinary shapes stay silent, because most joined sessions genuinely have no manager to pull
493
+ * from and that is not trouble. Everything else is said once per distinct reason, and saying it
494
+ * again waits for the reason to change or for a pull to succeed.
495
+ */
496
+ private notePullTrouble;
497
+ /** Format every not-yet-surfaced turn as an injectable context block, WITHOUT marking anything
498
+ * (undefined when none wait). Two-phase on purpose, like the inbox's format-then-verdict rail:
499
+ * marking at format time would let a lost frame auto-yield `done` for work the model never
500
+ * saw. A caller commits with {@link commitSurfacedTurns} only once the injection verifiably
501
+ * reached the host. The payload is opaque relay bytes; when it parses as JSON with a string
502
+ * `context`, that rendered context is what the model reads, else the raw payload is shown. */
503
+ peekPendingTurns(): {
504
+ text: string;
505
+ goalIds: string[];
506
+ } | undefined;
507
+ /** Mark peeked turns as surfaced — the second phase, called once their injection verifiably
508
+ * reached the host. Surfacing is what arms the automatic `done` at the next turn boundary; a
509
+ * turn never committed re-surfaces on a later frame instead of yielding a lie. */
510
+ commitSurfacedTurns(goalIds: readonly string[]): void;
511
+ /** Yield one active turn back to the run (`turn-yield`, self-mode). Without `turn` it targets
512
+ * the OLDEST surfaced turn — the one the current session turn is working on. The entry is
513
+ * dropped locally only on a confirmed yield; a refused one stays for the poll to reconcile
514
+ * (the manager's answer, not a local guess, decides whether it is settled). */
515
+ yieldTurn(status: "done" | "blocked" | "handoff", opts?: {
516
+ to?: string;
517
+ note?: string;
518
+ turn?: string;
519
+ }): Promise<ControlReply>;
469
520
  /** Ask the manager to purge the space's retained chat backlog (its `purge` op). Cleanup only —
470
521
  * it doesn't touch live agents or the anycast work queue. `includeDms` also clears DM history. */
471
522
  purgeHistory(opts?: {
@@ -510,6 +561,23 @@ export declare class MeshAgent extends EventEmitter {
510
561
  /** Our last self-reported presence status. */
511
562
  get status(): PresenceStatus;
512
563
  setStatus(status: PresenceStatus, activity?: string): Promise<void>;
564
+ /**
565
+ * Publish presence for something that is NOT a turn ending.
566
+ *
567
+ * The boundary above reads working→idle as "the seat finished its turn", and that reading holds
568
+ * only at a real turn terminal. A session (re)start writes idle too: Claude Code fires
569
+ * `SessionStart` on compact, clear and resume, and an auto-compaction lands in the MIDDLE of a
570
+ * long turn. Routed through `setStatus` it yielded `done` for work the model had not finished,
571
+ * and the run moved on. An adapter uses this for every idle that is a lifecycle event rather
572
+ * than an ending.
573
+ */
574
+ resetStatus(status: PresenceStatus, activity?: string): Promise<void>;
575
+ private publishStatus;
576
+ /** The working→idle boundary: yield `done` for every SURFACED turn (its payload was in the
577
+ * context of the turn that just ended; ending without an explicit yield IS the done signal),
578
+ * then re-poll immediately so a queued turn wakes the seat without waiting out the cadence.
579
+ * Fire-and-forget from the presence path — a yield must never block a status write. */
580
+ private onTurnBoundary;
513
581
  /** Record the host's actual model and optional variant learned after launch, so peers see the
514
582
  * selection in `cotal_roster` and the web roster even when the operator never pinned one. Explicit
515
583
  * `model:` / `variant:` config wins; this only fills the gap. Best-effort presence mirror (no
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAOL,aAAa,EAQb,KAAK,YAAY,EAIjB,KAAK,QAAQ,EACb,KAAK,cAAc,EAEnB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;AAE3C;;;6DAG6D;AAC7D,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC;;;;;;8EAM8E;AAC9E,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC;;8BAE8B;AAC9B,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAItD;AAgCD,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;6EAMyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,kGAAkG;IAClG,UAAU,EAAE,OAAO,CAAC;IACpB,+FAA+F;IAC/F,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,0GAA0G;AAC1G,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,0GAA0G;AAC1G,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CASrE;AAmCD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAiBD;;;;;;;;;;;;;;;GAeG;AACH;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,cAAc,GAAG,SAAS,CAAC;AAmC/F,qBAAa,SAAU,SAAQ,YAAY;IACzC,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAE7B,OAAO,CAAC,KAAK,CAAiB;IAC9B;;;;;;oGAMgG;IAChG,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,cAAc,CAAqB;IAC3C;;8DAE0D;IAC1D,OAAO,CAAC,sBAAsB,CAA6D;IAC3F;wGACoG;IACpG,OAAO,CAAC,iBAAiB,CAA6B;IACtD;oDACgD;IAChD,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,oBAAoB,CAAS;IACrC;;6EAEyE;IACzE,OAAO,CAAC,oBAAoB,CAAqB;IACjD,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,+FAA+F;IAC/F,OAAO,CAAC,mBAAmB,CAAS;IACpC;;0CAEsC;IACtC,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC;sEACkE;IAClE,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC,OAAO,CAAC,iBAAiB,CAAmE;IAC5F,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAyB;IAC3C,OAAO,CAAC,aAAa,CAAiC;IACtD;;kEAE8D;IAC9D,OAAO,CAAC,cAAc,CAAqB;IAC3C;;;8EAG0E;IAC1E,OAAO,CAAC,YAAY,CAAkC;IACtD;;;;mFAI+E;IAC/E,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,aAAa,CAAC,CAAiC;IACvD,wFAAwF;IACxF,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAqB;IACvC;qFACiF;IACjF,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B;;;;;mGAK+F;IAC/F,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAChE,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,yBAAyB,CAAqB;IACtD,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,WAAW;IAuE/B,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,qGAAqG;IACrG,IAAI,kBAAkB,IAAI,OAAO,CAEhC;IAED,yGAAyG;IACzG,IAAI,eAAe,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,oEAAoE;IACpE,IAAI,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAE3C;IAED;;yGAEqG;IACrG,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;4FAEwF;IACxF,IAAI,eAAe,IAAI,eAAe,CAIrC;IAED;;oFAEgF;IAC1E,kBAAkB,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B3D,+EAA+E;IAC/E,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAKjD,4FAA4F;IAC5F,KAAK,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAItB,WAAW;IAsBnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB3B;;;;iGAI6F;IACvF,SAAS,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAkB5D,OAAO,CAAC,MAAM;IA+Fd,OAAO,CAAC,MAAM;IA8Ed,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,kBAAkB;IAa1B;;;;gDAI4C;IAC5C,OAAO,CAAC,WAAW;IAwBnB;sDACkD;IAClD,SAAS,CAAC,KAAK,GAAE,UAAkB,GAAG,SAAS,EAAE;IAIjD;;;;;;;;;;;;;kEAa8D;IAC9D,YAAY,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO;IAa7C;;;sGAGkG;IAClG,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI/B;mGAC+F;IAC/F,eAAe,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAS7C,8FAA8F;IAC9F,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,UAAkB,GAAG,SAAS,EAAE;IAclE;;;;;;iDAM6C;IAC7C,oBAAoB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB;IA8B/D,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,OAAO;IAIf;;gGAE4F;IAC5F,OAAO,CAAC,WAAW;IAUnB,UAAU,CAAC,KAAK,GAAE,UAAkB,GAAG,MAAM;IAI7C,kFAAkF;IAClF,yBAAyB,IAAI,MAAM,GAAG,SAAS;IAS/C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,IAAI,YAAY,IAAI,UAAU,CAE7B;IAED;;;;;;;OAOG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAIpC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,WAAW,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;IAI1C,oFAAoF;IACpF,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIpC;;;;;;;;OAQG;IACH,eAAe,IAAI,MAAM;IAIzB,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAInC;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAKvB;gCAC4B;IAC5B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,SAAS;IAK/D;;;0EAGsE;IACtE,oBAAoB,IAAI,MAAM;IAI9B;;;;;;0GAMsG;IACtG,WAAW,IAAI,MAAM;IAYrB;;;wFAGoF;IACpF,WAAW,IAAI,IAAI;IAMnB;qFACiF;IACjF,IAAI,SAAS,IAAI,aAAa,CAE7B;IAED,4FAA4F;IAC5F,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAItD,4EAA4E;IAC5E,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAIjD;;;;;;;;iDAQ6C;IACvC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlF;;;;;;kCAM8B;IACxB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BtD;;;;;;;;;iBASa;IACP,aAAa,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA0B3E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAOtF;;;;;OAKG;IACG,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAe3D;;;;;2DAKuD;IACvD,OAAO,CAAC,mBAAmB;IASrB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAKhE;;wEAEoE;IACpE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI3C,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IAUtF;;;;;;;;;;;kFAW8E;IACxE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAiDpM;6FACyF;IACnF,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAStG;;;;;;sEAMkE;YACpD,aAAa;IAyC3B;;;;;kGAK8F;YAChF,gBAAgB;IAS9B;;;;;;;4FAOwF;IAClF,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAYlF,OAAO,CAAC,cAAc;IAStB;;;;sGAIkG;YACpF,SAAS;IAsBvB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IASvB;;;;;mGAK+F;IAC/F,gBAAgB,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS;IAqBnE;;uFAEmF;IACnF,mBAAmB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAOrD;;;oFAGgF;IAC1E,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,EAAE,IAAI,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAgBxI;uGACmG;IAC7F,YAAY,CAAC,IAAI,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAM1E;;;;;;;;;;;;;;;;;;;+FAmB2F;IACrF,aAAa,CAAC,GAAG,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;KAAE,CAAC;IA8D9F;6CACyC;IACnC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAK3C,8FAA8F;IACxF,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAOtD,4CAA4C;IAC5C,MAAM,IAAI,QAAQ,EAAE;IAIpB,8CAA8C;IAC9C,IAAI,MAAM,IAAI,cAAc,CAE3B;IAEK,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzE;;;;;;;;;OASG;IACG,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAS7D,aAAa;IAK3B;;;4FAGwF;IACxF,OAAO,CAAC,cAAc;IAUtB;;;8EAG0E;IACpE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9D;;;;qFAIiF;IACjF,eAAe,IAAI,MAAM,GAAG,SAAS;IAUrC;oFACgF;IAChF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE;IAUnH,2EAA2E;IAC3E,cAAc,IAAI,MAAM,EAAE;IAI1B;;iEAE6D;IACvD,YAAY,IAAI,OAAO,CAC3B;QACE,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,EAAE,OAAO,CAAC;QAChB,eAAe,EAAE,OAAO,CAAC;QACzB,cAAc,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;QACvC,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,WAAW,GAAG,QAAQ,CAAC;KAC9B,EAAE,CACJ;IA6DD;;;;;2BAKuB;IACjB,WAAW,CACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAKtF,mEAAmE;IAC7D,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAO/D,OAAO,CAAC,GAAG;IAIX;;wEAEoE;YACtD,gBAAgB;IAI9B;;;;+EAI2E;IACrE,aAAa,CAAC,SAAS,GAAE,MAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxE;;;6DAGyD;IACzD,OAAO,CAAC,eAAe;IAmBvB;;qEAEiE;IACjE,OAAO,CAAC,mBAAmB;IAO3B;;uFAEmF;IACnF,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,GAAG;CAGZ;AAED,kGAAkG;AAClG,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAOrF"}
package/dist/agent.js CHANGED
@@ -83,6 +83,11 @@ const PROTECTED_DISPOSITION_CAP = 4096;
83
83
  /** Repeated async NATS status errors can arrive once per ordered-consumer retry. They describe one
84
84
  * fault, not one hundred useful facts; keep the first visible and summarize at most twice a minute. */
85
85
  const ENDPOINT_ERROR_LOG_WINDOW_MS = 30_000;
86
+ /** Cadence of the turn-pending pull while connected. The relay is PULL-shaped by design (the
87
+ * manager holds no DM machinery and a pushed relay could not authenticate its sender), so this
88
+ * poll is the intake's whole latency: a fresh turn waits at most one interval plus one wake.
89
+ * Deadlines are minutes-scale; fifteen seconds of intake lag is invisible to a run. */
90
+ const TURN_POLL_MS = 15_000;
86
91
  import { randomUUID } from "node:crypto";
87
92
  function sleep(ms) {
88
93
  return new Promise((r) => setTimeout(r, ms));
@@ -95,6 +100,40 @@ function sleep(ms) {
95
100
  function ingestDedupKey(id) {
96
101
  return id === "" ? undefined : id;
97
102
  }
103
+ /** An `ask` relayed as a turn: the record the run needs, the attempt it is on, the previous
104
+ * refusal when there was one, and the command that answers it (`cotal run answer`, the same door
105
+ * a checkpoint is answered through). Empty when the payload carries no ask. */
106
+ function renderAskRequest(p, seatName) {
107
+ const escalation = renderEscalation(p, seatName);
108
+ if (escalation !== "")
109
+ return escalation;
110
+ const ask = p.ask;
111
+ if (ask === null || typeof ask !== "object")
112
+ return "";
113
+ const a = ask;
114
+ const entries = a.schema !== null && typeof a.schema === "object" ? Object.entries(a.schema) : [];
115
+ const fields = entries.length === 0 ? "any record" : entries.map(([k, v]) => `${k}: ${String(v)}`).join(", ");
116
+ const by = typeof a.deadlineAt === "number" ? `, by ${new Date(a.deadlineAt).toISOString()}` : "";
117
+ const refused = typeof a.refused === "string" ? `\nYour last answer was refused: ${a.refused}` : "";
118
+ return `\nThis turn is an ask: the run needs a record from you at step ${String(p.step)} with fields ${fields}`
119
+ + ` (attempt ${String(a.attempt)} of ${String(a.attempts)}${by}).${refused}`
120
+ + `\nAnswer with: cotal run answer ${String(p.run)} ${String(p.step)} --by ${seatName} --value '<json record>'`;
121
+ }
122
+ /** An escalated `checkpoint` relayed as a turn: the question, the record wanted when the pause
123
+ * carries a schema, and the same answer command an ask uses. The runtime submitted this shape from
124
+ * the day escalations were relayed, and the seat read `ask` alone: the addressee was woken with a
125
+ * context block and no question, auto-yielded `done`, and the pause ran to its own expiry. */
126
+ function renderEscalation(p, seatName) {
127
+ const cp = p.checkpoint;
128
+ if (cp === null || typeof cp !== "object")
129
+ return "";
130
+ const c = cp;
131
+ const entries = c.schema !== null && typeof c.schema === "object" ? Object.entries(c.schema) : [];
132
+ const wanted = entries.length === 0 ? "" : `\nAnswer with a record with fields ${entries.map(([k, v]) => `${k}: ${String(v)}`).join(", ")}.`;
133
+ const by = typeof c.deadlineAt === "number" ? ` It expires at ${new Date(c.deadlineAt).toISOString()}.` : "";
134
+ return `\nThis turn is a checkpoint escalated to you at step ${String(p.step)}: ${String(c.prompt)}${by}${wanted}`
135
+ + `\nAnswer with: cotal run answer ${String(p.run)} ${String(p.step)} --by ${seatName} --value '<json>'`;
136
+ }
98
137
  export class MeshAgent extends EventEmitter {
99
138
  ep;
100
139
  config;
@@ -148,6 +187,16 @@ export class MeshAgent extends EventEmitter {
148
187
  * to presence for peers. An absent key ⇒ that channel follows the global {@link _attention}. Reset
149
188
  * on restart (rebuilt from config; presence sweep clears the mirror). */
150
189
  channelModes = new Map();
190
+ /** The turn relay's seat-side intake: every pulled-and-unyielded run turn, by goal id. Fed by
191
+ * {@link pollTurns}; surfaced into host context by {@link surfacePendingTurns}; drained by
192
+ * {@link yieldTurn} (explicit) and the working→idle boundary in {@link setStatus} (automatic
193
+ * `done`). The poll is also the reconciler: a turn settled elsewhere (deadline, another yield
194
+ * path) vanishes from `turn-pending` and is dropped here on the next pull. */
195
+ activeTurns = new Map();
196
+ turnPollTimer;
197
+ /** The last pull failure this seat reported, so one that keeps failing is said once. */
198
+ pullTrouble;
199
+ turnPollBusy = false;
151
200
  _contextId;
152
201
  /** Chat-stream frontier captured when this agent entered `focus` — recall surfaces ambient
153
202
  * published after it ("since you entered focus"). Undefined unless in focus. */
@@ -323,6 +372,7 @@ export class MeshAgent extends EventEmitter {
323
372
  await this.ep.start();
324
373
  // _connected is set by the endpoint's "connection" event (fired inside start()), not here.
325
374
  this.log(`connected to ${this.config.servers} as ${this.who()} in space "${this.config.space}" on #${this.config.subscribe.join(", #")}`);
375
+ this.ensureTurnPoll();
326
376
  }
327
377
  catch (e) {
328
378
  const error = e instanceof Error ? e : new Error(String(e));
@@ -339,6 +389,10 @@ export class MeshAgent extends EventEmitter {
339
389
  }
340
390
  async stop() {
341
391
  this._stopping = true;
392
+ if (this.turnPollTimer !== undefined) {
393
+ clearInterval(this.turnPollTimer);
394
+ this.turnPollTimer = undefined;
395
+ }
342
396
  // stop() is a local terminal fact. Do not wait for an endpoint event that intentionally ignores
343
397
  // its own stopped close, or leave a cleanly stopped session reporting either state as live.
344
398
  this._connected = false;
@@ -887,7 +941,10 @@ export class MeshAgent extends EventEmitter {
887
941
  * Subsumes {@link directedPendingCount}: in `dnd`/`focus` (no override) the open term is false, so it
888
942
  * equals the directed count; in `open` it adds normal ambient but excludes quiet-channel ambient. */
889
943
  pendingWake() {
890
- return this.inbox.filter((p) => {
944
+ // An unsurfaced run turn is directed-strength: it wakes regardless of attention, exactly like
945
+ // a DM — a run is waiting on this seat, and holding it costs the run its deadline.
946
+ const turns = [...this.activeTurns.values()].filter((t) => !t.surfaced).length;
947
+ return turns + this.inbox.filter((p) => {
891
948
  const it = p.item;
892
949
  if (p.pullOnly)
893
950
  return false;
@@ -1221,6 +1278,131 @@ export class MeshAgent extends EventEmitter {
1221
1278
  return resolved.error;
1222
1279
  return this.managerInvoke("despawn", { graceful }, { target: resolved.target });
1223
1280
  }
1281
+ // ---- the turn relay (seat side) ------------------------------------------------------------
1282
+ ensureTurnPoll() {
1283
+ if (this.turnPollTimer !== undefined)
1284
+ return;
1285
+ const t = setInterval(() => {
1286
+ void this.pollTurns().catch((e) => this.notePullTrouble(e.message));
1287
+ }, TURN_POLL_MS);
1288
+ t.unref?.();
1289
+ this.turnPollTimer = t;
1290
+ }
1291
+ /** Pull this seat's pending run turns from the manager (`turn-pending`, self-mode). New turns
1292
+ * request a wake so the payload surfaces on the next injectable frame; turns gone from the
1293
+ * reply were settled elsewhere (deadline, agent-down, a competing yield path) and are dropped.
1294
+ * A seat with no manager in its space, or no self-service reach, gets a refused invoke and
1295
+ * simply has no relay — silence, not an error, because most joined sessions are exactly that. */
1296
+ async pollTurns() {
1297
+ if (!this._connected || this._stopping || this.turnPollBusy)
1298
+ return;
1299
+ this.turnPollBusy = true;
1300
+ try {
1301
+ const r = await this.managerInvoke("turn-pending", undefined, { target: { mode: "self" } });
1302
+ if (!r.ok) {
1303
+ this.notePullTrouble(r.error ?? "refused with no message");
1304
+ return;
1305
+ }
1306
+ this.pullTrouble = undefined;
1307
+ const turns = r.data?.turns ?? [];
1308
+ const live = new Set(turns.map((t) => t.goalId));
1309
+ for (const id of [...this.activeTurns.keys()])
1310
+ if (!live.has(id))
1311
+ this.activeTurns.delete(id);
1312
+ let fresh = 0;
1313
+ for (const t of turns) {
1314
+ if (this.activeTurns.has(t.goalId))
1315
+ continue;
1316
+ this.activeTurns.set(t.goalId, { goalId: t.goalId, payload: t.payload, acceptedAt: t.acceptedAt, deadlineAt: t.deadlineAt, surfaced: false });
1317
+ fresh += 1;
1318
+ }
1319
+ if (fresh > 0)
1320
+ this.requestWake();
1321
+ }
1322
+ finally {
1323
+ this.turnPollBusy = false;
1324
+ }
1325
+ }
1326
+ /**
1327
+ * A pull that did not come back, said ONCE.
1328
+ *
1329
+ * The poll runs every few seconds for the life of the session, so a line per failure would be a
1330
+ * torrent and there was none at all instead: a seat whose relay had gone quiet looked exactly
1331
+ * like a seat with no relay, and neither the operator nor the agent could tell which. The
1332
+ * ordinary shapes stay silent, because most joined sessions genuinely have no manager to pull
1333
+ * from and that is not trouble. Everything else is said once per distinct reason, and saying it
1334
+ * again waits for the reason to change or for a pull to succeed.
1335
+ */
1336
+ notePullTrouble(reason) {
1337
+ // "Nobody answered" is the no-relay case this poll expects, and the boot window is a manager
1338
+ // telling the seat to come back — both resolve themselves and neither is worth a line.
1339
+ if (/no responder answered|still reconciling/i.test(reason))
1340
+ return;
1341
+ if (this.pullTrouble === reason)
1342
+ return;
1343
+ this.pullTrouble = reason;
1344
+ this.log(`the run-turn pull is not answering (${reason}); retrying every ${TURN_POLL_MS}ms`);
1345
+ }
1346
+ /** Format every not-yet-surfaced turn as an injectable context block, WITHOUT marking anything
1347
+ * (undefined when none wait). Two-phase on purpose, like the inbox's format-then-verdict rail:
1348
+ * marking at format time would let a lost frame auto-yield `done` for work the model never
1349
+ * saw. A caller commits with {@link commitSurfacedTurns} only once the injection verifiably
1350
+ * reached the host. The payload is opaque relay bytes; when it parses as JSON with a string
1351
+ * `context`, that rendered context is what the model reads, else the raw payload is shown. */
1352
+ peekPendingTurns() {
1353
+ const waiting = [...this.activeTurns.values()].filter((t) => !t.surfaced).sort((a, b) => a.acceptedAt - b.acceptedAt);
1354
+ if (!waiting.length)
1355
+ return undefined;
1356
+ const blocks = waiting.map((t) => {
1357
+ let context = t.payload;
1358
+ let ask = "";
1359
+ try {
1360
+ const p = JSON.parse(t.payload);
1361
+ if (typeof p.context === "string" && p.context.length > 0)
1362
+ context = p.context;
1363
+ ask = renderAskRequest(p, this.config.name);
1364
+ }
1365
+ catch { /* opaque payload — surface it as it came */ }
1366
+ return `— turn ${t.goalId} (deadline ${new Date(t.deadlineAt).toISOString()}):\n${context}${ask}`;
1367
+ });
1368
+ const text = `🎯 Cotal — a run handed you ${waiting.length === 1 ? "its turn" : `${waiting.length} turns`}:\n` +
1369
+ `${blocks.join("\n")}\n` +
1370
+ `(Do the work now with your own tools. Ending your turn yields "done" back to the run automatically; ` +
1371
+ `call cotal_yield only when you are blocked or handing the turn to another agent.)`;
1372
+ return { text, goalIds: waiting.map((t) => t.goalId) };
1373
+ }
1374
+ /** Mark peeked turns as surfaced — the second phase, called once their injection verifiably
1375
+ * reached the host. Surfacing is what arms the automatic `done` at the next turn boundary; a
1376
+ * turn never committed re-surfaces on a later frame instead of yielding a lie. */
1377
+ commitSurfacedTurns(goalIds) {
1378
+ for (const id of goalIds) {
1379
+ const t = this.activeTurns.get(id);
1380
+ if (t)
1381
+ t.surfaced = true;
1382
+ }
1383
+ }
1384
+ /** Yield one active turn back to the run (`turn-yield`, self-mode). Without `turn` it targets
1385
+ * the OLDEST surfaced turn — the one the current session turn is working on. The entry is
1386
+ * dropped locally only on a confirmed yield; a refused one stays for the poll to reconcile
1387
+ * (the manager's answer, not a local guess, decides whether it is settled). */
1388
+ async yieldTurn(status, opts = {}) {
1389
+ await this.requireConnected();
1390
+ const t = opts.turn !== undefined
1391
+ ? this.activeTurns.get(opts.turn)
1392
+ : [...this.activeTurns.values()].filter((x) => x.surfaced).sort((a, b) => a.acceptedAt - b.acceptedAt)[0];
1393
+ if (!t)
1394
+ return { ok: false, error: opts.turn !== undefined ? `no active turn "${opts.turn}" on this seat` : "no turn is active — nothing to yield" };
1395
+ // The surfaced gate holds for an explicit id too: a yield for a payload the session has not
1396
+ // been shown would record work nobody did.
1397
+ if (!t.surfaced)
1398
+ return { ok: false, error: `turn "${t.goalId}" has not been surfaced into this session yet; nothing was seen, so nothing can be yielded for it` };
1399
+ if (status === "handoff" && (opts.to === undefined || opts.to.length === 0))
1400
+ return { ok: false, error: "a handoff yield names its addressee (to)" };
1401
+ const r = await this.managerInvoke("turn-yield", { goalId: t.goalId, status, to: opts.to, note: opts.note }, { target: { mode: "self" } });
1402
+ if (r.ok)
1403
+ this.activeTurns.delete(t.goalId);
1404
+ return r;
1405
+ }
1224
1406
  /** Ask the manager to purge the space's retained chat backlog (its `purge` op). Cleanup only —
1225
1407
  * it doesn't touch live agents or the anycast work queue. `includeDms` also clears DM history. */
1226
1408
  async purgeHistory(opts) {
@@ -1331,11 +1513,62 @@ export class MeshAgent extends EventEmitter {
1331
1513
  }
1332
1514
  async setStatus(status, activity) {
1333
1515
  await this.requireConnected();
1334
- this._status = status;
1516
+ const prev = this._status;
1517
+ try {
1518
+ await this.publishStatus(status, activity);
1519
+ }
1520
+ finally {
1521
+ // The transition is a fact about the SEAT, not about whether its presence row was written:
1522
+ // assigning before the writes meant one failed publish (which every adapter swallows) left
1523
+ // `_status` idle with no boundary run, and the next real turn end saw no transition at all.
1524
+ this._status = status;
1525
+ // The turn relay's boundary: an adapter funnels its turn-end through this transition (Stop
1526
+ // hooks set idle), so the automatic `done` yield and the immediate re-poll live here once
1527
+ // instead of per connector. `waiting` is not a boundary — a seat blocked on a permission has
1528
+ // not finished, and its deadline is what bounds a stuck one.
1529
+ if (prev === "working" && status === "idle")
1530
+ this.onTurnBoundary();
1531
+ }
1532
+ }
1533
+ /**
1534
+ * Publish presence for something that is NOT a turn ending.
1535
+ *
1536
+ * The boundary above reads working→idle as "the seat finished its turn", and that reading holds
1537
+ * only at a real turn terminal. A session (re)start writes idle too: Claude Code fires
1538
+ * `SessionStart` on compact, clear and resume, and an auto-compaction lands in the MIDDLE of a
1539
+ * long turn. Routed through `setStatus` it yielded `done` for work the model had not finished,
1540
+ * and the run moved on. An adapter uses this for every idle that is a lifecycle event rather
1541
+ * than an ending.
1542
+ */
1543
+ async resetStatus(status, activity) {
1544
+ await this.requireConnected();
1545
+ try {
1546
+ await this.publishStatus(status, activity);
1547
+ }
1548
+ finally {
1549
+ this._status = status;
1550
+ }
1551
+ }
1552
+ async publishStatus(status, activity) {
1335
1553
  if (activity !== undefined)
1336
1554
  await this.ep.setActivity(activity);
1337
1555
  await this.ep.setStatus(status);
1338
1556
  }
1557
+ /** The working→idle boundary: yield `done` for every SURFACED turn (its payload was in the
1558
+ * context of the turn that just ended; ending without an explicit yield IS the done signal),
1559
+ * then re-poll immediately so a queued turn wakes the seat without waiting out the cadence.
1560
+ * Fire-and-forget from the presence path — a yield must never block a status write. */
1561
+ onTurnBoundary() {
1562
+ for (const t of [...this.activeTurns.values()]) {
1563
+ if (!t.surfaced)
1564
+ continue;
1565
+ void this.yieldTurn("done", { turn: t.goalId })
1566
+ .then((r) => { if (!r.ok)
1567
+ this.log(`turn ${t.goalId} auto-yield: ${r.error ?? "refused"}`); })
1568
+ .catch((e) => this.log(`turn ${t.goalId} auto-yield: ${e.message}`));
1569
+ }
1570
+ void this.pollTurns().catch(() => { });
1571
+ }
1339
1572
  /** Record the host's actual model and optional variant learned after launch, so peers see the
1340
1573
  * selection in `cotal_roster` and the web roster even when the operator never pinned one. Explicit
1341
1574
  * `model:` / `variant:` config wins; this only fills the gap. Best-effort presence mirror (no