agentus 0.11.5 → 0.12.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Multi-session web cockpit for ACP-speaking coding agents (Qoder CLI / Hermes). UI has no intelligence — the agent lives in spawned CLI subprocesses.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -1387,9 +1387,14 @@ export class SessionManager {
|
|
|
1387
1387
|
// The agent has the block (a cancelled turn still received it): NOW the boundary is spent.
|
|
1388
1388
|
settleVoice();
|
|
1389
1389
|
this.#finalizePlan(sessionId, terminalState);
|
|
1390
|
+
// Turn END is the second and last ordering event of a turn (issue #50): start moved the session,
|
|
1391
|
+
// this settles it where the conversation now is. Mid-turn rows deliberately do NOT touch — see
|
|
1392
|
+
// #touch.
|
|
1393
|
+
this.#touch(s);
|
|
1390
1394
|
this.#emit({ t: "turn-end", sessionId, stopReason: res?.stopReason, durationMs: Date.now() - turnStartedAt });
|
|
1391
1395
|
} catch (err) {
|
|
1392
1396
|
this.#finalizePlan(sessionId, "failed");
|
|
1397
|
+
this.#touch(s);
|
|
1393
1398
|
this.#emit({ t: "turn-end", sessionId, error: errMessage(err), durationMs: Date.now() - turnStartedAt });
|
|
1394
1399
|
} finally {
|
|
1395
1400
|
s.busy = false;
|
|
@@ -2308,7 +2313,8 @@ export class SessionManager {
|
|
|
2308
2313
|
toolCallId: String(u.toolCallId ?? ""), createdAt: Date.now(),
|
|
2309
2314
|
});
|
|
2310
2315
|
if (up.isNew) {
|
|
2311
|
-
|
|
2316
|
+
// No clock move (issue #50): a tool call is work inside a turn, not a reason for the session to
|
|
2317
|
+
// jump to the top of the rail. The turn's start and end are the only two moves it gets.
|
|
2312
2318
|
this.#emit({ t: "message", message: up.message });
|
|
2313
2319
|
}
|
|
2314
2320
|
return;
|
|
@@ -2403,9 +2409,10 @@ export class SessionManager {
|
|
|
2403
2409
|
if (msg.kind === "agent" || msg.kind === "thought") {
|
|
2404
2410
|
const r = this.#store.appendTextChunk({ ...msg, kind: msg.kind });
|
|
2405
2411
|
if (r.delta || r.isNew) {
|
|
2406
|
-
// A row that did NOT move is not activity.
|
|
2407
|
-
//
|
|
2408
|
-
|
|
2412
|
+
// A row that did NOT move is not activity. Neither is one that DID move — a long reply arrives
|
|
2413
|
+
// as dozens of chunks, and touching per chunk re-sorted the rail on every token (issue #50:
|
|
2414
|
+
// three sessions in parallel swapped places continuously). Only the turn's start/end move the
|
|
2415
|
+
// clock; see #touch.
|
|
2409
2416
|
// One message = one row, so a row that GREW keeps its seq. A client that deduplicated frames
|
|
2410
2417
|
// by seq therefore dropped every chunk after the first one (measured: a phone bubble showing
|
|
2411
2418
|
// "不是" with the rest of the reply nowhere, and the next frame landing in an empty bubble).
|
|
@@ -2422,7 +2429,7 @@ export class SessionManager {
|
|
|
2422
2429
|
return;
|
|
2423
2430
|
}
|
|
2424
2431
|
const stored = this.#store.appendMessage(msg);
|
|
2425
|
-
|
|
2432
|
+
// Plan/other state rows are mid-turn noise for ordering (issue #50): stored, emitted, no clock move.
|
|
2426
2433
|
this.#emit({ t: "message", message: stored });
|
|
2427
2434
|
}
|
|
2428
2435
|
}
|
|
@@ -2831,7 +2838,18 @@ export class SessionManager {
|
|
|
2831
2838
|
/** Keep `lastAt` on the session ITSELF, not only on the list projection. A single-session
|
|
2832
2839
|
* payload (status change, title update, a rename response) built from `info` used to arrive
|
|
2833
2840
|
* without the field, so the client's copy dropped it and that session fell back to creation
|
|
2834
|
-
* order — the rail stopped moving a session up the moment you talked to it.
|
|
2841
|
+
* order — the rail stopped moving a session up the moment you talked to it.
|
|
2842
|
+
*
|
|
2843
|
+
* WHO may move the clock is the whole of issue #50. The rail sorts on this field, so every writer
|
|
2844
|
+
* is a potential re-sort the operator sees. Allowed: the operator's own prompt (he said something),
|
|
2845
|
+
* the END of a turn (the conversation settled somewhere new), and an approval request (the session
|
|
2846
|
+
* is now blocked on a human — a real state change, and rare). NOT allowed, and this is what used to
|
|
2847
|
+
* make the rail jitter: every agent text chunk, every tool call, plan/state rows, usage frames.
|
|
2848
|
+
* A long reply arrives as dozens of chunks; touching per chunk meant three parallel sessions swapped
|
|
2849
|
+
* places continuously, with rows moving out from under the pointer.
|
|
2850
|
+
*
|
|
2851
|
+
* A turn therefore moves its session at most twice — start and end — and its position inside the
|
|
2852
|
+
* turn is frozen, which is what a reader can actually follow. */
|
|
2835
2853
|
#touch(live: LiveSession, at = Date.now()): void {
|
|
2836
2854
|
live.info.lastAt = at;
|
|
2837
2855
|
// …and persist it: `lastAt` on the live object is only the projection the sockets see. The rail
|