@wrongstack/core 0.3.1 → 0.3.2
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/{compactor-BUU6Zm_3.d.ts → compactor-DpJBI1YH.d.ts} +7 -1
- package/dist/{config-CKLYPkCi.d.ts → config-D2qvAxVd.d.ts} +38 -1
- package/dist/coordination/index.d.ts +3 -3
- package/dist/coordination/index.js +283 -244
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +7 -7
- package/dist/defaults/index.js +803 -524
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-CNB9PALO.d.ts → events-BHIQs4o1.d.ts} +7 -0
- package/dist/execution/index.d.ts +10 -7
- package/dist/execution/index.js +166 -18
- package/dist/execution/index.js.map +1 -1
- package/dist/extension/index.d.ts +3 -3
- package/dist/extension/index.js +14 -7
- package/dist/extension/index.js.map +1 -1
- package/dist/{index-BDb0cAMP.d.ts → index-hWNybrNZ.d.ts} +3 -5
- package/dist/index.d.ts +12 -12
- package/dist/index.js +629 -299
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +5 -5
- package/dist/infrastructure/index.js +191 -20
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +4 -4
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-DR35ojJZ.d.ts → mcp-servers-C2OopXOn.d.ts} +20 -4
- package/dist/observability/index.d.ts +1 -1
- package/dist/{path-resolver-Cl_q0u-R.d.ts → path-resolver--59rCou3.d.ts} +1 -1
- package/dist/{provider-runner-BXuADQqQ.d.ts → provider-runner-B39miKRw.d.ts} +1 -1
- package/dist/sdd/index.d.ts +1 -1
- package/dist/storage/index.d.ts +4 -3
- package/dist/storage/index.js +180 -13
- package/dist/storage/index.js.map +1 -1
- package/dist/{tool-executor-DKu4A6nB.d.ts → tool-executor-HsBLGRaA.d.ts} +2 -2
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.js +206 -9
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +23 -2
- package/dist/utils/index.js +93 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/storage/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { randomBytes, randomUUID } from 'crypto';
|
|
2
2
|
import * as fsp from 'fs/promises';
|
|
3
3
|
import * as path2 from 'path';
|
|
4
|
-
import 'fs';
|
|
5
4
|
import * as os from 'os';
|
|
6
5
|
|
|
7
6
|
// src/storage/session-store.ts
|
|
@@ -70,6 +69,98 @@ async function renameWithRetry(from, to) {
|
|
|
70
69
|
throw lastErr;
|
|
71
70
|
}
|
|
72
71
|
|
|
72
|
+
// src/utils/message-invariants.ts
|
|
73
|
+
function repairToolUseAdjacency(messages) {
|
|
74
|
+
const removedToolUses = [];
|
|
75
|
+
const removedToolResults = [];
|
|
76
|
+
let removedMessages = 0;
|
|
77
|
+
let changed = false;
|
|
78
|
+
const out = [];
|
|
79
|
+
for (let i = 0; i < messages.length; i++) {
|
|
80
|
+
const original = messages[i];
|
|
81
|
+
let msg = original;
|
|
82
|
+
if (hasToolUse(msg)) {
|
|
83
|
+
const nextIds = toolResultIds(messages[i + 1]);
|
|
84
|
+
const filtered = mapContent(msg, (blocks) => {
|
|
85
|
+
const next = [];
|
|
86
|
+
for (const block of blocks) {
|
|
87
|
+
if (block.type === "tool_use" && !nextIds.has(block.id)) {
|
|
88
|
+
removedToolUses.push(block.id);
|
|
89
|
+
changed = true;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
next.push(block);
|
|
93
|
+
}
|
|
94
|
+
return next;
|
|
95
|
+
});
|
|
96
|
+
msg = filtered ?? msg;
|
|
97
|
+
}
|
|
98
|
+
if (hasToolResult(msg)) {
|
|
99
|
+
const allowed = toolUseIds(out[out.length - 1]);
|
|
100
|
+
const filtered = mapContent(msg, (blocks) => {
|
|
101
|
+
const next = [];
|
|
102
|
+
for (const block of blocks) {
|
|
103
|
+
if (block.type === "tool_result" && !allowed.has(block.tool_use_id)) {
|
|
104
|
+
removedToolResults.push(block.tool_use_id);
|
|
105
|
+
changed = true;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
next.push(block);
|
|
109
|
+
}
|
|
110
|
+
return next;
|
|
111
|
+
});
|
|
112
|
+
msg = filtered ?? msg;
|
|
113
|
+
}
|
|
114
|
+
if (isEmptyMessage(msg)) {
|
|
115
|
+
removedMessages++;
|
|
116
|
+
changed = true;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
out.push(msg);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
messages: changed ? out : messages,
|
|
123
|
+
report: { changed, removedToolUses, removedToolResults, removedMessages }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function hasToolUse(msg) {
|
|
127
|
+
return contentBlocks(msg).some((b) => b.type === "tool_use");
|
|
128
|
+
}
|
|
129
|
+
function hasToolResult(msg) {
|
|
130
|
+
return contentBlocks(msg).some((b) => b.type === "tool_result");
|
|
131
|
+
}
|
|
132
|
+
function toolUseIds(msg) {
|
|
133
|
+
const ids = /* @__PURE__ */ new Set();
|
|
134
|
+
if (!msg || msg.role !== "assistant") return ids;
|
|
135
|
+
for (const block of contentBlocks(msg)) {
|
|
136
|
+
if (block.type === "tool_use") ids.add(block.id);
|
|
137
|
+
}
|
|
138
|
+
return ids;
|
|
139
|
+
}
|
|
140
|
+
function toolResultIds(msg) {
|
|
141
|
+
const ids = /* @__PURE__ */ new Set();
|
|
142
|
+
if (!msg || msg.role !== "user") return ids;
|
|
143
|
+
for (const block of contentBlocks(msg)) {
|
|
144
|
+
if (block.type === "tool_result") ids.add(block.tool_use_id);
|
|
145
|
+
}
|
|
146
|
+
return ids;
|
|
147
|
+
}
|
|
148
|
+
function contentBlocks(msg) {
|
|
149
|
+
return msg && Array.isArray(msg.content) ? msg.content : [];
|
|
150
|
+
}
|
|
151
|
+
function mapContent(msg, fn) {
|
|
152
|
+
if (!Array.isArray(msg.content)) return msg;
|
|
153
|
+
const next = fn(msg.content);
|
|
154
|
+
if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {
|
|
155
|
+
return msg;
|
|
156
|
+
}
|
|
157
|
+
return { ...msg, content: next };
|
|
158
|
+
}
|
|
159
|
+
function isEmptyMessage(msg) {
|
|
160
|
+
if (typeof msg.content === "string") return msg.content.trim().length === 0;
|
|
161
|
+
return msg.content.length === 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
73
164
|
// src/storage/session-store.ts
|
|
74
165
|
var DefaultSessionStore = class {
|
|
75
166
|
dir;
|
|
@@ -272,11 +363,17 @@ var DefaultSessionStore = class {
|
|
|
272
363
|
if (openToolUses.size > 0) {
|
|
273
364
|
this.events?.emit("session.damaged", {
|
|
274
365
|
sessionId,
|
|
275
|
-
detail: `${openToolUses.size} tool_use blocks without matching results
|
|
366
|
+
detail: `${openToolUses.size} tool_use blocks without matching results - replay repaired`
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
const repaired = repairToolUseAdjacency(messages);
|
|
370
|
+
if (repaired.report.changed) {
|
|
371
|
+
this.events?.emit("session.damaged", {
|
|
372
|
+
sessionId,
|
|
373
|
+
detail: `Repaired replay adjacency: removed ${repaired.report.removedToolUses.length} tool_use, ${repaired.report.removedToolResults.length} tool_result, ${repaired.report.removedMessages} empty messages`
|
|
276
374
|
});
|
|
277
|
-
return { messages, usage };
|
|
278
375
|
}
|
|
279
|
-
return { messages, usage };
|
|
376
|
+
return { messages: repaired.messages, usage };
|
|
280
377
|
}
|
|
281
378
|
};
|
|
282
379
|
var FileSessionWriter = class {
|
|
@@ -302,6 +399,7 @@ var FileSessionWriter = class {
|
|
|
302
399
|
startedAt;
|
|
303
400
|
meta;
|
|
304
401
|
closed = false;
|
|
402
|
+
closing = false;
|
|
305
403
|
manifestFile;
|
|
306
404
|
summary;
|
|
307
405
|
tokenIn = 0;
|
|
@@ -317,9 +415,7 @@ var FileSessionWriter = class {
|
|
|
317
415
|
resumed;
|
|
318
416
|
appendFailCount = 0;
|
|
319
417
|
lastAppendWarnAt = 0;
|
|
320
|
-
async
|
|
321
|
-
if (this.initDone || this.closed) return;
|
|
322
|
-
this.initDone = true;
|
|
418
|
+
async writeSessionStartLazy() {
|
|
323
419
|
const record = `${JSON.stringify({
|
|
324
420
|
type: this.resumed ? "session_resumed" : "session_start",
|
|
325
421
|
ts: this.startedAt,
|
|
@@ -338,7 +434,8 @@ var FileSessionWriter = class {
|
|
|
338
434
|
async append(event) {
|
|
339
435
|
if (this.closed) return;
|
|
340
436
|
if (!this.initDone) {
|
|
341
|
-
|
|
437
|
+
this.initDone = true;
|
|
438
|
+
await this.writeSessionStartLazy();
|
|
342
439
|
}
|
|
343
440
|
this.observeForSummary(event);
|
|
344
441
|
try {
|
|
@@ -379,7 +476,8 @@ var FileSessionWriter = class {
|
|
|
379
476
|
}
|
|
380
477
|
}
|
|
381
478
|
async close() {
|
|
382
|
-
if (this.
|
|
479
|
+
if (this.closing) return;
|
|
480
|
+
this.closing = true;
|
|
383
481
|
this.closed = true;
|
|
384
482
|
if (this.manifestFile) {
|
|
385
483
|
try {
|
|
@@ -781,6 +879,8 @@ function deepFreeze(obj) {
|
|
|
781
879
|
}
|
|
782
880
|
return Object.freeze(obj);
|
|
783
881
|
}
|
|
882
|
+
|
|
883
|
+
// src/security/config-secrets.ts
|
|
784
884
|
function decryptConfigSecrets(cfg, vault) {
|
|
785
885
|
return walk(cfg, vault, (v, key) => {
|
|
786
886
|
try {
|
|
@@ -820,6 +920,57 @@ function isSecretField(name) {
|
|
|
820
920
|
return SECRET_KEY_PATTERN.test(lc);
|
|
821
921
|
}
|
|
822
922
|
|
|
923
|
+
// src/types/context-window.ts
|
|
924
|
+
var DEFAULT_CONTEXT_WINDOW_MODE_ID = "balanced";
|
|
925
|
+
var CONTEXT_WINDOW_MODES = Object.freeze([
|
|
926
|
+
{
|
|
927
|
+
id: "balanced",
|
|
928
|
+
name: "Balanced",
|
|
929
|
+
description: "Default rolling compaction: recent work stays verbatim, old tool output is trimmed.",
|
|
930
|
+
thresholds: { warn: 0.6, soft: 0.75, hard: 0.9 },
|
|
931
|
+
aggressiveOn: "soft",
|
|
932
|
+
preserveK: 10,
|
|
933
|
+
eliseThreshold: 2e3,
|
|
934
|
+
targetLoad: 0.65
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
id: "frugal",
|
|
938
|
+
name: "Frugal",
|
|
939
|
+
description: "Token-saver mode: compacts early and keeps a tighter verbatim tail.",
|
|
940
|
+
thresholds: { warn: 0.45, soft: 0.6, hard: 0.75 },
|
|
941
|
+
aggressiveOn: "warn",
|
|
942
|
+
preserveK: 6,
|
|
943
|
+
eliseThreshold: 700,
|
|
944
|
+
targetLoad: 0.5
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
id: "deep",
|
|
948
|
+
name: "Deep",
|
|
949
|
+
description: "Long-reasoning mode: delays compaction and keeps more recent turns intact.",
|
|
950
|
+
thresholds: { warn: 0.72, soft: 0.86, hard: 0.96 },
|
|
951
|
+
aggressiveOn: "hard",
|
|
952
|
+
preserveK: 18,
|
|
953
|
+
eliseThreshold: 5e3,
|
|
954
|
+
targetLoad: 0.78
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
id: "archival",
|
|
958
|
+
name: "Archival",
|
|
959
|
+
description: "Decision-preserving mode: compacts steadily while keeping summaries prominent.",
|
|
960
|
+
thresholds: { warn: 0.55, soft: 0.7, hard: 0.84 },
|
|
961
|
+
aggressiveOn: "soft",
|
|
962
|
+
preserveK: 8,
|
|
963
|
+
eliseThreshold: 1200,
|
|
964
|
+
targetLoad: 0.58
|
|
965
|
+
}
|
|
966
|
+
]);
|
|
967
|
+
function listContextWindowModes() {
|
|
968
|
+
return CONTEXT_WINDOW_MODES.map((m) => ({ ...m, thresholds: { ...m.thresholds } }));
|
|
969
|
+
}
|
|
970
|
+
function isContextWindowModeId(id) {
|
|
971
|
+
return CONTEXT_WINDOW_MODES.some((m) => m.id === id);
|
|
972
|
+
}
|
|
973
|
+
|
|
823
974
|
// src/utils/safe-json.ts
|
|
824
975
|
function safeParse(input, maxBytes = 5e6) {
|
|
825
976
|
if (input.length > maxBytes) {
|
|
@@ -839,6 +990,7 @@ function safeParse(input, maxBytes = 5e6) {
|
|
|
839
990
|
var BEHAVIOR_DEFAULTS = {
|
|
840
991
|
version: 1,
|
|
841
992
|
context: {
|
|
993
|
+
mode: DEFAULT_CONTEXT_WINDOW_MODE_ID,
|
|
842
994
|
warnThreshold: 0.6,
|
|
843
995
|
softThreshold: 0.75,
|
|
844
996
|
hardThreshold: 0.9,
|
|
@@ -1013,6 +1165,10 @@ var DefaultConfigLoader = class {
|
|
|
1013
1165
|
if (c.warnThreshold >= c.softThreshold || c.softThreshold >= c.hardThreshold) {
|
|
1014
1166
|
throw new Error("Config: context thresholds must satisfy warn < soft < hard");
|
|
1015
1167
|
}
|
|
1168
|
+
if (c.mode !== void 0 && !isContextWindowModeId(c.mode)) {
|
|
1169
|
+
const known = listContextWindowModes().map((m) => m.id).join(", ");
|
|
1170
|
+
throw new Error(`Config: context.mode must be one of: ${known}`);
|
|
1171
|
+
}
|
|
1016
1172
|
}
|
|
1017
1173
|
validateIdentity(cfg) {
|
|
1018
1174
|
if (!cfg.provider) {
|
|
@@ -1589,24 +1745,35 @@ async function saveTodosCheckpoint(filePath, sessionId, todos) {
|
|
|
1589
1745
|
function attachTodosCheckpoint(state, filePath, sessionId) {
|
|
1590
1746
|
let timer = null;
|
|
1591
1747
|
let pending = null;
|
|
1748
|
+
let writeChain = Promise.resolve();
|
|
1749
|
+
const enqueueWrite = (todos) => {
|
|
1750
|
+
writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos));
|
|
1751
|
+
return writeChain;
|
|
1752
|
+
};
|
|
1592
1753
|
const flush = () => {
|
|
1593
1754
|
timer = null;
|
|
1594
1755
|
if (pending) {
|
|
1595
|
-
|
|
1756
|
+
const todos = pending;
|
|
1596
1757
|
pending = null;
|
|
1758
|
+
return enqueueWrite(todos);
|
|
1597
1759
|
}
|
|
1760
|
+
return writeChain;
|
|
1598
1761
|
};
|
|
1599
1762
|
const unsubscribe = state.onChange((change) => {
|
|
1600
1763
|
if (change.kind !== "todos_replaced") return;
|
|
1601
1764
|
pending = change.todos;
|
|
1602
1765
|
if (timer) clearTimeout(timer);
|
|
1603
|
-
timer = setTimeout(
|
|
1766
|
+
timer = setTimeout(() => {
|
|
1767
|
+
void flush();
|
|
1768
|
+
}, 150);
|
|
1604
1769
|
});
|
|
1605
|
-
return () => {
|
|
1770
|
+
return async () => {
|
|
1606
1771
|
unsubscribe();
|
|
1607
1772
|
if (timer) {
|
|
1608
1773
|
clearTimeout(timer);
|
|
1609
|
-
flush();
|
|
1774
|
+
await flush();
|
|
1775
|
+
} else {
|
|
1776
|
+
await writeChain;
|
|
1610
1777
|
}
|
|
1611
1778
|
};
|
|
1612
1779
|
}
|