replicas-engine 0.1.35 → 0.1.36
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 +121 -2
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -716,6 +716,21 @@ var MessageQueue = class {
|
|
|
716
716
|
clearQueue() {
|
|
717
717
|
this.queue = [];
|
|
718
718
|
}
|
|
719
|
+
drainQueue(options) {
|
|
720
|
+
const maxItems = options?.maxItems ?? this.queue.length;
|
|
721
|
+
const maxChars = options?.maxChars ?? Number.POSITIVE_INFINITY;
|
|
722
|
+
const drained = [];
|
|
723
|
+
let totalChars = 0;
|
|
724
|
+
for (const message of this.queue) {
|
|
725
|
+
if (drained.length >= maxItems) break;
|
|
726
|
+
const text = message.message;
|
|
727
|
+
if (totalChars + text.length > maxChars) break;
|
|
728
|
+
drained.push(text);
|
|
729
|
+
totalChars += text.length;
|
|
730
|
+
}
|
|
731
|
+
this.queue = [];
|
|
732
|
+
return drained;
|
|
733
|
+
}
|
|
719
734
|
/**
|
|
720
735
|
* Reset everything including clearing processing state
|
|
721
736
|
*/
|
|
@@ -1016,6 +1031,8 @@ var replicasConfigService = new ReplicasConfigService();
|
|
|
1016
1031
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
1017
1032
|
var DEFAULT_MODEL = "gpt-5.2-codex";
|
|
1018
1033
|
var CODEX_CONFIG_PATH = join3(homedir3(), ".codex", "config.toml");
|
|
1034
|
+
var MAX_INTERRUPT_QUEUE_ITEMS = 1e3;
|
|
1035
|
+
var MAX_INTERRUPT_QUEUE_CHARS = 2e5;
|
|
1019
1036
|
var CodexManager = class {
|
|
1020
1037
|
codex;
|
|
1021
1038
|
currentThreadId = null;
|
|
@@ -1025,6 +1042,7 @@ var CodexManager = class {
|
|
|
1025
1042
|
baseSystemPrompt;
|
|
1026
1043
|
tempImageDir;
|
|
1027
1044
|
initialized;
|
|
1045
|
+
activeAbortController = null;
|
|
1028
1046
|
constructor(workingDirectory) {
|
|
1029
1047
|
this.codex = new Codex();
|
|
1030
1048
|
if (workingDirectory) {
|
|
@@ -1067,6 +1085,33 @@ var CodexManager = class {
|
|
|
1067
1085
|
getQueueStatus() {
|
|
1068
1086
|
return this.messageQueue.getStatus();
|
|
1069
1087
|
}
|
|
1088
|
+
async interrupt() {
|
|
1089
|
+
const queue = this.messageQueue.drainQueue({
|
|
1090
|
+
maxItems: MAX_INTERRUPT_QUEUE_ITEMS,
|
|
1091
|
+
maxChars: MAX_INTERRUPT_QUEUE_CHARS
|
|
1092
|
+
});
|
|
1093
|
+
const isProcessing = this.messageQueue.isProcessing();
|
|
1094
|
+
if (isProcessing && this.activeAbortController) {
|
|
1095
|
+
try {
|
|
1096
|
+
this.activeAbortController.abort();
|
|
1097
|
+
} catch {
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
const linearSessionId = process.env.LINEAR_SESSION_ID;
|
|
1101
|
+
if (linearSessionId && queue.length > 0) {
|
|
1102
|
+
const body = ["Interrupted. Cleared queue:", ...queue].join("\n");
|
|
1103
|
+
const thoughtEvent = {
|
|
1104
|
+
linearSessionId,
|
|
1105
|
+
content: {
|
|
1106
|
+
type: "thought",
|
|
1107
|
+
body
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
monolithService.sendEvent({ type: "agent_update", payload: thoughtEvent }).catch(() => {
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
return { interrupted: isProcessing || queue.length > 0, queue };
|
|
1114
|
+
}
|
|
1070
1115
|
/**
|
|
1071
1116
|
* Set the base system prompt from replicas.json
|
|
1072
1117
|
* This will be combined with any custom instructions passed to individual messages
|
|
@@ -1172,11 +1217,13 @@ var CodexManager = class {
|
|
|
1172
1217
|
model: model || DEFAULT_MODEL,
|
|
1173
1218
|
webSearchMode: "live"
|
|
1174
1219
|
};
|
|
1220
|
+
const abortController = new AbortController();
|
|
1221
|
+
this.activeAbortController = abortController;
|
|
1175
1222
|
if (this.currentThreadId) {
|
|
1176
1223
|
this.currentThread = this.codex.resumeThread(this.currentThreadId, threadOptions);
|
|
1177
1224
|
} else {
|
|
1178
1225
|
this.currentThread = this.codex.startThread(threadOptions);
|
|
1179
|
-
const { events: events2 } = await this.currentThread.runStreamed("Hello");
|
|
1226
|
+
const { events: events2 } = await this.currentThread.runStreamed("Hello", { signal: abortController.signal });
|
|
1180
1227
|
for await (const event of events2) {
|
|
1181
1228
|
if (event.type === "thread.started") {
|
|
1182
1229
|
this.currentThreadId = event.thread_id;
|
|
@@ -1200,7 +1247,7 @@ var CodexManager = class {
|
|
|
1200
1247
|
} else {
|
|
1201
1248
|
input = message;
|
|
1202
1249
|
}
|
|
1203
|
-
const { events } = await this.currentThread.runStreamed(input);
|
|
1250
|
+
const { events } = await this.currentThread.runStreamed(input, { signal: abortController.signal });
|
|
1204
1251
|
let latestThoughtEvent = null;
|
|
1205
1252
|
for await (const event of events) {
|
|
1206
1253
|
if (linearSessionId) {
|
|
@@ -1226,6 +1273,7 @@ var CodexManager = class {
|
|
|
1226
1273
|
});
|
|
1227
1274
|
}
|
|
1228
1275
|
} finally {
|
|
1276
|
+
this.activeAbortController = null;
|
|
1229
1277
|
const status = await getGitStatus(this.workingDirectory);
|
|
1230
1278
|
const payload = linearSessionId ? { linearSessionId, status } : { status };
|
|
1231
1279
|
monolithService.sendEvent({ type: "agent_turn_complete", payload }).catch(() => {
|
|
@@ -1514,6 +1562,22 @@ codex.post("/reset", async (c) => {
|
|
|
1514
1562
|
);
|
|
1515
1563
|
}
|
|
1516
1564
|
});
|
|
1565
|
+
codex.post("/interrupt", async (c) => {
|
|
1566
|
+
try {
|
|
1567
|
+
const result = await codexManager.interrupt();
|
|
1568
|
+
const response = result;
|
|
1569
|
+
return c.json(response);
|
|
1570
|
+
} catch (error) {
|
|
1571
|
+
console.error("Error in /codex/interrupt:", error);
|
|
1572
|
+
return c.json(
|
|
1573
|
+
{
|
|
1574
|
+
error: "Failed to interrupt thread",
|
|
1575
|
+
details: error instanceof Error ? error.message : "Unknown error"
|
|
1576
|
+
},
|
|
1577
|
+
500
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
});
|
|
1517
1581
|
var codex_default = codex;
|
|
1518
1582
|
|
|
1519
1583
|
// src/routes/claude.ts
|
|
@@ -1526,6 +1590,8 @@ import {
|
|
|
1526
1590
|
import { join as join4 } from "path";
|
|
1527
1591
|
import { mkdir as mkdir4, appendFile as appendFile2, rm } from "fs/promises";
|
|
1528
1592
|
import { homedir as homedir4 } from "os";
|
|
1593
|
+
var MAX_INTERRUPT_QUEUE_ITEMS2 = 1e3;
|
|
1594
|
+
var MAX_INTERRUPT_QUEUE_CHARS2 = 2e5;
|
|
1529
1595
|
var ClaudeManager = class {
|
|
1530
1596
|
workingDirectory;
|
|
1531
1597
|
historyFile;
|
|
@@ -1533,6 +1599,7 @@ var ClaudeManager = class {
|
|
|
1533
1599
|
initialized;
|
|
1534
1600
|
messageQueue;
|
|
1535
1601
|
baseSystemPrompt;
|
|
1602
|
+
activeQuery = null;
|
|
1536
1603
|
constructor(workingDirectory) {
|
|
1537
1604
|
if (workingDirectory) {
|
|
1538
1605
|
this.workingDirectory = workingDirectory;
|
|
@@ -1567,6 +1634,33 @@ var ClaudeManager = class {
|
|
|
1567
1634
|
getQueueStatus() {
|
|
1568
1635
|
return this.messageQueue.getStatus();
|
|
1569
1636
|
}
|
|
1637
|
+
async interrupt() {
|
|
1638
|
+
const queue = this.messageQueue.drainQueue({
|
|
1639
|
+
maxItems: MAX_INTERRUPT_QUEUE_ITEMS2,
|
|
1640
|
+
maxChars: MAX_INTERRUPT_QUEUE_CHARS2
|
|
1641
|
+
});
|
|
1642
|
+
const isProcessing = this.messageQueue.isProcessing();
|
|
1643
|
+
if (isProcessing && this.activeQuery) {
|
|
1644
|
+
try {
|
|
1645
|
+
await this.activeQuery.interrupt();
|
|
1646
|
+
} catch {
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
const linearSessionId = process.env.LINEAR_SESSION_ID;
|
|
1650
|
+
if (linearSessionId && queue.length > 0) {
|
|
1651
|
+
const body = ["Interrupted. Cleared queue:", ...queue].join("\n");
|
|
1652
|
+
const thoughtEvent = {
|
|
1653
|
+
linearSessionId,
|
|
1654
|
+
content: {
|
|
1655
|
+
type: "thought",
|
|
1656
|
+
body
|
|
1657
|
+
}
|
|
1658
|
+
};
|
|
1659
|
+
monolithService.sendEvent({ type: "agent_update", payload: thoughtEvent }).catch(() => {
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
return { interrupted: isProcessing || queue.length > 0, queue };
|
|
1663
|
+
}
|
|
1570
1664
|
/**
|
|
1571
1665
|
* Set the base system prompt from replicas.json
|
|
1572
1666
|
* This will be combined with any custom instructions passed to individual messages
|
|
@@ -1674,6 +1768,7 @@ var ClaudeManager = class {
|
|
|
1674
1768
|
model: model || "opus"
|
|
1675
1769
|
}
|
|
1676
1770
|
});
|
|
1771
|
+
this.activeQuery = response;
|
|
1677
1772
|
let latestThoughtEvent = null;
|
|
1678
1773
|
for await (const msg of response) {
|
|
1679
1774
|
await this.handleMessage(msg);
|
|
@@ -1700,6 +1795,7 @@ var ClaudeManager = class {
|
|
|
1700
1795
|
});
|
|
1701
1796
|
}
|
|
1702
1797
|
} finally {
|
|
1798
|
+
this.activeQuery = null;
|
|
1703
1799
|
const status = await getGitStatus(this.workingDirectory);
|
|
1704
1800
|
const payload = linearSessionId ? { linearSessionId, status } : { status };
|
|
1705
1801
|
monolithService.sendEvent({ type: "agent_turn_complete", payload }).catch(() => {
|
|
@@ -1926,6 +2022,22 @@ claude.post("/reset", async (c) => {
|
|
|
1926
2022
|
);
|
|
1927
2023
|
}
|
|
1928
2024
|
});
|
|
2025
|
+
claude.post("/interrupt", async (c) => {
|
|
2026
|
+
try {
|
|
2027
|
+
const result = await claudeManager.interrupt();
|
|
2028
|
+
const response = result;
|
|
2029
|
+
return c.json(response);
|
|
2030
|
+
} catch (error) {
|
|
2031
|
+
console.error("Error in /claude/interrupt:", error);
|
|
2032
|
+
return c.json(
|
|
2033
|
+
{
|
|
2034
|
+
error: "Failed to interrupt session",
|
|
2035
|
+
details: error instanceof Error ? error.message : "Unknown error"
|
|
2036
|
+
},
|
|
2037
|
+
500
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
});
|
|
1929
2041
|
var claude_default = claude;
|
|
1930
2042
|
|
|
1931
2043
|
// src/routes/plans.ts
|
|
@@ -2111,6 +2223,10 @@ var ClaudeTokenManager = class {
|
|
|
2111
2223
|
REFRESH_INTERVAL_MS = 45 * 60 * 1e3;
|
|
2112
2224
|
// 45 minutes
|
|
2113
2225
|
async start() {
|
|
2226
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
2227
|
+
console.log("[ClaudeTokenManager] Skipping: ANTHROPIC_API_KEY is set");
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2114
2230
|
const monolithUrl = process.env.MONOLITH_URL;
|
|
2115
2231
|
const workspaceId = process.env.WORKSPACE_ID;
|
|
2116
2232
|
const engineSecret = process.env.REPLICAS_ENGINE_SECRET;
|
|
@@ -2135,6 +2251,9 @@ var ClaudeTokenManager = class {
|
|
|
2135
2251
|
}
|
|
2136
2252
|
}
|
|
2137
2253
|
async refreshCredentials() {
|
|
2254
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
2255
|
+
return;
|
|
2256
|
+
}
|
|
2138
2257
|
const monolithUrl = process.env.MONOLITH_URL;
|
|
2139
2258
|
const workspaceId = process.env.WORKSPACE_ID;
|
|
2140
2259
|
const engineSecret = process.env.REPLICAS_ENGINE_SECRET;
|