replicas-engine 0.1.579 → 0.1.581

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/src/index.js CHANGED
@@ -3311,14 +3311,23 @@ function chatHistoryPageParamsFromQuery(query2) {
3311
3311
  beforeTurn: parse(query2.beforeTurn)
3312
3312
  };
3313
3313
  }
3314
+ function getChatHistoryPageWindow(totalItems, limit, before) {
3315
+ const endIndex = Math.min(before ?? totalItems, totalItems);
3316
+ return { startIndex: Math.max(0, endIndex - Math.max(1, limit)), endIndex };
3317
+ }
3314
3318
  function paginateChatHistory(full, params) {
3315
3319
  if (params.limit === void 0) return { ...full, totalEvents: full.events.length };
3316
- const limit = Math.max(1, params.limit);
3317
- const eventsEnd = Math.min(params.beforeEvent ?? full.events.length, full.events.length);
3318
- const eventsStartIndex = Math.max(0, eventsEnd - limit);
3320
+ const { startIndex: eventsStartIndex, endIndex: eventsEnd } = getChatHistoryPageWindow(
3321
+ full.events.length,
3322
+ params.limit,
3323
+ params.beforeEvent
3324
+ );
3319
3325
  const turns = full.codexAspTranscript?.turns;
3320
- const turnsEnd = turns ? Math.min(params.beforeTurn ?? turns.length, turns.length) : 0;
3321
- const turnsStartIndex = Math.max(0, turnsEnd - limit);
3326
+ const { startIndex: turnsStartIndex, endIndex: turnsEnd } = getChatHistoryPageWindow(
3327
+ turns?.length ?? 0,
3328
+ params.limit,
3329
+ params.beforeTurn
3330
+ );
3322
3331
  const codexAspTranscript = full.codexAspTranscript && turns && (turnsStartIndex > 0 || turnsEnd < turns.length) ? { ...full.codexAspTranscript, turns: turns.slice(turnsStartIndex, turnsEnd) } : full.codexAspTranscript;
3323
3332
  return {
3324
3333
  ...full,
@@ -9406,13 +9415,14 @@ function isNotFoundError(error) {
9406
9415
  }
9407
9416
 
9408
9417
  // src/managers/codex-asp/codex-history-file.ts
9409
- import { appendFile as appendFile2, readFile as readFile9 } from "fs/promises";
9418
+ import { appendFile as appendFile2, open, readFile as readFile9 } from "fs/promises";
9410
9419
  var CodexHistoryFile = class {
9411
9420
  constructor(filePath) {
9412
9421
  this.filePath = filePath;
9413
9422
  }
9414
9423
  filePath;
9415
9424
  writeLock = new AsyncLock();
9425
+ eventLineIndex = null;
9416
9426
  /** Best-effort ordered append; failures must not disrupt the turn. */
9417
9427
  append(event) {
9418
9428
  void this.writeLock.run(
@@ -9435,6 +9445,88 @@ var CodexHistoryFile = class {
9435
9445
  return { events: [], transcript: null, transcriptsByThreadId: /* @__PURE__ */ new Map() };
9436
9446
  }
9437
9447
  }
9448
+ async loadEventsPage(page) {
9449
+ if (page.limit === void 0) {
9450
+ const history2 = await this.load();
9451
+ return { events: history2.events, eventsStartIndex: 0, totalEvents: history2.events.length };
9452
+ }
9453
+ let file;
9454
+ try {
9455
+ file = await open(this.filePath, "r");
9456
+ } catch (error) {
9457
+ if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) {
9458
+ console.error("[CodexHistoryFile] Failed to open history file:", error);
9459
+ }
9460
+ return { events: [], eventsStartIndex: 0, totalEvents: 0 };
9461
+ }
9462
+ try {
9463
+ const stats = await file.stat();
9464
+ let index = this.eventLineIndex;
9465
+ if (!index || index.size !== stats.size || index.mtimeMs !== stats.mtimeMs) {
9466
+ const starts = stats.size > 0 ? [0] : [];
9467
+ const buffer = Buffer.allocUnsafe(64 * 1024);
9468
+ let position = 0;
9469
+ while (position < stats.size) {
9470
+ const { bytesRead: bytesRead2 } = await file.read(
9471
+ buffer,
9472
+ 0,
9473
+ Math.min(buffer.length, stats.size - position),
9474
+ position
9475
+ );
9476
+ if (bytesRead2 === 0) break;
9477
+ for (let offset = 0; offset < bytesRead2; offset += 1) {
9478
+ const next = position + offset + 1;
9479
+ if (buffer[offset] === 10 && next < stats.size) starts.push(next);
9480
+ }
9481
+ position += bytesRead2;
9482
+ }
9483
+ index = { size: stats.size, mtimeMs: stats.mtimeMs, starts };
9484
+ this.eventLineIndex = index;
9485
+ }
9486
+ const totalEvents2 = index.starts.length;
9487
+ const { startIndex: eventsStartIndex2, endIndex: eventsEnd2 } = getChatHistoryPageWindow(
9488
+ totalEvents2,
9489
+ page.limit,
9490
+ page.beforeEvent
9491
+ );
9492
+ const startByte = index.starts[eventsStartIndex2] ?? index.size;
9493
+ const endByte = index.starts[eventsEnd2] ?? index.size;
9494
+ const content = Buffer.allocUnsafe(endByte - startByte);
9495
+ let bytesRead = 0;
9496
+ while (bytesRead < content.length) {
9497
+ const result = await file.read(
9498
+ content,
9499
+ bytesRead,
9500
+ content.length - bytesRead,
9501
+ startByte + bytesRead
9502
+ );
9503
+ if (result.bytesRead === 0) break;
9504
+ bytesRead += result.bytesRead;
9505
+ }
9506
+ if (bytesRead === content.length) {
9507
+ const parsed = parseAgentEventJsonlWithCodexAspTranscript(content.toString("utf-8"));
9508
+ if (!parsed.transcript && parsed.events.length === eventsEnd2 - eventsStartIndex2) {
9509
+ return { events: parsed.events, eventsStartIndex: eventsStartIndex2, totalEvents: totalEvents2 };
9510
+ }
9511
+ }
9512
+ } catch (error) {
9513
+ console.error("[CodexHistoryFile] Failed to load history page:", error);
9514
+ } finally {
9515
+ await file.close();
9516
+ }
9517
+ const history = await this.load();
9518
+ const totalEvents = history.events.length;
9519
+ const { startIndex: eventsStartIndex, endIndex: eventsEnd } = getChatHistoryPageWindow(
9520
+ totalEvents,
9521
+ page.limit,
9522
+ page.beforeEvent
9523
+ );
9524
+ return {
9525
+ events: history.events.slice(eventsStartIndex, eventsEnd),
9526
+ eventsStartIndex,
9527
+ totalEvents
9528
+ };
9529
+ }
9438
9530
  };
9439
9531
 
9440
9532
  // src/managers/claude-activity.ts
@@ -10563,13 +10655,13 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
10563
10655
  }
10564
10656
  return null;
10565
10657
  }
