antechamber 0.2.27 → 0.2.29

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/CHANGELOG.md CHANGED
@@ -7,10 +7,22 @@ and this project uses [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.29] - 2026-10-19
11
+
12
+ ### Fixed
13
+
14
+ - Keep compaction markers before the replies that follow them, both live and after reopening a conversation.
15
+
16
+ ## [0.2.28] - 2026-10-18
17
+
18
+ - fix(session): keep replies visible after compaction (#37)
19
+
10
20
  ## [0.2.27] - 2026-10-18
11
21
 
12
22
  ### Fixed
13
23
 
24
+ - Keep new replies and tool activity visible after compaction in long conversations by retaining their original
25
+ prompt in paged history.
14
26
  - Keep a subagent and its parent session shown as running when OmO resumes the subagent on its own after its turn
15
27
  ended while its background work ran, and keep the subagent's transcript up to its final reply.
16
28
 
@@ -255,6 +255,16 @@ export class PiEventTranslator {
255
255
  }
256
256
  s.activeUserMessageID = messageID;
257
257
  const input = s.inputs?.get(messageID);
258
+ if (ev.type === "message_start" || (input && !input.delivered)) {
259
+ const messages = s.messages ?? [];
260
+ const boundary = messages.findIndex((item) => item.info.id === s.tree.revert?.messageID);
261
+ const compaction = messages.findLast((item, index) => (boundary < 0 || index < boundary) && item.parts.some((part) => part.type === "compaction"));
262
+ // Optimistic queued prompts can precede compactions that happened before delivery.
263
+ if (compaction)
264
+ (s.deliveredInputCompactions ??= new Map()).set(messageID, compaction.info.id);
265
+ else
266
+ s.deliveredInputCompactions?.delete(messageID);
267
+ }
258
268
  if (input && !input.delivered) {
259
269
  input.delivered = true;
260
270
  if (input.accepted)
@@ -519,15 +529,23 @@ export class PiEventTranslator {
519
529
  // Trust that over our snapshot, which goes stale whenever pi switches on
520
530
  // its own side (subagent routing, an in-session /model, a resumed file).
521
531
  this.services.applyPiModel(s, msg.provider, piModelId(msg.responseModel, msg.model));
522
- const parent = s.messages?.findLast((m) => m.info.role === "user");
532
+ const messages = s.messages ?? [];
533
+ const inputID = typeof ev.clientMessageId === "string"
534
+ ? ev.clientMessageId
535
+ : (s.activeUserMessageID ?? messages.findLast((m) => m.info.role === "user")?.info.id ?? "");
536
+ const inputIndex = Math.max(messages.findIndex((m) => m.info.id === inputID), messages.findIndex((m) => m.info.id === s.deliveredInputCompactions?.get(inputID)));
537
+ const boundary = messages.findIndex((m) => m.info.id === s.tree.revert?.messageID);
538
+ // A compaction starts a display turn without changing the native prompt's identity.
539
+ const compaction = messages.findLast((m, index) => index > inputIndex &&
540
+ (boundary < 0 || index < boundary) &&
541
+ m.info.role === "user" &&
542
+ m.parts.some((part) => part.type === "compaction"));
523
543
  const assistant = {
524
544
  id: id("msg"),
525
545
  sessionID: s.info.id,
526
546
  role: "assistant",
527
547
  time: { created: Date.now() },
528
- parentID: typeof ev.clientMessageId === "string"
529
- ? ev.clientMessageId
530
- : (s.activeUserMessageID ?? parent?.info.id ?? ""),
548
+ parentID: compaction?.info.id ?? inputID,
531
549
  modelID: s.model?.modelID ?? "unknown",
532
550
  providerID: s.model?.providerID ?? "unknown",
533
551
  mode: getAgentName(),
package/dist/routes-v1.js CHANGED
@@ -148,11 +148,21 @@ export async function handleV1(services, req, res, url, path, method, directory)
148
148
  return;
149
149
  }
150
150
  let start = limit === undefined ? 0 : Math.max(0, end - limit);
151
+ const parents = new Set(messages
152
+ .slice(start, end)
153
+ .flatMap((message) => (message.info.role === "assistant" ? [message.info.parentID] : [])));
154
+ const parent = messages.findIndex((message, index) => index < start && message.info.role === "user" && parents.has(message.info.id));
155
+ if (parent >= 0)
156
+ start = parent;
151
157
  // OpenChamber 1.24 widens a page with no user message only up to 120 messages
152
158
  // (150 on desktop), then renders it with no turn to anchor on: blank. A long agent
153
- // turn outgrows that, so a page reaches back to the prompt that opened its turn.
154
- if (!messages.slice(start, end).some((message) => message.info.role === "user")) {
155
- const prompt = messages.findLastIndex((message, index) => index < start && message.info.role === "user");
159
+ // turn outgrows that, so retain its native prompt, not just a compaction display marker.
160
+ if (!messages
161
+ .slice(start, end)
162
+ .some((message) => message.info.role === "user" && !message.parts.some((part) => part.type === "compaction"))) {
163
+ const prompt = messages.findLastIndex((message, index) => index < start &&
164
+ message.info.role === "user" &&
165
+ !message.parts.some((part) => part.type === "compaction"));
156
166
  if (prompt >= 0)
157
167
  start = prompt;
158
168
  }
@@ -152,8 +152,9 @@ export function parsePiSessionText(s, agentName, raw) {
152
152
  continue;
153
153
  }
154
154
  if (e.type === "compaction" && typeof e.summary === "string" && typeof e.firstKeptEntryId === "string") {
155
- // Not a run boundary: an automatic compaction can sit between steps of one turn.
156
- out.push(...compactionMessages(s, e.id ?? `r${indexOf.get(e) ?? 0}`, e.summary, entryTime(e), currentModel, currentThinkingLevel));
155
+ const compaction = compactionMessages(s, e.id ?? `r${indexOf.get(e) ?? 0}`, e.summary, entryTime(e), currentModel, currentThinkingLevel);
156
+ out.push(...compaction);
157
+ lastUserId = compaction[0].info.id;
157
158
  continue;
158
159
  }
159
160
  if (e.type === "custom_message") {
@@ -24,6 +24,7 @@ export interface ManagedSession extends ThinkingState {
24
24
  abortRequests?: number;
25
25
  titleSource?: TitleSource;
26
26
  activeUserMessageID?: string;
27
+ deliveredInputCompactions?: Map<string, string>;
27
28
  inputs?: Map<string, {
28
29
  text: string;
29
30
  delivery: "steer" | "queue";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antechamber-omo-compat",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "description": "OpenChamber extension: displays OmO tool calls the way OmO means them when OpenChamber runs on antechamber",
5
5
  "private": true,
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antechamber-omo-graph",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "description": "OpenChamber extension: live, interactive graph of the OmO sub-agents behind the current session",
5
5
  "private": true,
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antechamber",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "description": "OpenCode-compatible HTTP/SSE server that lets OpenChamber drive the pi coding agent (and OmO) over RPC",
5
5
  "type": "module",
6
6
  "license": "MIT",