@mindstudio-ai/remy 0.1.163 → 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 +15 -1
- package/dist/headless.js +117 -40
- package/dist/index.js +119 -40
- package/dist/prompt/static/instructions.md +1 -1
- package/package.json +1 -1
package/dist/headless.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ declare class HeadlessSession {
|
|
|
55
55
|
private earlyResults;
|
|
56
56
|
private pendingBlockUpdates;
|
|
57
57
|
private toolRegistry;
|
|
58
|
-
private
|
|
58
|
+
private stdinBuffer;
|
|
59
59
|
constructor(opts?: HeadlessOptions);
|
|
60
60
|
start(): Promise<void>;
|
|
61
61
|
private shutdown;
|
|
@@ -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
|
@@ -4,9 +4,6 @@ var __export = (target, all) => {
|
|
|
4
4
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
// src/headless/index.ts
|
|
8
|
-
import { createInterface } from "readline";
|
|
9
|
-
|
|
10
7
|
// src/logger.ts
|
|
11
8
|
import fs from "fs";
|
|
12
9
|
var LEVELS = {
|
|
@@ -1760,8 +1757,10 @@ var compactConversationTool = {
|
|
|
1760
1757
|
}
|
|
1761
1758
|
triggerCompaction(
|
|
1762
1759
|
{ messages: context.conversationMessages },
|
|
1763
|
-
context.apiConfig
|
|
1764
|
-
|
|
1760
|
+
context.apiConfig,
|
|
1761
|
+
{ blocking: false, requestId: context.requestId }
|
|
1762
|
+
).catch(() => {
|
|
1763
|
+
});
|
|
1765
1764
|
return "Compaction started in the background.";
|
|
1766
1765
|
}
|
|
1767
1766
|
};
|
|
@@ -5187,23 +5186,40 @@ function executeTool(name, input, context) {
|
|
|
5187
5186
|
// src/compaction/trigger.ts
|
|
5188
5187
|
var log7 = createLogger("compaction:trigger");
|
|
5189
5188
|
var pendingSummaries = [];
|
|
5189
|
+
var inflightCompaction = null;
|
|
5190
5190
|
function getPendingSummaries() {
|
|
5191
5191
|
return pendingSummaries.splice(0);
|
|
5192
5192
|
}
|
|
5193
|
-
|
|
5194
|
-
|
|
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 });
|
|
5195
5203
|
const system = buildSystemPrompt("onboardingFinished");
|
|
5196
5204
|
const tools2 = getToolDefinitions("onboardingFinished");
|
|
5197
|
-
|
|
5205
|
+
inflightCompaction = compactConversation(
|
|
5206
|
+
state.messages,
|
|
5207
|
+
apiConfig,
|
|
5208
|
+
system,
|
|
5209
|
+
tools2
|
|
5210
|
+
).then((summaries) => {
|
|
5198
5211
|
pendingSummaries.push(...summaries);
|
|
5199
|
-
|
|
5212
|
+
listener?.({ type: "complete", requestId });
|
|
5200
5213
|
log7.info("Compaction complete");
|
|
5201
5214
|
}).catch((err) => {
|
|
5202
|
-
|
|
5203
|
-
|
|
5215
|
+
const message = err.message || "Compaction failed";
|
|
5216
|
+
listener?.({ type: "complete", error: message, requestId });
|
|
5217
|
+
log7.error("Compaction failed", { error: message });
|
|
5218
|
+
throw err;
|
|
5204
5219
|
}).finally(() => {
|
|
5205
|
-
|
|
5220
|
+
inflightCompaction = null;
|
|
5206
5221
|
});
|
|
5222
|
+
return inflightCompaction;
|
|
5207
5223
|
}
|
|
5208
5224
|
|
|
5209
5225
|
// src/brandExtraction/index.ts
|
|
@@ -6631,6 +6647,7 @@ var USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
|
6631
6647
|
"confirmDestructiveAction",
|
|
6632
6648
|
"presentPublishPlan"
|
|
6633
6649
|
]);
|
|
6650
|
+
var FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
|
|
6634
6651
|
var HeadlessSession = class {
|
|
6635
6652
|
// Configuration
|
|
6636
6653
|
opts;
|
|
@@ -6666,8 +6683,8 @@ var HeadlessSession = class {
|
|
|
6666
6683
|
pendingBlockUpdates = [];
|
|
6667
6684
|
// Tool lifecycle management — shared across all nesting depths
|
|
6668
6685
|
toolRegistry = new ToolRegistry();
|
|
6669
|
-
// IO
|
|
6670
|
-
|
|
6686
|
+
// IO — accumulates stdin bytes between newline boundaries
|
|
6687
|
+
stdinBuffer = "";
|
|
6671
6688
|
constructor(opts = {}) {
|
|
6672
6689
|
this.opts = opts;
|
|
6673
6690
|
}
|
|
@@ -6698,9 +6715,42 @@ var HeadlessSession = class {
|
|
|
6698
6715
|
}
|
|
6699
6716
|
triggerBrandExtraction(this.config);
|
|
6700
6717
|
this.toolRegistry.onEvent = this.onEvent;
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
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
|
+
});
|
|
6736
|
+
process.stdin.setEncoding("utf-8");
|
|
6737
|
+
process.stdin.on("data", (chunk) => {
|
|
6738
|
+
this.stdinBuffer += chunk;
|
|
6739
|
+
let nlIdx;
|
|
6740
|
+
while ((nlIdx = this.stdinBuffer.indexOf("\n")) !== -1) {
|
|
6741
|
+
const endIdx = nlIdx > 0 && this.stdinBuffer[nlIdx - 1] === "\r" ? nlIdx - 1 : nlIdx;
|
|
6742
|
+
const line = this.stdinBuffer.slice(0, endIdx);
|
|
6743
|
+
this.stdinBuffer = this.stdinBuffer.slice(nlIdx + 1);
|
|
6744
|
+
if (line.length > 0) {
|
|
6745
|
+
void this.handleStdinLine(line);
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
});
|
|
6749
|
+
process.stdin.on("end", () => {
|
|
6750
|
+
if (this.stdinBuffer.length > 0) {
|
|
6751
|
+
void this.handleStdinLine(this.stdinBuffer);
|
|
6752
|
+
this.stdinBuffer = "";
|
|
6753
|
+
}
|
|
6704
6754
|
this.emit("stopping");
|
|
6705
6755
|
this.emit("stopped");
|
|
6706
6756
|
process.exit(0);
|
|
@@ -6784,6 +6834,37 @@ var HeadlessSession = class {
|
|
|
6784
6834
|
}
|
|
6785
6835
|
saveSession(this.state);
|
|
6786
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
|
+
}
|
|
6787
6868
|
/** Drain pending compaction summaries and insert at a safe point. */
|
|
6788
6869
|
applyPendingSummaries() {
|
|
6789
6870
|
const summaries = getPendingSummaries();
|
|
@@ -7015,6 +7096,7 @@ var HeadlessSession = class {
|
|
|
7015
7096
|
this.currentAbort = new AbortController();
|
|
7016
7097
|
this.completedEmitted = false;
|
|
7017
7098
|
this.turnStart = Date.now();
|
|
7099
|
+
await this.runForcedCompactionIfNeeded(requestId);
|
|
7018
7100
|
const attachments = parsed.attachments;
|
|
7019
7101
|
if (attachments?.length) {
|
|
7020
7102
|
log14.info("Message has attachments", {
|
|
@@ -7234,7 +7316,12 @@ var HeadlessSession = class {
|
|
|
7234
7316
|
let parsed;
|
|
7235
7317
|
try {
|
|
7236
7318
|
parsed = JSON.parse(line);
|
|
7237
|
-
} catch {
|
|
7319
|
+
} catch (err) {
|
|
7320
|
+
log14.warn("Invalid JSON on stdin", {
|
|
7321
|
+
error: err.message,
|
|
7322
|
+
lineLength: line.length,
|
|
7323
|
+
preview: line.slice(0, 200)
|
|
7324
|
+
});
|
|
7238
7325
|
this.emit("error", { error: "Invalid JSON on stdin" });
|
|
7239
7326
|
return;
|
|
7240
7327
|
}
|
|
@@ -7316,29 +7403,19 @@ var HeadlessSession = class {
|
|
|
7316
7403
|
return;
|
|
7317
7404
|
}
|
|
7318
7405
|
if (action === "compact") {
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
}
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
this.applyPendingSummaries();
|
|
7327
|
-
}
|
|
7328
|
-
this.emit("compaction_complete", {}, requestId);
|
|
7329
|
-
this.emit("completed", { success: true }, requestId);
|
|
7330
|
-
},
|
|
7331
|
-
onError: (error) => {
|
|
7332
|
-
this.emit("compaction_complete", { error }, requestId);
|
|
7333
|
-
this.emit("completed", { success: false, error }, requestId);
|
|
7334
|
-
},
|
|
7335
|
-
onFinally: () => {
|
|
7336
|
-
this.sessionStats.compactionInProgress = false;
|
|
7337
|
-
this.sessionStats.lastContextSize = 0;
|
|
7338
|
-
this.sessionStats.messageCount = this.state.messages.length;
|
|
7339
|
-
this.persistStats();
|
|
7406
|
+
try {
|
|
7407
|
+
await triggerCompaction(this.state, this.config, {
|
|
7408
|
+
blocking: false,
|
|
7409
|
+
requestId
|
|
7410
|
+
});
|
|
7411
|
+
if (!this.running) {
|
|
7412
|
+
this.applyPendingSummaries();
|
|
7340
7413
|
}
|
|
7341
|
-
|
|
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
|
+
}
|
|
7342
7419
|
return;
|
|
7343
7420
|
}
|
|
7344
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,8 +7374,7 @@ var headless_exports = {};
|
|
|
7355
7374
|
__export(headless_exports, {
|
|
7356
7375
|
HeadlessSession: () => HeadlessSession
|
|
7357
7376
|
});
|
|
7358
|
-
|
|
7359
|
-
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;
|
|
7360
7378
|
var init_headless = __esm({
|
|
7361
7379
|
"src/headless/index.ts"() {
|
|
7362
7380
|
"use strict";
|
|
@@ -7383,6 +7401,7 @@ var init_headless = __esm({
|
|
|
7383
7401
|
"confirmDestructiveAction",
|
|
7384
7402
|
"presentPublishPlan"
|
|
7385
7403
|
]);
|
|
7404
|
+
FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
|
|
7386
7405
|
HeadlessSession = class {
|
|
7387
7406
|
// Configuration
|
|
7388
7407
|
opts;
|
|
@@ -7418,8 +7437,8 @@ var init_headless = __esm({
|
|
|
7418
7437
|
pendingBlockUpdates = [];
|
|
7419
7438
|
// Tool lifecycle management — shared across all nesting depths
|
|
7420
7439
|
toolRegistry = new ToolRegistry();
|
|
7421
|
-
// IO
|
|
7422
|
-
|
|
7440
|
+
// IO — accumulates stdin bytes between newline boundaries
|
|
7441
|
+
stdinBuffer = "";
|
|
7423
7442
|
constructor(opts = {}) {
|
|
7424
7443
|
this.opts = opts;
|
|
7425
7444
|
}
|
|
@@ -7450,9 +7469,42 @@ var init_headless = __esm({
|
|
|
7450
7469
|
}
|
|
7451
7470
|
triggerBrandExtraction(this.config);
|
|
7452
7471
|
this.toolRegistry.onEvent = this.onEvent;
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
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
|
+
});
|
|
7490
|
+
process.stdin.setEncoding("utf-8");
|
|
7491
|
+
process.stdin.on("data", (chunk) => {
|
|
7492
|
+
this.stdinBuffer += chunk;
|
|
7493
|
+
let nlIdx;
|
|
7494
|
+
while ((nlIdx = this.stdinBuffer.indexOf("\n")) !== -1) {
|
|
7495
|
+
const endIdx = nlIdx > 0 && this.stdinBuffer[nlIdx - 1] === "\r" ? nlIdx - 1 : nlIdx;
|
|
7496
|
+
const line = this.stdinBuffer.slice(0, endIdx);
|
|
7497
|
+
this.stdinBuffer = this.stdinBuffer.slice(nlIdx + 1);
|
|
7498
|
+
if (line.length > 0) {
|
|
7499
|
+
void this.handleStdinLine(line);
|
|
7500
|
+
}
|
|
7501
|
+
}
|
|
7502
|
+
});
|
|
7503
|
+
process.stdin.on("end", () => {
|
|
7504
|
+
if (this.stdinBuffer.length > 0) {
|
|
7505
|
+
void this.handleStdinLine(this.stdinBuffer);
|
|
7506
|
+
this.stdinBuffer = "";
|
|
7507
|
+
}
|
|
7456
7508
|
this.emit("stopping");
|
|
7457
7509
|
this.emit("stopped");
|
|
7458
7510
|
process.exit(0);
|
|
@@ -7536,6 +7588,37 @@ var init_headless = __esm({
|
|
|
7536
7588
|
}
|
|
7537
7589
|
saveSession(this.state);
|
|
7538
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
|
+
}
|
|
7539
7622
|
/** Drain pending compaction summaries and insert at a safe point. */
|
|
7540
7623
|
applyPendingSummaries() {
|
|
7541
7624
|
const summaries = getPendingSummaries();
|
|
@@ -7767,6 +7850,7 @@ var init_headless = __esm({
|
|
|
7767
7850
|
this.currentAbort = new AbortController();
|
|
7768
7851
|
this.completedEmitted = false;
|
|
7769
7852
|
this.turnStart = Date.now();
|
|
7853
|
+
await this.runForcedCompactionIfNeeded(requestId);
|
|
7770
7854
|
const attachments = parsed.attachments;
|
|
7771
7855
|
if (attachments?.length) {
|
|
7772
7856
|
log14.info("Message has attachments", {
|
|
@@ -7986,7 +8070,12 @@ var init_headless = __esm({
|
|
|
7986
8070
|
let parsed;
|
|
7987
8071
|
try {
|
|
7988
8072
|
parsed = JSON.parse(line);
|
|
7989
|
-
} catch {
|
|
8073
|
+
} catch (err) {
|
|
8074
|
+
log14.warn("Invalid JSON on stdin", {
|
|
8075
|
+
error: err.message,
|
|
8076
|
+
lineLength: line.length,
|
|
8077
|
+
preview: line.slice(0, 200)
|
|
8078
|
+
});
|
|
7990
8079
|
this.emit("error", { error: "Invalid JSON on stdin" });
|
|
7991
8080
|
return;
|
|
7992
8081
|
}
|
|
@@ -8068,29 +8157,19 @@ var init_headless = __esm({
|
|
|
8068
8157
|
return;
|
|
8069
8158
|
}
|
|
8070
8159
|
if (action === "compact") {
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
}
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
this.applyPendingSummaries();
|
|
8079
|
-
}
|
|
8080
|
-
this.emit("compaction_complete", {}, requestId);
|
|
8081
|
-
this.emit("completed", { success: true }, requestId);
|
|
8082
|
-
},
|
|
8083
|
-
onError: (error) => {
|
|
8084
|
-
this.emit("compaction_complete", { error }, requestId);
|
|
8085
|
-
this.emit("completed", { success: false, error }, requestId);
|
|
8086
|
-
},
|
|
8087
|
-
onFinally: () => {
|
|
8088
|
-
this.sessionStats.compactionInProgress = false;
|
|
8089
|
-
this.sessionStats.lastContextSize = 0;
|
|
8090
|
-
this.sessionStats.messageCount = this.state.messages.length;
|
|
8091
|
-
this.persistStats();
|
|
8160
|
+
try {
|
|
8161
|
+
await triggerCompaction(this.state, this.config, {
|
|
8162
|
+
blocking: false,
|
|
8163
|
+
requestId
|
|
8164
|
+
});
|
|
8165
|
+
if (!this.running) {
|
|
8166
|
+
this.applyPendingSummaries();
|
|
8092
8167
|
}
|
|
8093
|
-
|
|
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
|
+
}
|
|
8094
8173
|
return;
|
|
8095
8174
|
}
|
|
8096
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
|