@mindstudio-ai/remy 0.1.164 → 0.1.165
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/headless.d.ts +14 -0
- package/dist/headless.js +91 -31
- package/dist/index.js +93 -33
- package/dist/prompt/static/instructions.md +1 -1
- package/package.json +1 -1
package/dist/headless.d.ts
CHANGED
|
@@ -74,6 +74,20 @@ declare class HeadlessSession {
|
|
|
74
74
|
private persistStats;
|
|
75
75
|
/** Apply queued tool block updates to state.messages. Safe to call any time. */
|
|
76
76
|
private applyPendingBlockUpdates;
|
|
77
|
+
/**
|
|
78
|
+
* Forced compaction gate. If lastContextSize exceeds the threshold, compact
|
|
79
|
+
* before letting the upcoming turn run. Coalesces with any in-flight
|
|
80
|
+
* compaction (e.g., one already started by /compact or a tool call). No
|
|
81
|
+
* timeout — compaction takes as long as it takes.
|
|
82
|
+
*
|
|
83
|
+
* Lifecycle events (`compaction_started` / `compaction_complete`) and
|
|
84
|
+
* stats updates are handled by the listener registered in start(); this
|
|
85
|
+
* method only awaits the promise and applies the resulting summaries.
|
|
86
|
+
*
|
|
87
|
+
* On compaction failure we don't bail — the turn proceeds and surfaces any
|
|
88
|
+
* downstream overflow through the existing "prompt is too long" path.
|
|
89
|
+
*/
|
|
90
|
+
private runForcedCompactionIfNeeded;
|
|
77
91
|
/** Drain pending compaction summaries and insert at a safe point. */
|
|
78
92
|
private applyPendingSummaries;
|
|
79
93
|
private onBackgroundComplete;
|
package/dist/headless.js
CHANGED
|
@@ -1757,8 +1757,10 @@ var compactConversationTool = {
|
|
|
1757
1757
|
}
|
|
1758
1758
|
triggerCompaction(
|
|
1759
1759
|
{ messages: context.conversationMessages },
|
|
1760
|
-
context.apiConfig
|
|
1761
|
-
|
|
1760
|
+
context.apiConfig,
|
|
1761
|
+
{ blocking: false, requestId: context.requestId }
|
|
1762
|
+
).catch(() => {
|
|
1763
|
+
});
|
|
1762
1764
|
return "Compaction started in the background.";
|
|
1763
1765
|
}
|
|
1764
1766
|
};
|
|
@@ -5184,23 +5186,40 @@ function executeTool(name, input, context) {
|
|
|
5184
5186
|
// src/compaction/trigger.ts
|
|
5185
5187
|
var log7 = createLogger("compaction:trigger");
|
|
5186
5188
|
var pendingSummaries = [];
|
|
5189
|
+
var inflightCompaction = null;
|
|
5187
5190
|
function getPendingSummaries() {
|
|
5188
5191
|
return pendingSummaries.splice(0);
|
|
5189
5192
|
}
|
|
5190
|
-
|
|
5191
|
-
|
|
5193
|
+
var listener = null;
|
|
5194
|
+
function setCompactionListener(l) {
|
|
5195
|
+
listener = l;
|
|
5196
|
+
}
|
|
5197
|
+
function triggerCompaction(state, apiConfig, opts = {}) {
|
|
5198
|
+
if (inflightCompaction) {
|
|
5199
|
+
return inflightCompaction;
|
|
5200
|
+
}
|
|
5201
|
+
const { blocking = false, requestId } = opts;
|
|
5202
|
+
listener?.({ type: "started", blocking, requestId });
|
|
5192
5203
|
const system = buildSystemPrompt("onboardingFinished");
|
|
5193
5204
|
const tools2 = getToolDefinitions("onboardingFinished");
|
|
5194
|
-
|
|
5205
|
+
inflightCompaction = compactConversation(
|
|
5206
|
+
state.messages,
|
|
5207
|
+
apiConfig,
|
|
5208
|
+
system,
|
|
5209
|
+
tools2
|
|
5210
|
+
).then((summaries) => {
|
|
5195
5211
|
pendingSummaries.push(...summaries);
|
|
5196
|
-
|
|
5212
|
+
listener?.({ type: "complete", requestId });
|
|
5197
5213
|
log7.info("Compaction complete");
|
|
5198
5214
|
}).catch((err) => {
|
|
5199
|
-
|
|
5200
|
-
|
|
5215
|
+
const message = err.message || "Compaction failed";
|
|
5216
|
+
listener?.({ type: "complete", error: message, requestId });
|
|
5217
|
+
log7.error("Compaction failed", { error: message });
|
|
5218
|
+
throw err;
|
|
5201
5219
|
}).finally(() => {
|
|
5202
|
-
|
|
5220
|
+
inflightCompaction = null;
|
|
5203
5221
|
});
|
|
5222
|
+
return inflightCompaction;
|
|
5204
5223
|
}
|
|
5205
5224
|
|
|
5206
5225
|
// src/brandExtraction/index.ts
|
|
@@ -6628,6 +6647,7 @@ var USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
|
6628
6647
|
"confirmDestructiveAction",
|
|
6629
6648
|
"presentPublishPlan"
|
|
6630
6649
|
]);
|
|
6650
|
+
var FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
|
|
6631
6651
|
var HeadlessSession = class {
|
|
6632
6652
|
// Configuration
|
|
6633
6653
|
opts;
|
|
@@ -6695,6 +6715,24 @@ var HeadlessSession = class {
|
|
|
6695
6715
|
}
|
|
6696
6716
|
triggerBrandExtraction(this.config);
|
|
6697
6717
|
this.toolRegistry.onEvent = this.onEvent;
|
|
6718
|
+
setCompactionListener((event) => {
|
|
6719
|
+
if (event.type === "started") {
|
|
6720
|
+
this.emit(
|
|
6721
|
+
"compaction_started",
|
|
6722
|
+
{ blocking: event.blocking },
|
|
6723
|
+
event.requestId
|
|
6724
|
+
);
|
|
6725
|
+
this.sessionStats.compactionInProgress = true;
|
|
6726
|
+
this.persistStats();
|
|
6727
|
+
} else {
|
|
6728
|
+
const data = event.error ? { error: event.error } : {};
|
|
6729
|
+
this.emit("compaction_complete", data, event.requestId);
|
|
6730
|
+
this.sessionStats.compactionInProgress = false;
|
|
6731
|
+
this.sessionStats.lastContextSize = 0;
|
|
6732
|
+
this.sessionStats.messageCount = this.state.messages.length;
|
|
6733
|
+
this.persistStats();
|
|
6734
|
+
}
|
|
6735
|
+
});
|
|
6698
6736
|
process.stdin.setEncoding("utf-8");
|
|
6699
6737
|
process.stdin.on("data", (chunk) => {
|
|
6700
6738
|
this.stdinBuffer += chunk;
|
|
@@ -6796,6 +6834,37 @@ var HeadlessSession = class {
|
|
|
6796
6834
|
}
|
|
6797
6835
|
saveSession(this.state);
|
|
6798
6836
|
}
|
|
6837
|
+
/**
|
|
6838
|
+
* Forced compaction gate. If lastContextSize exceeds the threshold, compact
|
|
6839
|
+
* before letting the upcoming turn run. Coalesces with any in-flight
|
|
6840
|
+
* compaction (e.g., one already started by /compact or a tool call). No
|
|
6841
|
+
* timeout — compaction takes as long as it takes.
|
|
6842
|
+
*
|
|
6843
|
+
* Lifecycle events (`compaction_started` / `compaction_complete`) and
|
|
6844
|
+
* stats updates are handled by the listener registered in start(); this
|
|
6845
|
+
* method only awaits the promise and applies the resulting summaries.
|
|
6846
|
+
*
|
|
6847
|
+
* On compaction failure we don't bail — the turn proceeds and surfaces any
|
|
6848
|
+
* downstream overflow through the existing "prompt is too long" path.
|
|
6849
|
+
*/
|
|
6850
|
+
async runForcedCompactionIfNeeded(requestId) {
|
|
6851
|
+
if (this.sessionStats.lastContextSize <= FORCED_COMPACTION_THRESHOLD_TOKENS) {
|
|
6852
|
+
return;
|
|
6853
|
+
}
|
|
6854
|
+
log14.info("Forced compaction gate triggered", {
|
|
6855
|
+
contextSize: this.sessionStats.lastContextSize,
|
|
6856
|
+
threshold: FORCED_COMPACTION_THRESHOLD_TOKENS,
|
|
6857
|
+
requestId
|
|
6858
|
+
});
|
|
6859
|
+
try {
|
|
6860
|
+
await triggerCompaction(this.state, this.config, {
|
|
6861
|
+
blocking: true,
|
|
6862
|
+
requestId
|
|
6863
|
+
});
|
|
6864
|
+
this.applyPendingSummaries();
|
|
6865
|
+
} catch {
|
|
6866
|
+
}
|
|
6867
|
+
}
|
|
6799
6868
|
/** Drain pending compaction summaries and insert at a safe point. */
|
|
6800
6869
|
applyPendingSummaries() {
|
|
6801
6870
|
const summaries = getPendingSummaries();
|
|
@@ -7027,6 +7096,7 @@ var HeadlessSession = class {
|
|
|
7027
7096
|
this.currentAbort = new AbortController();
|
|
7028
7097
|
this.completedEmitted = false;
|
|
7029
7098
|
this.turnStart = Date.now();
|
|
7099
|
+
await this.runForcedCompactionIfNeeded(requestId);
|
|
7030
7100
|
const attachments = parsed.attachments;
|
|
7031
7101
|
if (attachments?.length) {
|
|
7032
7102
|
log14.info("Message has attachments", {
|
|
@@ -7333,29 +7403,19 @@ var HeadlessSession = class {
|
|
|
7333
7403
|
return;
|
|
7334
7404
|
}
|
|
7335
7405
|
if (action === "compact") {
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
}
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
this.applyPendingSummaries();
|
|
7344
|
-
}
|
|
7345
|
-
this.emit("compaction_complete", {}, requestId);
|
|
7346
|
-
this.emit("completed", { success: true }, requestId);
|
|
7347
|
-
},
|
|
7348
|
-
onError: (error) => {
|
|
7349
|
-
this.emit("compaction_complete", { error }, requestId);
|
|
7350
|
-
this.emit("completed", { success: false, error }, requestId);
|
|
7351
|
-
},
|
|
7352
|
-
onFinally: () => {
|
|
7353
|
-
this.sessionStats.compactionInProgress = false;
|
|
7354
|
-
this.sessionStats.lastContextSize = 0;
|
|
7355
|
-
this.sessionStats.messageCount = this.state.messages.length;
|
|
7356
|
-
this.persistStats();
|
|
7406
|
+
try {
|
|
7407
|
+
await triggerCompaction(this.state, this.config, {
|
|
7408
|
+
blocking: false,
|
|
7409
|
+
requestId
|
|
7410
|
+
});
|
|
7411
|
+
if (!this.running) {
|
|
7412
|
+
this.applyPendingSummaries();
|
|
7357
7413
|
}
|
|
7358
|
-
|
|
7414
|
+
this.emit("completed", { success: true }, requestId);
|
|
7415
|
+
} catch (err) {
|
|
7416
|
+
const error = err.message || "Compaction failed";
|
|
7417
|
+
this.emit("completed", { success: false, error }, requestId);
|
|
7418
|
+
}
|
|
7359
7419
|
return;
|
|
7360
7420
|
}
|
|
7361
7421
|
if (action === "message") {
|
package/dist/index.js
CHANGED
|
@@ -1870,22 +1870,37 @@ var init_prompt = __esm({
|
|
|
1870
1870
|
function getPendingSummaries() {
|
|
1871
1871
|
return pendingSummaries.splice(0);
|
|
1872
1872
|
}
|
|
1873
|
-
function
|
|
1874
|
-
|
|
1873
|
+
function setCompactionListener(l) {
|
|
1874
|
+
listener = l;
|
|
1875
|
+
}
|
|
1876
|
+
function triggerCompaction(state, apiConfig, opts = {}) {
|
|
1877
|
+
if (inflightCompaction) {
|
|
1878
|
+
return inflightCompaction;
|
|
1879
|
+
}
|
|
1880
|
+
const { blocking = false, requestId } = opts;
|
|
1881
|
+
listener?.({ type: "started", blocking, requestId });
|
|
1875
1882
|
const system = buildSystemPrompt("onboardingFinished");
|
|
1876
1883
|
const tools2 = getToolDefinitions("onboardingFinished");
|
|
1877
|
-
|
|
1884
|
+
inflightCompaction = compactConversation(
|
|
1885
|
+
state.messages,
|
|
1886
|
+
apiConfig,
|
|
1887
|
+
system,
|
|
1888
|
+
tools2
|
|
1889
|
+
).then((summaries) => {
|
|
1878
1890
|
pendingSummaries.push(...summaries);
|
|
1879
|
-
|
|
1891
|
+
listener?.({ type: "complete", requestId });
|
|
1880
1892
|
log3.info("Compaction complete");
|
|
1881
1893
|
}).catch((err) => {
|
|
1882
|
-
|
|
1883
|
-
|
|
1894
|
+
const message = err.message || "Compaction failed";
|
|
1895
|
+
listener?.({ type: "complete", error: message, requestId });
|
|
1896
|
+
log3.error("Compaction failed", { error: message });
|
|
1897
|
+
throw err;
|
|
1884
1898
|
}).finally(() => {
|
|
1885
|
-
|
|
1899
|
+
inflightCompaction = null;
|
|
1886
1900
|
});
|
|
1901
|
+
return inflightCompaction;
|
|
1887
1902
|
}
|
|
1888
|
-
var log3, pendingSummaries;
|
|
1903
|
+
var log3, pendingSummaries, inflightCompaction, listener;
|
|
1889
1904
|
var init_trigger = __esm({
|
|
1890
1905
|
"src/compaction/trigger.ts"() {
|
|
1891
1906
|
"use strict";
|
|
@@ -1895,6 +1910,8 @@ var init_trigger = __esm({
|
|
|
1895
1910
|
init_logger();
|
|
1896
1911
|
log3 = createLogger("compaction:trigger");
|
|
1897
1912
|
pendingSummaries = [];
|
|
1913
|
+
inflightCompaction = null;
|
|
1914
|
+
listener = null;
|
|
1898
1915
|
}
|
|
1899
1916
|
});
|
|
1900
1917
|
|
|
@@ -1920,8 +1937,10 @@ var init_compactConversation = __esm({
|
|
|
1920
1937
|
}
|
|
1921
1938
|
triggerCompaction(
|
|
1922
1939
|
{ messages: context.conversationMessages },
|
|
1923
|
-
context.apiConfig
|
|
1924
|
-
|
|
1940
|
+
context.apiConfig,
|
|
1941
|
+
{ blocking: false, requestId: context.requestId }
|
|
1942
|
+
).catch(() => {
|
|
1943
|
+
});
|
|
1925
1944
|
return "Compaction started in the background.";
|
|
1926
1945
|
}
|
|
1927
1946
|
};
|
|
@@ -7355,7 +7374,7 @@ var headless_exports = {};
|
|
|
7355
7374
|
__export(headless_exports, {
|
|
7356
7375
|
HeadlessSession: () => HeadlessSession
|
|
7357
7376
|
});
|
|
7358
|
-
var log14, EXTERNAL_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, HeadlessSession;
|
|
7377
|
+
var log14, EXTERNAL_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, FORCED_COMPACTION_THRESHOLD_TOKENS, HeadlessSession;
|
|
7359
7378
|
var init_headless = __esm({
|
|
7360
7379
|
"src/headless/index.ts"() {
|
|
7361
7380
|
"use strict";
|
|
@@ -7382,6 +7401,7 @@ var init_headless = __esm({
|
|
|
7382
7401
|
"confirmDestructiveAction",
|
|
7383
7402
|
"presentPublishPlan"
|
|
7384
7403
|
]);
|
|
7404
|
+
FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
|
|
7385
7405
|
HeadlessSession = class {
|
|
7386
7406
|
// Configuration
|
|
7387
7407
|
opts;
|
|
@@ -7449,6 +7469,24 @@ var init_headless = __esm({
|
|
|
7449
7469
|
}
|
|
7450
7470
|
triggerBrandExtraction(this.config);
|
|
7451
7471
|
this.toolRegistry.onEvent = this.onEvent;
|
|
7472
|
+
setCompactionListener((event) => {
|
|
7473
|
+
if (event.type === "started") {
|
|
7474
|
+
this.emit(
|
|
7475
|
+
"compaction_started",
|
|
7476
|
+
{ blocking: event.blocking },
|
|
7477
|
+
event.requestId
|
|
7478
|
+
);
|
|
7479
|
+
this.sessionStats.compactionInProgress = true;
|
|
7480
|
+
this.persistStats();
|
|
7481
|
+
} else {
|
|
7482
|
+
const data = event.error ? { error: event.error } : {};
|
|
7483
|
+
this.emit("compaction_complete", data, event.requestId);
|
|
7484
|
+
this.sessionStats.compactionInProgress = false;
|
|
7485
|
+
this.sessionStats.lastContextSize = 0;
|
|
7486
|
+
this.sessionStats.messageCount = this.state.messages.length;
|
|
7487
|
+
this.persistStats();
|
|
7488
|
+
}
|
|
7489
|
+
});
|
|
7452
7490
|
process.stdin.setEncoding("utf-8");
|
|
7453
7491
|
process.stdin.on("data", (chunk) => {
|
|
7454
7492
|
this.stdinBuffer += chunk;
|
|
@@ -7550,6 +7588,37 @@ var init_headless = __esm({
|
|
|
7550
7588
|
}
|
|
7551
7589
|
saveSession(this.state);
|
|
7552
7590
|
}
|
|
7591
|
+
/**
|
|
7592
|
+
* Forced compaction gate. If lastContextSize exceeds the threshold, compact
|
|
7593
|
+
* before letting the upcoming turn run. Coalesces with any in-flight
|
|
7594
|
+
* compaction (e.g., one already started by /compact or a tool call). No
|
|
7595
|
+
* timeout — compaction takes as long as it takes.
|
|
7596
|
+
*
|
|
7597
|
+
* Lifecycle events (`compaction_started` / `compaction_complete`) and
|
|
7598
|
+
* stats updates are handled by the listener registered in start(); this
|
|
7599
|
+
* method only awaits the promise and applies the resulting summaries.
|
|
7600
|
+
*
|
|
7601
|
+
* On compaction failure we don't bail — the turn proceeds and surfaces any
|
|
7602
|
+
* downstream overflow through the existing "prompt is too long" path.
|
|
7603
|
+
*/
|
|
7604
|
+
async runForcedCompactionIfNeeded(requestId) {
|
|
7605
|
+
if (this.sessionStats.lastContextSize <= FORCED_COMPACTION_THRESHOLD_TOKENS) {
|
|
7606
|
+
return;
|
|
7607
|
+
}
|
|
7608
|
+
log14.info("Forced compaction gate triggered", {
|
|
7609
|
+
contextSize: this.sessionStats.lastContextSize,
|
|
7610
|
+
threshold: FORCED_COMPACTION_THRESHOLD_TOKENS,
|
|
7611
|
+
requestId
|
|
7612
|
+
});
|
|
7613
|
+
try {
|
|
7614
|
+
await triggerCompaction(this.state, this.config, {
|
|
7615
|
+
blocking: true,
|
|
7616
|
+
requestId
|
|
7617
|
+
});
|
|
7618
|
+
this.applyPendingSummaries();
|
|
7619
|
+
} catch {
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7553
7622
|
/** Drain pending compaction summaries and insert at a safe point. */
|
|
7554
7623
|
applyPendingSummaries() {
|
|
7555
7624
|
const summaries = getPendingSummaries();
|
|
@@ -7781,6 +7850,7 @@ var init_headless = __esm({
|
|
|
7781
7850
|
this.currentAbort = new AbortController();
|
|
7782
7851
|
this.completedEmitted = false;
|
|
7783
7852
|
this.turnStart = Date.now();
|
|
7853
|
+
await this.runForcedCompactionIfNeeded(requestId);
|
|
7784
7854
|
const attachments = parsed.attachments;
|
|
7785
7855
|
if (attachments?.length) {
|
|
7786
7856
|
log14.info("Message has attachments", {
|
|
@@ -8087,29 +8157,19 @@ var init_headless = __esm({
|
|
|
8087
8157
|
return;
|
|
8088
8158
|
}
|
|
8089
8159
|
if (action === "compact") {
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
}
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
this.applyPendingSummaries();
|
|
8098
|
-
}
|
|
8099
|
-
this.emit("compaction_complete", {}, requestId);
|
|
8100
|
-
this.emit("completed", { success: true }, requestId);
|
|
8101
|
-
},
|
|
8102
|
-
onError: (error) => {
|
|
8103
|
-
this.emit("compaction_complete", { error }, requestId);
|
|
8104
|
-
this.emit("completed", { success: false, error }, requestId);
|
|
8105
|
-
},
|
|
8106
|
-
onFinally: () => {
|
|
8107
|
-
this.sessionStats.compactionInProgress = false;
|
|
8108
|
-
this.sessionStats.lastContextSize = 0;
|
|
8109
|
-
this.sessionStats.messageCount = this.state.messages.length;
|
|
8110
|
-
this.persistStats();
|
|
8160
|
+
try {
|
|
8161
|
+
await triggerCompaction(this.state, this.config, {
|
|
8162
|
+
blocking: false,
|
|
8163
|
+
requestId
|
|
8164
|
+
});
|
|
8165
|
+
if (!this.running) {
|
|
8166
|
+
this.applyPendingSummaries();
|
|
8111
8167
|
}
|
|
8112
|
-
|
|
8168
|
+
this.emit("completed", { success: true }, requestId);
|
|
8169
|
+
} catch (err) {
|
|
8170
|
+
const error = err.message || "Compaction failed";
|
|
8171
|
+
this.emit("completed", { success: false, error }, requestId);
|
|
8172
|
+
}
|
|
8113
8173
|
return;
|
|
8114
8174
|
}
|
|
8115
8175
|
if (action === "message") {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
- Work with what you already know. If you've read a file in this session, use what you learned rather than reading it again. If a subagent already researched something, use its findings. Every tool call costs time; prefer acting on information you have over re-gathering it.
|
|
14
14
|
- When multiple tool calls are independent, make them all in a single turn. Reading three files, writing two methods, or running a scenario while taking a screenshot: batch them instead of doing one per turn.
|
|
15
15
|
- After two failed attempts at the same approach, tell the user what's going wrong.
|
|
16
|
-
- Never estimate how long something will take or how much it will cost. Just do it. If the user asks,
|
|
16
|
+
- Never estimate how long something will take or how much it will cost. Just do it. If the user asks, politely refuse — any number would be a guess. Never quote concrete time units for work you're about to do. You can describe scope qualitatively (small change, large refactor, etc.), but never estimate the time it will take you to do work.
|
|
17
17
|
- Pushing to main branch will trigger a deploy. The user presses the publish button in the interface to request publishing.
|
|
18
18
|
|
|
19
19
|
### Build Notes
|