agentus 0.11.4 → 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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/docs/installation.md +1 -1
- package/docs/installation.zh-CN.md +1 -1
- package/package.json +1 -1
- package/packages/server/src/acp/session-manager.ts +24 -6
- package/packages/web/dist/assets/{index-DKXkp6hP.js → index-DJwTjptq.js} +59 -59
- package/packages/web/dist/index.html +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ background process comes back as a turn of its own), an **ACP session that write
|
|
|
57
57
|
cockpit-side failure is diagnosable afterwards), and a **DeepSeek web backend** (search +
|
|
58
58
|
extract on the model key) — come from the fork's integration build instead. That is a five-line install:
|
|
59
59
|
[§ Which Hermes to run](docs/installation.md#which-hermes-to-run) — currently the tag
|
|
60
|
-
`agentus/v0.22.0/merge-20261023-
|
|
60
|
+
`agentus/v0.22.0/merge-20261023-0852`, on Hermes `v0.22.0`.
|
|
61
61
|
|
|
62
62
|
The first slot you start will use the Hermes home **your own agent already uses**
|
|
63
63
|
(`~/.hermes`) unless the backend row names another one — see "HERMES_HOME" below.
|
package/README.zh-CN.md
CHANGED
|
@@ -51,7 +51,7 @@ web bundle、配套 APK —— 然后直接退出,不启动任何东西)。
|
|
|
51
51
|
以及 **DeepSeek 的 web 后端**(搜索 + 正文抓取,共用模型 key)—— 来自 fork 的集成构建(tag)。
|
|
52
52
|
装法就五行:
|
|
53
53
|
[§ 该跑哪份 Hermes](docs/installation.zh-CN.md#该跑哪份-hermes) —— 当前是 tag
|
|
54
|
-
`agentus/v0.22.0/merge-20261023-
|
|
54
|
+
`agentus/v0.22.0/merge-20261023-0852`,基座 Hermes `v0.22.0`。
|
|
55
55
|
|
|
56
56
|
你启动的第一个 slot 会使用**你自己的 agent 已经在用的**那个 Hermes home(`~/.hermes`),除非后端那一行
|
|
57
57
|
指定了另一个 —— 见下面的「HERMES_HOME」。
|
package/docs/installation.md
CHANGED
|
@@ -60,7 +60,7 @@ ref and gets rebuilt, while a tag never moves — so pin the tag. The `agentus/`
|
|
|
60
60
|
ours apart from upstream's own tags (`v0.22.0`, `v0.22.0+canary.*`), and the timestamp in the
|
|
61
61
|
last segment sorts, so "newest" is a `sort -V`.
|
|
62
62
|
|
|
63
|
-
**Current integration build: `agentus/v0.22.0/merge-20261023-
|
|
63
|
+
**Current integration build: `agentus/v0.22.0/merge-20261023-0852`** — the newest tag on the fork,
|
|
64
64
|
built on Hermes `v0.22.0`. This line is for orientation only, not the source of truth: the
|
|
65
65
|
`TAG=$(…)` step below resolves the newest one on every run, so read it there if this sentence
|
|
66
66
|
ever looks stale.
|
|
@@ -52,7 +52,7 @@ agentus/<hermes 内部版本>/merge-<YYYYMMDD-HHMM>
|
|
|
52
52
|
tag。`agentus/` 这个前缀也把它和上游自己的 tag(`v0.22.0`、`v0.22.0+canary.*`)分开;最后一段是时间戳,
|
|
53
53
|
可排序,所以「最新」就是一次 `sort -V`。
|
|
54
54
|
|
|
55
|
-
**当前集成构建:`agentus/v0.22.0/merge-20261023-
|
|
55
|
+
**当前集成构建:`agentus/v0.22.0/merge-20261023-0852`** —— fork 上最新的那个 tag,基座 Hermes
|
|
56
56
|
`v0.22.0`。这行只为一眼看个大概,不是权威:下面的 `TAG=$(…)` 每次都会自己解析出最新,觉得这行过期就
|
|
57
57
|
以它为准。
|
|
58
58
|
|
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
|