replicas-engine 0.1.165 → 0.1.167

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 +166 -1
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -20,6 +20,7 @@ import { readFileSync } from "fs";
20
20
 
21
21
  // ../shared/src/event.ts
22
22
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
23
+ var CONTEXT_USAGE_EVENT_TYPE = "context-usage";
23
24
 
24
25
  // ../shared/src/pricing.ts
25
26
  var PLANS = {
@@ -285,7 +286,7 @@ function parseReplicasConfigString(content, filename) {
285
286
  }
286
287
 
287
288
  // ../shared/src/engine/environment.ts
288
- var DAYTONA_SNAPSHOT_ID = "13-05-2026-royal-york-v11";
289
+ var DAYTONA_SNAPSHOT_ID = "13-05-2026-royal-york-v13";
289
290
 
290
291
  // ../shared/src/engine/types.ts
291
292
  var DEFAULT_CHAT_TITLES = {
@@ -2522,6 +2523,35 @@ var MessageQueueService = class {
2522
2523
  this.queue = [];
2523
2524
  return drained;
2524
2525
  }
2526
+ /**
2527
+ * Get all queued messages (does not include the currently processing message)
2528
+ */
2529
+ getQueue() {
2530
+ return [...this.queue];
2531
+ }
2532
+ /**
2533
+ * Remove a message from the queue by its ID
2534
+ * @returns true if the message was found and removed
2535
+ */
2536
+ removeFromQueue(messageId) {
2537
+ const index = this.queue.findIndex((m) => m.id === messageId);
2538
+ if (index === -1) return false;
2539
+ this.queue.splice(index, 1);
2540
+ return true;
2541
+ }
2542
+ /**
2543
+ * Move a message to a new position in the queue
2544
+ * @returns true if the message was found and moved
2545
+ */
2546
+ reorderQueue(messageId, newPosition) {
2547
+ const index = this.queue.findIndex((m) => m.id === messageId);
2548
+ if (index === -1) return false;
2549
+ const clamped = Math.max(0, Math.min(newPosition, this.queue.length - 1));
2550
+ if (index === clamped) return true;
2551
+ const [item] = this.queue.splice(index, 1);
2552
+ this.queue.splice(clamped, 0, item);
2553
+ return true;
2554
+ }
2525
2555
  /**
2526
2556
  * Reset everything including clearing processing state
2527
2557
  */
@@ -2567,10 +2597,35 @@ var CodingAgentManager = class {
2567
2597
  isProcessing() {
2568
2598
  return this.messageQueue.isProcessing();
2569
2599
  }
2600
+ getQueue() {
2601
+ return this.messageQueue.getQueue().map((m) => ({
2602
+ id: m.id,
2603
+ message: m.message,
2604
+ queuedAt: m.queuedAt,
2605
+ ...m.senderUserId ? { senderUserId: m.senderUserId } : {},
2606
+ ...m.senderEmail ? { senderEmail: m.senderEmail } : {},
2607
+ ...m.senderDisplayName ? { senderDisplayName: m.senderDisplayName } : {}
2608
+ }));
2609
+ }
2610
+ removeFromQueue(messageId) {
2611
+ return this.messageQueue.removeFromQueue(messageId);
2612
+ }
2613
+ reorderQueue(messageId, newPosition) {
2614
+ return this.messageQueue.reorderQueue(messageId, newPosition);
2615
+ }
2570
2616
  async enqueueMessage(request) {
2571
2617
  await this.initialized;
2572
2618
  return this.messageQueue.enqueue(request);
2573
2619
  }
2620
+ emitContextUsage(payload) {
2621
+ const event = {
2622
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2623
+ type: CONTEXT_USAGE_EVENT_TYPE,
2624
+ payload: { ...payload }
2625
+ };
2626
+ this.onEvent(event);
2627
+ return event;
2628
+ }
2574
2629
  buildCombinedInstructions(customInstructions) {
2575
2630
  const startHooksInstruction = this.getStartHooksInstruction();
2576
2631
  const repositorySystemPromptInstruction = this.getRepositorySystemPromptInstruction();
@@ -2881,6 +2936,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
2881
2936
  }
2882
2937
  }
2883
2938
  if (msg.type === "result") {
2939
+ await this.recordContextUsage(response);
2884
2940
  this.activePromptStream?.close();
2885
2941
  break;
2886
2942
  }
@@ -2902,6 +2958,45 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
2902
2958
  }
2903
2959
  }
2904
2960
  }