10566
- async getHistory() {
10658
+ async getHistory(page = {}) {
10567
10659
  await this.initialized;
10568
10660
  await this.historyFile.flush();
10569
- const history = await this.historyFile.load();
10661
+ const history = await this.historyFile.loadEventsPage(page);
10570
10662
  return {
10571
10663
  thread_id: this.sessionId,
10572
- events: history.events
10664
+ ...history
10573
10665
  };
10574
10666
  }
10575
10667
  partialMessageStreamKey(message) {
@@ -10896,7 +10988,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
10896
10988
  var MIN_CODEX_CLI_VERSION = "0.144.6";
10897
10989
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
10898
10990
  var codexCliVersionEnsured = null;
10899
- var ENGINE_PACKAGE_VERSION = "0.1.579";
10991
+ var ENGINE_PACKAGE_VERSION = "0.1.581";
10900
10992
  var INITIALIZE_METHOD = "initialize";
10901
10993
  var INITIALIZED_NOTIFICATION = "initialized";
10902
10994
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -12009,22 +12101,24 @@ var CodexAspManager = class extends CodingAgentManager {
12009
12101
  this.recordUserMessageEvent(request);
12010
12102
  return true;
12011
12103
  }
12012
- async getHistory() {
12104
+ async getHistory(page = {}) {
12013
12105
  if (!this.currentThreadId) {
12014
- return { thread_id: null, events: [], goal: null };
12106
+ return paginateChatHistory({ thread_id: null, events: [], goal: null }, page);
12015
12107
  }
12016
- if (this.activeTurnId && this.codexAspTranscript?.threadId === this.currentThreadId) {
12017
- try {
12018
- const host = await getCodexAspHost();
12019
- await this.refreshThreadGoal(host, this.currentThreadId);
12020
- } catch {
12108
+ if (this.codexAspTranscript?.threadId === this.currentThreadId) {
12109
+ if (page.beforeEvent === void 0 && page.beforeTurn === void 0) {
12110
+ try {
12111
+ const host = await getCodexAspHost();
12112
+ await this.refreshThreadGoal(host, this.currentThreadId);
12113
+ } catch {
12114
+ }
12021
12115
  }
12022
- return {
12116
+ return paginateChatHistory({
12023
12117
  thread_id: this.currentThreadId,
12024
12118
  events: [...this.historyEvents],
12025
12119
  codexAspTranscript: this.codexAspTranscript,
12026
12120
  goal: this.currentGoal
12027
- };
12121
+ }, page);
12028
12122
  }
12029
12123
  try {
12030
12124
  const host = await getCodexAspHost();
@@ -12039,20 +12133,20 @@ var CodexAspManager = class extends CodingAgentManager {
12039
12133
  if (transcript) {
12040
12134
  transcript.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
12041
12135
  }
12042
- return {
12136
+ return paginateChatHistory({
12043
12137
  thread_id: this.currentThreadId,
12044
12138
  events: [...this.historyEvents],
12045
12139
  codexAspTranscript: transcript,
12046
12140
  goal: this.currentGoal
12047
- };
12141
+ }, page);
12048
12142
  } catch {
12049
12143
  }
12050
- return {
12144
+ return paginateChatHistory({
12051
12145
  thread_id: this.currentThreadId,
12052
12146
  events: [...this.historyEvents],
12053
12147
  codexAspTranscript: this.codexAspTranscript,
12054
12148
  goal: this.currentGoal
12055
- };
12149
+ }, page);
12056
12150
  }
12057
12151
  getGoal() {
12058
12152
  return this.currentGoal;
@@ -13260,12 +13354,12 @@ var CursorManager = class extends CodingAgentManager {
13260
13354
  }
13261
13355
  this.agent = null;
13262
13356
  }
13263
- async getHistory() {
13357
+ async getHistory(page = {}) {
13264
13358
  await this.historyFile.flush();
13265
- const history = await this.historyFile.load();
13359
+ const history = await this.historyFile.loadEventsPage(page);
13266
13360
  return {
13267
13361
  thread_id: this.agent?.agentId ?? this.initialSessionId,
13268
- events: history.events,
13362
+ ...history,
13269
13363
  goal: null
13270
13364
  };
13271
13365
  }
@@ -13822,6 +13916,7 @@ var OpencodeManager = class extends CodingAgentManager {
13822
13916
  nonAssistantMessageIds = /* @__PURE__ */ new Set();
13823
13917
  activeLinearForwarder = null;
13824
13918
  forwardedLinearPartKeys = /* @__PURE__ */ new Set();
13919
+ handledAccountRateLimit = false;
13825
13920
  modelVariants = /* @__PURE__ */ new Map();
13826
13921
  handledPermissionRequestIds = /* @__PURE__ */ new Set();
13827
13922
  pendingPermissionRequestIds = /* @__PURE__ */ new Set();
@@ -13844,24 +13939,26 @@ var OpencodeManager = class extends CodingAgentManager {
13844
13939
  return this.historyFile;
13845
13940
  }
13846
13941
  async interruptActiveTurn() {
13847
- this.activeAbortController?.abort();
13848
- if (this.client && this.sessionId) {
13849
- try {
13850
- await this.client.session.abort(
13851
- { sessionID: this.sessionId, directory: this.workingDirectory },
13852
- { throwOnError: true }
13853
- );
13854
- } catch (error) {
13855
- console.error("[OpencodeManager] Failed to abort Opencode session:", error);
13856
- }
13942
+ try {
13943
+ await this.abortActiveTurn();
13944
+ } catch (error) {
13945
+ console.error("[OpencodeManager] Failed to abort Opencode session:", error);
13857
13946
  }
13858
13947
  }
13859
- async getHistory() {
13948
+ async abortActiveTurn() {
13949
+ this.activeAbortController?.abort();
13950
+ if (!this.client || !this.sessionId) return;
13951
+ await this.client.session.abort(
13952
+ { sessionID: this.sessionId, directory: this.workingDirectory },
13953
+ { throwOnError: true }
13954
+ );
13955
+ }
13956
+ async getHistory(page = {}) {
13860
13957
  await this.historyFile.flush();
13861
- const history = await this.historyFile.load();
13958
+ const history = await this.historyFile.loadEventsPage(page);
13862
13959
  return {
13863
13960
  thread_id: this.sessionId ?? this.initialSessionId,
13864
- events: history.events,
13961
+ ...history,
13865
13962
  goal: null
13866
13963
  };
13867
13964
  }
@@ -14017,6 +14114,7 @@ var OpencodeManager = class extends CodingAgentManager {
14017
14114
  const controller = new AbortController();
14018
14115
  const linearSessionId = ENGINE_ENV.REPLICAS_LINEAR_SESSION_ID;
14019
14116
  const linearForwarder = new LinearEventForwarder(linearSessionId);
14117
+ this.handledAccountRateLimit = false;
14020
14118
  this.activeAbortController = controller;
14021
14119
  this.activeLinearForwarder = linearForwarder;
14022
14120
  this.forwardedLinearPartKeys.clear();
@@ -14104,6 +14202,11 @@ var OpencodeManager = class extends CodingAgentManager {
14104
14202
  return;
14105
14203
  }
14106
14204
  if (event.type === "message.updated") this.recordOpencodeMessageRole(payload);
14205
+ if (event.type === "session.status") {
14206
+ this.handleAccountRateLimit(payload).catch((error) => {
14207
+ console.error("[OpencodeManager] Failed to stop account-rate-limited turn:", error);
14208
+ });
14209
+ }
14107
14210
  if (event.type === "session.next.tool.input.ended") {
14108
14211
  const callId = typeof payload.callID === "string" ? payload.callID : void 0;
14109
14212
  if (callId && typeof payload.text === "string") {
@@ -14123,6 +14226,15 @@ var OpencodeManager = class extends CodingAgentManager {
14123
14226
  if (this.recordOpencodeNextPart(event.type, payload)) return;
14124
14227
  this.recordHistoryEvent(`opencode-${event.type}`, payload, this.historyFile);
14125
14228
  }
14229
+ async handleAccountRateLimit(payload) {
14230
+ const status = isRecord4(payload.status) ? payload.status : null;
14231
+ const action = isRecord4(status?.action) ? status.action : null;
14232
+ if (status?.type !== "retry" || action?.reason !== "account_rate_limit" || this.handledAccountRateLimit) return;
14233
+ this.handledAccountRateLimit = true;
14234
+ const message = typeof status.message === "string" ? status.message : typeof action.message === "string" ? action.message : "OpenCode Go usage limit reached.";
14235
+ this.recordHistoryEvent("opencode-error", { message, code: "account_rate_limit" }, this.historyFile);
14236
+ await this.abortActiveTurn();
14237
+ }
14126
14238
  async respondToOpencodePermission(type, payload) {
14127
14239
  if (!this.client) return;
14128
14240
  const requestId = typeof payload.id === "string" ? payload.id : void 0;
@@ -14221,13 +14333,7 @@ var OpencodeManager = class extends CodingAgentManager {
14221
14333
  historyFile: this.historyFile,
14222
14334
  recordHistoryEvent: this.recordHistoryEvent.bind(this)
14223
14335
  });
14224
- this.activeAbortController?.abort();
14225
- if (this.client && this.sessionId) {
14226
- await this.client.session.abort(
14227
- { sessionID: this.sessionId, directory: this.workingDirectory },
14228
- { throwOnError: true }
14229
- );
14230
- }
14336
+ await this.abortActiveTurn();
14231
14337
  this.handledToolCallIds.add(toolUseId);
14232
14338
  } finally {
14233
14339
  this.pendingToolCallIds.delete(toolUseId);
@@ -14423,10 +14529,10 @@ var PiManager = class extends CodingAgentManager {
14423
14529
  this.recordUserMessage(session, request.message);
14424
14530
  return true;
14425
14531
  }
14426
- async getHistory() {
14532
+ async getHistory(page = {}) {
14427
14533
  await this.historyFile.flush();
14428
- const history = await this.historyFile.load();
14429
- return { thread_id: this.activeSessionFile ?? this.initialSessionId, events: history.events, goal: null };
14534
+ const history = await this.historyFile.loadEventsPage(page);
14535
+ return { thread_id: this.activeSessionFile ?? this.initialSessionId, ...history, goal: null };
14430
14536
  }
14431
14537
  async listSlashCommands() {
14432
14538
  await this.initialized;
@@ -15143,8 +15249,8 @@ var RelayManager = class {
15143
15249
  async interrupt() {
15144
15250
  return this.inner.interrupt();
15145
15251
  }
15146
- async getHistory() {
15147
- return this.inner.getHistory();
15252
+ async getHistory(page = {}) {
15253
+ return this.inner.getHistory(page);
15148
15254
  }
15149
15255
  async listSlashCommands() {
15150
15256
  return this.inner.listSlashCommands?.() ?? [];
@@ -16407,17 +16513,27 @@ var ChatService = class {
16407
16513
  async getChatHistory(chatId, page = {}) {
16408
16514
  const chat = this.requireChat(chatId);
16409
16515
  const [history, senders] = await Promise.all([
16410
- chat.provider.getHistory(),
16516
+ chat.provider.getHistory(page),
16411
16517
  this.readSenders(chatId)
16412
16518
  ]);
16413
16519
  for (const [messageId, acceptedEvent] of chat.acceptedUserEvents) {
16414
- if (acceptedEventInCodexTranscript(acceptedEvent, history.codexAspTranscript)) {
16520
+ if (acceptedEventInCodexTranscript(acceptedEvent, history.codexAspTranscript) || history.events.some((event) => isSameAcceptedUserEvent(event, acceptedEvent))) {
16415
16521
  chat.acceptedUserEvents.delete(messageId);
16416
16522
  }
16417
16523
  }
16524
+ const isLatestPage = page.beforeEvent === void 0 && page.beforeTurn === void 0;
16418
16525
  const queuedMessageIds = new Set(chat.provider.getQueue().map((message) => message.id));
16419
- const acceptedEvents = [...chat.acceptedUserEvents.entries()].filter(([messageId]) => messageId === chat.activeMessageId || !chat.hasActiveTurn && chat.pendingMessageIds[0] === messageId && !queuedMessageIds.has(messageId)).map(([, acceptedEvent]) => acceptedEvent).filter((acceptedEvent) => !acceptedEventInCodexTranscript(acceptedEvent, history.codexAspTranscript) && !history.events.some((event) => isSameAcceptedUserEvent(event, acceptedEvent)));
16526
+ const acceptedEvents = (isLatestPage ? [...chat.acceptedUserEvents.entries()] : []).filter(([messageId]) => messageId === chat.activeMessageId || !chat.hasActiveTurn && chat.pendingMessageIds[0] === messageId && !queuedMessageIds.has(messageId)).map(([, acceptedEvent]) => acceptedEvent).filter((acceptedEvent) => !acceptedEventInCodexTranscript(acceptedEvent, history.codexAspTranscript) && !history.events.some((event) => isSameAcceptedUserEvent(event, acceptedEvent)));
16420
16527
  const events = [...history.events, ...acceptedEvents].sort((a, b) => getEventTimestampMs(a) - getEventTimestampMs(b));
16528
+ if (history.eventsStartIndex !== void 0) {
16529
+ return {
16530
+ ...history,
16531
+ events,
16532
+ totalEvents: (history.totalEvents ?? history.eventsStartIndex + history.events.length) + acceptedEvents.length,
16533
+ goal: history.goal ?? chat.provider.getGoal?.() ?? null,
16534
+ senders
16535
+ };
16536
+ }
16421
16537
  return paginateChatHistory({
16422
16538
  thread_id: history.thread_id,
16423
16539
  events,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.579",
3
+ "version": "0.1.581",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",