replicas-engine 0.1.208 → 0.1.210

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.
Files changed (2) hide show
  1. package/dist/src/index.js +128 -7
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -22,6 +22,7 @@ import { join } from "path";
22
22
 
23
23
  // ../shared/src/event.ts
24
24
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
25
+ var COMPACTION_STATUS_EVENT_TYPE = "compaction-status";
25
26
  var CONTEXT_USAGE_EVENT_TYPE = "context-usage";
26
27
 
27
28
  // ../shared/src/languages.ts
@@ -396,7 +397,7 @@ function parseReplicasConfigString(content, filename) {
396
397
  }
397
398
 
398
399
  // ../shared/src/engine/environment.ts
399
- var DAYTONA_SNAPSHOT_ID = "23-05-2026-royal-york-v6";
400
+ var DAYTONA_SNAPSHOT_ID = "25-05-2026-royal-york-v1";
400
401
 
401
402
  // ../shared/src/engine/types.ts
402
403
  var DEFAULT_CHAT_TITLES = {
@@ -2926,6 +2927,20 @@ var MessageQueueService = class {
2926
2927
  };
2927
2928
 
2928
2929
  // src/managers/coding-agent-manager.ts
2930
+ var COMPACT_COMMAND_REGEX = /^\/compact\b\s*(.*)$/s;
2931
+ var COMPACT_TURN_MARKER = "\0__replicas_compact_turn__\0";
2932
+ var COMPACT_SUMMARY_PROMPT = [
2933
+ "The user has requested a session compaction. Produce a thorough summary of this conversation that captures everything needed to continue the work without the prior context.",
2934
+ "",
2935
+ "Cover at least:",
2936
+ "1. The high-level goal we are working toward and the user's most recent intent.",
2937
+ "2. Key decisions made and the rationale behind them.",
2938
+ "3. Files inspected or modified (paths + the relevant changes).",
2939
+ "4. Open questions, blockers, and pending follow-ups.",
2940
+ "5. Any environment details, credentials, or external systems already configured.",
2941
+ "",
2942
+ "Format the response as Markdown with clear headings. The session will be reset after your reply and your summary re-injected as the prelude to the next user turn; write it so a future agent can resume using only that prelude."
2943
+ ].join("\n");
2929
2944
  var MAX_INTERRUPT_QUEUE_ITEMS = 1e3;
2930
2945
  var MAX_INTERRUPT_QUEUE_CHARS = 2e5;
2931
2946
  var CodingAgentManager = class {
@@ -2935,16 +2950,77 @@ var CodingAgentManager = class {
2935
2950
  initialSessionId;
2936
2951
  onSaveSessionId;
2937
2952
  onEvent;
2938
- onTurnComplete;
2953
+ hostOnTurnComplete;
2954
+ compactionInFlight = false;
2955
+ compactionBuffer = "";
2956
+ pendingSessionPrelude = null;
2939
2957
  constructor(options) {
2940
2958
  this.workingDirectory = options.workingDirectory ?? ENGINE_ENV.WORKSPACE_ROOT;
2941
2959
  this.initialSessionId = options.initialSessionId;
2942
2960
  this.onSaveSessionId = options.onSaveSessionId;
2943
2961
  this.onEvent = options.onEvent;
2944
- this.onTurnComplete = options.onTurnComplete;
2962
+ this.hostOnTurnComplete = options.onTurnComplete;
2963
+ }
2964
+ onTurnComplete = async () => {
2965
+ if (this.compactionInFlight) {
2966
+ this.compactionInFlight = false;
2967
+ const summary = this.compactionBuffer.trim();
2968
+ this.compactionBuffer = "";
2969
+ this.pendingSessionPrelude = summary.length > 0 ? summary : null;
2970
+ this.emitCompactionStatus("completed");
2971
+ try {
2972
+ await this.clearSessionState();
2973
+ } catch (error) {
2974
+ console.error("[CodingAgentManager] Failed to clear session after compaction:", error);
2975
+ }
2976
+ }
2977
+ await this.hostOnTurnComplete();
2978
+ };
2979
+ isCompacting() {
2980
+ return this.compactionInFlight;
2981
+ }
2982
+ captureCompactionText(text) {
2983
+ if (!this.compactionInFlight) return;
2984
+ const trimmed = text.trim();
2985
+ if (!trimmed) return;
2986
+ this.compactionBuffer = this.compactionBuffer.length > 0 ? `${this.compactionBuffer}
2987
+
2988
+ ${trimmed}` : trimmed;
2989
+ }
2990
+ consumePendingPrelude(message) {
2991
+ if (!this.pendingSessionPrelude) return message;
2992
+ const prelude = this.pendingSessionPrelude;
2993
+ this.pendingSessionPrelude = null;
2994
+ return `<prior-session-summary>
2995
+ ${prelude}
2996
+ </prior-session-summary>
2997
+
2998
+ ${message}`;
2999
+ }
3000
+ emitCompactionStatus(state) {
3001
+ this.onEvent({
3002
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3003
+ type: COMPACTION_STATUS_EVENT_TYPE,
3004
+ payload: { state }
3005
+ });
2945
3006
  }
2946
3007
  initializeManager(processMessage) {
2947
- this.messageQueue = new MessageQueueService(processMessage);
3008
+ const wrappedProcessMessage = async (request) => {
3009
+ if (request.message.startsWith(COMPACT_TURN_MARKER)) {
3010
+ this.compactionInFlight = true;
3011
+ this.compactionBuffer = "";
3012
+ this.emitCompactionStatus("in_progress");
3013
+ const summaryPrompt = this.consumePendingPrelude(
3014
+ request.message.slice(COMPACT_TURN_MARKER.length)
3015
+ );
3016
+ return processMessage({ ...request, message: summaryPrompt });
3017
+ }
3018
+ return processMessage({
3019
+ ...request,
3020
+ message: this.consumePendingPrelude(request.message)
3021
+ });
3022
+ };
3023
+ this.messageQueue = new MessageQueueService(wrappedProcessMessage);
2948
3024
  this.initialized = this.initialize();
2949
3025
  }
2950
3026
  async interrupt() {
@@ -2964,7 +3040,7 @@ var CodingAgentManager = class {
2964
3040
  getQueue() {
2965
3041
  return this.messageQueue.getQueue().map((m) => ({
2966
3042
  id: m.id,
2967
- message: m.message,
3043
+ message: m.message.startsWith(COMPACT_TURN_MARKER) ? "/compact" : m.message,
2968
3044
  queuedAt: m.queuedAt,
2969
3045
  ...m.senderUserId ? { senderUserId: m.senderUserId } : {},
2970
3046
  ...m.senderEmail ? { senderEmail: m.senderEmail } : {},
@@ -2979,6 +3055,18 @@ var CodingAgentManager = class {
2979
3055
  }
2980
3056
  async enqueueMessage(request) {
2981
3057
  await this.initialized;
3058
+ const compact = request.message.trimStart().match(COMPACT_COMMAND_REGEX);
3059
+ if (compact) {
3060
+ const guidance = compact[1].trim();
3061
+ const prompt = guidance ? `${COMPACT_SUMMARY_PROMPT}
3062
+
3063
+ Additional guidance from the user for the summary:
3064
+ ${guidance}` : COMPACT_SUMMARY_PROMPT;
3065
+ return this.messageQueue.enqueue({
3066
+ ...request,
3067
+ message: `${COMPACT_TURN_MARKER}${prompt}`
3068
+ });
3069
+ }
2982
3070
  return this.messageQueue.enqueue(request);
2983
3071
  }
2984
3072
  emitContextUsage(payload) {
@@ -3017,7 +3105,7 @@ var CodingAgentManager = class {
3017
3105
  const queue = this.messageQueue.drainQueue({
3018
3106
  maxItems: MAX_INTERRUPT_QUEUE_ITEMS,
3019
3107
  maxChars: MAX_INTERRUPT_QUEUE_CHARS
3020
- });
3108
+ }).map((m) => m.startsWith(COMPACT_TURN_MARKER) ? "/compact" : m);
3021
3109
  return {
3022
3110
  queue,
3023
3111
  isProcessing: this.messageQueue.isProcessing()
@@ -3294,6 +3382,10 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
3294
3382
  }
3295
3383
  await this.abortAllPendingToolInputs();
3296
3384
  }
3385
+ async clearSessionState() {
3386
+ this.sessionId = null;
3387
+ await this.onSaveSessionId(null);
3388
+ }
3297
3389
  async abortAllPendingToolInputs() {
3298
3390
  const pending = Array.from(this.pendingToolInputs.values());
3299
3391
  this.pendingToolInputs.clear();
@@ -3651,6 +3743,13 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
3651
3743
  console.log(`[ClaudeManager] Captured and persisted session ID: ${this.sessionId}`);
3652
3744
  }
3653
3745
  await this.checkForAuthFailure(message);
3746
+ if (this.isCompacting() && message.type === "assistant") {
3747
+ for (const block of message.message.content) {
3748
+ if (block.type === "text") {
3749
+ this.captureCompactionText(block.text);
3750
+ }
3751
+ }
3752
+ }
3654
3753
  await this.recordEvent(message);
3655
3754
  }
3656
3755
  async recordEvent(event) {
@@ -3816,6 +3915,11 @@ var CodexManager = class _CodexManager extends CodingAgentManager {
3816
3915
  this.activeAbortController.abort();
3817
3916
  }
3818
3917
  }
3918
+ async clearSessionState() {
3919
+ this.currentThreadId = null;
3920
+ this.currentThread = null;
3921
+ await this.onSaveSessionId(null);
3922
+ }
3819
3923
  /**
3820
3924
  * Update the developer_instructions in ~/.codex/config.toml
3821
3925
  * This sets the system prompt that Codex will use for this turn
@@ -4089,6 +4193,18 @@ var CodexManager = class _CodexManager extends CodingAgentManager {
4089
4193
  }
4090
4194
  return null;
4091
4195
  }
4196
+ bufferCompactionFromEvent(event) {
4197
+ if (!this.isCompacting()) return;
4198
+ if (event.type !== "response_item") return;
4199
+ const payload = event.payload;
4200
+ if (payload?.type !== "message" || payload?.role !== "assistant") return;
4201
+ const blocks = Array.isArray(payload.content) ? payload.content : [];
4202
+ for (const block of blocks) {
4203
+ if (block.type === "output_text" && typeof block.text === "string") {
4204
+ this.captureCompactionText(block.text);
4205
+ }
4206
+ }
4207
+ }
4092
4208
  async startSessionTail(threadId) {
4093
4209
  const sessionFile = await this.waitForSessionFile(threadId);
4094
4210
  if (!sessionFile) {
@@ -4139,6 +4255,7 @@ var CodexManager = class _CodexManager extends CodingAgentManager {
4139
4255
  this.emitQuotaStatus(snapshot);
4140
4256
  }
4141
4257
  if (isJsonlEvent2(parsed)) {
4258
+ this.bufferCompactionFromEvent(parsed);
4142
4259
  this.onEvent(parsed);
4143
4260
  emitted += 1;
4144
4261
  }
@@ -4690,6 +4807,9 @@ var RelayManager = class {
4690
4807
  isProcessing() {
4691
4808
  return this.inner.isProcessing();
4692
4809
  }
4810
+ isCompacting() {
4811
+ return this.inner.isCompacting();
4812
+ }
4693
4813
  getQueue() {
4694
4814
  return this.inner.getQueue();
4695
4815
  }
@@ -5113,6 +5233,7 @@ var ChatService = class {
5113
5233
  updatedAt: chat.persisted.updatedAt,
5114
5234
  processing: chat.provider.isProcessing(),
5115
5235
  awaitingInput: chat.provider.isAwaitingInput?.() ?? false,
5236
+ isCompacting: chat.provider.isCompacting?.() ?? false,
5116
5237
  parentChatId: chat.persisted.parentChatId
5117
5238
  };
5118
5239
  }
@@ -5155,7 +5276,7 @@ var ChatService = class {
5155
5276
  }
5156
5277
  }).catch(() => {
5157
5278
  });
5158
- if (event.type === "replicas-tool-input-request" || event.type === "replicas-tool-input-resolved") {
5279
+ if (event.type === "replicas-tool-input-request" || event.type === "replicas-tool-input-resolved" || event.type === "compaction-status") {
5159
5280
  this.publish({
5160
5281
  type: "chat.updated",
5161
5282
  payload: { chat: this.toSummary(chat) }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.208",
3
+ "version": "0.1.210",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",