2961
+ getContextUsageProvider() {
2962
+ return this.systemPromptOverride ? "relay" : "claude";
2963
+ }
2964
+ buildContextUsagePayload(usage) {
2965
+ const maxTokens = Number.isFinite(usage.maxTokens) ? usage.maxTokens : null;
2966
+ const percentage = Number.isFinite(usage.percentage) ? usage.percentage : maxTokens && maxTokens > 0 ? usage.totalTokens / maxTokens * 100 : 0;
2967
+ return {
2968
+ provider: this.getContextUsageProvider(),
2969
+ source: "claude_context",
2970
+ model: usage.model,
2971
+ totalTokens: usage.totalTokens,
2972
+ maxTokens,
2973
+ rawMaxTokens: Number.isFinite(usage.rawMaxTokens) ? usage.rawMaxTokens : maxTokens,
2974
+ percentage,
2975
+ categories: usage.categories.map((category) => ({
2976
+ name: category.name,
2977
+ tokens: category.tokens,
2978
+ percentage: maxTokens && maxTokens > 0 ? category.tokens / maxTokens * 100 : 0,
2979
+ color: category.color,
2980
+ ...category.isDeferred !== void 0 ? { isDeferred: category.isDeferred } : {}
2981
+ })),
2982
+ apiUsage: usage.apiUsage ? {
2983
+ inputTokens: usage.apiUsage.input_tokens,
2984
+ outputTokens: usage.apiUsage.output_tokens,
2985
+ cacheCreationInputTokens: usage.apiUsage.cache_creation_input_tokens,
2986
+ cacheReadInputTokens: usage.apiUsage.cache_read_input_tokens
2987
+ } : null,
2988
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2989
+ };
2990
+ }
2991
+ async recordContextUsage(response) {
2992
+ try {
2993
+ const usage = await response.getContextUsage();
2994
+ const event = this.emitContextUsage(this.buildContextUsagePayload(usage));
2995
+ await appendFile4(this.historyFile, JSON.stringify(event) + "\n", "utf-8");
2996
+ } catch (error) {
2997
+ console.warn("[ClaudeManager] Failed to record context usage:", error instanceof Error ? error.message : error);
2998
+ }
2999
+ }
2905
3000
  /**
2906
3001
  * Determines if an error is an OAuth authentication failure from the Claude SDK.
2907
3002
  * Known patterns:
@@ -3971,6 +4066,15 @@ var RelayManager = class {
3971
4066
  isProcessing() {
3972
4067
  return this.inner.isProcessing();
3973
4068
  }
4069
+ getQueue() {
4070
+ return this.inner.getQueue();
4071
+ }
4072
+ removeFromQueue(messageId) {
4073
+ return this.inner.removeFromQueue(messageId);
4074
+ }
4075
+ reorderQueue(messageId, newPosition) {
4076
+ return this.inner.reorderQueue(messageId, newPosition);
4077
+ }
3974
4078
  };
3975
4079
 
3976
4080
  // src/services/keep-alive-service.ts
@@ -4221,6 +4325,30 @@ var ChatService = class {
4221
4325
  });
4222
4326
  return result;
4223
4327
  }
4328
+ getChatQueue(chatId) {
4329
+ const chat = this.requireChat(chatId);
4330
+ return {
4331
+ chatId,
4332
+ processing: chat.provider.isProcessing(),
4333
+ queue: chat.provider.getQueue()
4334
+ };
4335
+ }
4336
+ removeFromQueue(chatId, messageId) {
4337
+ const chat = this.requireChat(chatId);
4338
+ const success = chat.provider.removeFromQueue(messageId);
4339
+ return {
4340
+ success,
4341
+ queue: chat.provider.getQueue()
4342
+ };
4343
+ }
4344
+ reorderQueue(chatId, messageId, position) {
4345
+ const chat = this.requireChat(chatId);
4346
+ const success = chat.provider.reorderQueue(messageId, position);
4347
+ return {
4348
+ success,
4349
+ queue: chat.provider.getQueue()
4350
+ };
4351
+ }
4224
4352
  async deleteChat(chatId) {
4225
4353
  const chat = this.requireChat(chatId);
4226
4354
  if (chat.persisted.title === DEFAULT_CHAT_TITLES[chat.persisted.provider]) {
@@ -5112,6 +5240,43 @@ function createV1Routes(deps) {
5112
5240
  return c.json(jsonError("Failed to interrupt chat", error instanceof Error ? error.message : "Unknown error"), 404);
5113
5241
  }
5114
5242
  });
5243
+ app2.get("/chats/:chatId/queue", (c) => {
5244
+ try {
5245
+ const result = deps.chatService.getChatQueue(c.req.param("chatId"));
5246
+ return c.json(result);
5247
+ } catch (error) {
5248
+ if (error instanceof ChatNotFoundError) {
5249
+ return c.json(jsonError("Chat not found", error.message), 404);
5250
+ }
5251
+ return c.json(jsonError("Failed to get queue", error instanceof Error ? error.message : "Unknown error"), 500);
5252
+ }
5253
+ });
5254
+ app2.delete("/chats/:chatId/queue/:messageId", (c) => {
5255
+ try {
5256
+ const result = deps.chatService.removeFromQueue(c.req.param("chatId"), c.req.param("messageId"));
5257
+ return c.json(result);
5258
+ } catch (error) {
5259
+ if (error instanceof ChatNotFoundError) {
5260
+ return c.json(jsonError("Chat not found", error.message), 404);
5261
+ }
5262
+ return c.json(jsonError("Failed to remove from queue", error instanceof Error ? error.message : "Unknown error"), 500);
5263
+ }
5264
+ });
5265
+ app2.patch("/chats/:chatId/queue/reorder", async (c) => {
5266
+ try {
5267
+ const body = await c.req.json();
5268
+ if (!body.messageId || typeof body.position !== "number" || !Number.isFinite(body.position)) {
5269
+ return c.json(jsonError("Invalid request", "messageId and position are required"), 400);
5270
+ }
5271
+ const result = deps.chatService.reorderQueue(c.req.param("chatId"), body.messageId, body.position);
5272
+ return c.json(result);
5273
+ } catch (error) {
5274
+ if (error instanceof ChatNotFoundError) {
5275
+ return c.json(jsonError("Chat not found", error.message), 404);
5276
+ }
5277
+ return c.json(jsonError("Failed to reorder queue", error instanceof Error ? error.message : "Unknown error"), 500);
5278
+ }
5279
+ });
5115
5280
  app2.get("/repos", async (c) => {
5116
5281
  const includeDiffs = c.req.query("includeDiffs") === "true";
5117
5282
  const repos = await gitService.listRepos({ includeDiffs });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.165",
3
+ "version": "0.1.167",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",