@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.
Files changed (40) hide show
  1. package/dist/{compactor-BUU6Zm_3.d.ts → compactor-DpJBI1YH.d.ts} +7 -1
  2. package/dist/{config-CKLYPkCi.d.ts → config-D2qvAxVd.d.ts} +38 -1
  3. package/dist/coordination/index.d.ts +3 -3
  4. package/dist/coordination/index.js +283 -244
  5. package/dist/coordination/index.js.map +1 -1
  6. package/dist/defaults/index.d.ts +7 -7
  7. package/dist/defaults/index.js +803 -524
  8. package/dist/defaults/index.js.map +1 -1
  9. package/dist/{events-CNB9PALO.d.ts → events-BHIQs4o1.d.ts} +7 -0
  10. package/dist/execution/index.d.ts +10 -7
  11. package/dist/execution/index.js +166 -18
  12. package/dist/execution/index.js.map +1 -1
  13. package/dist/extension/index.d.ts +3 -3
  14. package/dist/extension/index.js +14 -7
  15. package/dist/extension/index.js.map +1 -1
  16. package/dist/{index-BDb0cAMP.d.ts → index-hWNybrNZ.d.ts} +3 -5
  17. package/dist/index.d.ts +12 -12
  18. package/dist/index.js +629 -299
  19. package/dist/index.js.map +1 -1
  20. package/dist/infrastructure/index.d.ts +5 -5
  21. package/dist/infrastructure/index.js +191 -20
  22. package/dist/infrastructure/index.js.map +1 -1
  23. package/dist/kernel/index.d.ts +4 -4
  24. package/dist/kernel/index.js.map +1 -1
  25. package/dist/{mcp-servers-DR35ojJZ.d.ts → mcp-servers-C2OopXOn.d.ts} +20 -4
  26. package/dist/observability/index.d.ts +1 -1
  27. package/dist/{path-resolver-Cl_q0u-R.d.ts → path-resolver--59rCou3.d.ts} +1 -1
  28. package/dist/{provider-runner-BXuADQqQ.d.ts → provider-runner-B39miKRw.d.ts} +1 -1
  29. package/dist/sdd/index.d.ts +1 -1
  30. package/dist/storage/index.d.ts +4 -3
  31. package/dist/storage/index.js +180 -13
  32. package/dist/storage/index.js.map +1 -1
  33. package/dist/{tool-executor-DKu4A6nB.d.ts → tool-executor-HsBLGRaA.d.ts} +2 -2
  34. package/dist/types/index.d.ts +7 -7
  35. package/dist/types/index.js +206 -9
  36. package/dist/types/index.js.map +1 -1
  37. package/dist/utils/index.d.ts +23 -2
  38. package/dist/utils/index.js +93 -1
  39. package/dist/utils/index.js.map +1 -1
  40. package/package.json +1 -1
@@ -153,6 +153,13 @@ interface EventMap {
153
153
  used: number;
154
154
  limit: number;
155
155
  };
156
+ 'context.repaired': {
157
+ ctx: Context;
158
+ changed: boolean;
159
+ removedToolUses: string[];
160
+ removedToolResults: string[];
161
+ removedMessages: number;
162
+ };
156
163
  'compaction.fired': {
157
164
  before: number;
158
165
  after: number;
@@ -1,10 +1,11 @@
1
- export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-DKu4A6nB.js';
1
+ export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, T as ToolExecutor } from '../tool-executor-HsBLGRaA.js';
2
2
  import { g as Provider, a0 as Context } from '../context-IovtuTf8.js';
3
- import { C as Compactor, a as CompactReport } from '../compactor-BUU6Zm_3.js';
3
+ import { a as Compactor, C as CompactReport } from '../compactor-DpJBI1YH.js';
4
4
  import { M as MessageSelector } from '../selector-wT2fv9Fg.js';
5
- import { E as EventBus } from '../events-CNB9PALO.js';
5
+ import { E as EventBus } from '../events-BHIQs4o1.js';
6
6
  import { c as MiddlewareHandler } from '../system-prompt-Dk1qm8ey.js';
7
- import { r as Agent, R as RunResult } from '../index-BDb0cAMP.js';
7
+ import { e as ContextWindowAggressiveOn, i as ContextWindowPolicy } from '../config-D2qvAxVd.js';
8
+ import { r as Agent, R as RunResult } from '../index-hWNybrNZ.js';
8
9
  import { D as DoneCondition } from '../multi-agent-B9a6sflH.js';
9
10
  import { a as SkillLoader, b as SkillManifest, S as SkillEntry } from '../skill-C_7znCIC.js';
10
11
  import { a as WstackPaths } from '../wstack-paths-BGu2INTm.js';
@@ -12,7 +13,6 @@ import '../models-registry-Y2xbog0E.js';
12
13
  import '../logger-BMQgxvdy.js';
13
14
  import '../observability-BhnVLBLS.js';
14
15
  import '../secret-scrubber-CgG2tV2B.js';
15
- import '../config-CKLYPkCi.js';
16
16
 
17
17
  interface SkillLoaderOptions {
18
18
  paths: WstackPaths;
@@ -147,6 +147,7 @@ declare class SelectiveCompactor implements Compactor {
147
147
  compact(ctx: Context, opts?: {
148
148
  aggressive?: boolean;
149
149
  }): Promise<CompactReport>;
150
+ private repairProtocolAdjacency;
150
151
  /**
151
152
  * Run the LLM selector to decide what to keep vs collapse.
152
153
  * Returns the token savings achieved.
@@ -173,9 +174,10 @@ declare class SelectiveCompactor implements Compactor {
173
174
 
174
175
  type CompactionFailureMode = 'throw' | 'throw_on_hard' | 'continue';
175
176
  interface AutoCompactionOptions {
176
- aggressiveOn?: 'hard' | 'soft' | 'warn';
177
+ aggressiveOn?: ContextWindowAggressiveOn;
177
178
  events?: EventBus;
178
179
  failureMode?: CompactionFailureMode;
180
+ policyProvider?: (ctx: Context) => Pick<ContextWindowPolicy, 'thresholds' | 'aggressiveOn'> | null | undefined;
179
181
  }
180
182
  /**
181
183
  * Pipeline middleware that monitors context token load and automatically
@@ -193,6 +195,7 @@ declare class AutoCompactionMiddleware {
193
195
  private readonly aggressiveOn;
194
196
  private readonly events?;
195
197
  private readonly failureMode;
198
+ private readonly policyProvider?;
196
199
  /**
197
200
  * @param compactor Compactor to use for compaction.
198
201
  * @param maxContext Provider's max context window in tokens.
@@ -208,7 +211,7 @@ declare class AutoCompactionMiddleware {
208
211
  warn: number;
209
212
  soft: number;
210
213
  hard: number;
211
- }, optsOrAggressiveOn?: AutoCompactionOptions | 'hard' | 'soft' | 'warn', events?: EventBus);
214
+ }, optsOrAggressiveOn?: AutoCompactionOptions | ContextWindowAggressiveOn, events?: EventBus);
212
215
  handler(): MiddlewareHandler<Context>;
213
216
  private compact;
214
217
  }
@@ -35,6 +35,98 @@ function estimateTextTokens(text) {
35
35
  return RoughTokenEstimate(text);
36
36
  }
37
37
 
38
+ // src/utils/message-invariants.ts
39
+ function repairToolUseAdjacency(messages) {
40
+ const removedToolUses = [];
41
+ const removedToolResults = [];
42
+ let removedMessages = 0;
43
+ let changed = false;
44
+ const out = [];
45
+ for (let i = 0; i < messages.length; i++) {
46
+ const original = messages[i];
47
+ let msg = original;
48
+ if (hasToolUse(msg)) {
49
+ const nextIds = toolResultIds(messages[i + 1]);
50
+ const filtered = mapContent(msg, (blocks) => {
51
+ const next = [];
52
+ for (const block of blocks) {
53
+ if (block.type === "tool_use" && !nextIds.has(block.id)) {
54
+ removedToolUses.push(block.id);
55
+ changed = true;
56
+ continue;
57
+ }
58
+ next.push(block);
59
+ }
60
+ return next;
61
+ });
62
+ msg = filtered ?? msg;
63
+ }
64
+ if (hasToolResult(msg)) {
65
+ const allowed = toolUseIds(out[out.length - 1]);
66
+ const filtered = mapContent(msg, (blocks) => {
67
+ const next = [];
68
+ for (const block of blocks) {
69
+ if (block.type === "tool_result" && !allowed.has(block.tool_use_id)) {
70
+ removedToolResults.push(block.tool_use_id);
71
+ changed = true;
72
+ continue;
73
+ }
74
+ next.push(block);
75
+ }
76
+ return next;
77
+ });
78
+ msg = filtered ?? msg;
79
+ }
80
+ if (isEmptyMessage(msg)) {
81
+ removedMessages++;
82
+ changed = true;
83
+ continue;
84
+ }
85
+ out.push(msg);
86
+ }
87
+ return {
88
+ messages: changed ? out : messages,
89
+ report: { changed, removedToolUses, removedToolResults, removedMessages }
90
+ };
91
+ }
92
+ function hasToolUse(msg) {
93
+ return contentBlocks(msg).some((b) => b.type === "tool_use");
94
+ }
95
+ function hasToolResult(msg) {
96
+ return contentBlocks(msg).some((b) => b.type === "tool_result");
97
+ }
98
+ function toolUseIds(msg) {
99
+ const ids = /* @__PURE__ */ new Set();
100
+ if (!msg || msg.role !== "assistant") return ids;
101
+ for (const block of contentBlocks(msg)) {
102
+ if (block.type === "tool_use") ids.add(block.id);
103
+ }
104
+ return ids;
105
+ }
106
+ function toolResultIds(msg) {
107
+ const ids = /* @__PURE__ */ new Set();
108
+ if (!msg || msg.role !== "user") return ids;
109
+ for (const block of contentBlocks(msg)) {
110
+ if (block.type === "tool_result") ids.add(block.tool_use_id);
111
+ }
112
+ return ids;
113
+ }
114
+ function contentBlocks(msg) {
115
+ return msg && Array.isArray(msg.content) ? msg.content : [];
116
+ }
117
+ function mapContent(msg, fn) {
118
+ if (!Array.isArray(msg.content)) return msg;
119
+ const next = fn(msg.content);
120
+ if (next.length === msg.content.length && next.every((b, idx) => b === msg.content[idx])) {
121
+ return msg;
122
+ }
123
+ return { ...msg, content: next };
124
+ }
125
+ function isEmptyMessage(msg) {
126
+ if (typeof msg.content === "string") return msg.content.trim().length === 0;
127
+ return msg.content.length === 0;
128
+ }
129
+
38
130
  // src/execution/compactor.ts
39
131
  var HybridCompactor = class {
40
132
  preserveK;
@@ -48,20 +140,36 @@ var HybridCompactor = class {
48
140
  async compact(ctx, opts = {}) {
49
141
  const beforeTokens = this.estimateMessages(ctx.messages);
50
142
  const reductions = [];
51
- const phase1Saved = this.eliseOldToolResults(ctx);
143
+ const policy = readContextWindowPolicy(ctx);
144
+ const preserveK = policy?.preserveK ?? this.preserveK;
145
+ const eliseThreshold = policy?.eliseThreshold ?? this.eliseThreshold;
146
+ const phase1Saved = this.eliseOldToolResults(ctx, preserveK, eliseThreshold);
52
147
  if (phase1Saved > 0) reductions.push({ phase: "elision", saved: phase1Saved });
53
148
  if (opts.aggressive) {
54
- const phase2Saved = this.collapseAncientTurns(ctx);
149
+ const phase2Saved = this.collapseAncientTurns(ctx, preserveK);
55
150
  if (phase2Saved > 0) reductions.push({ phase: "summary", saved: phase2Saved });
56
151
  }
152
+ const repaired = repairToolUseAdjacency(ctx.messages);
153
+ if (repaired.report.changed) {
154
+ ctx.state.replaceMessages(repaired.messages);
155
+ }
57
156
  const afterTokens = this.estimateMessages(ctx.messages);
58
- return { before: beforeTokens, after: afterTokens, reductions };
157
+ return {
158
+ before: beforeTokens,
159
+ after: afterTokens,
160
+ reductions,
161
+ repaired: repaired.report.changed ? {
162
+ removedToolUses: repaired.report.removedToolUses,
163
+ removedToolResults: repaired.report.removedToolResults,
164
+ removedMessages: repaired.report.removedMessages
165
+ } : void 0
166
+ };
59
167
  }
60
- eliseOldToolResults(ctx) {
168
+ eliseOldToolResults(ctx, preserveK = this.preserveK, eliseThreshold = this.eliseThreshold) {
61
169
  const messages = ctx.messages;
62
170
  let pairCount = 0;
63
171
  let preserveStart = messages.length;
64
- for (let i = messages.length - 1; i >= 0 && pairCount < this.preserveK; i--) {
172
+ for (let i = messages.length - 1; i >= 0 && pairCount < preserveK; i--) {
65
173
  const m = messages[i];
66
174
  if (!m) continue;
67
175
  if (m.role === "user" || m.role === "assistant") {
@@ -85,7 +193,7 @@ var HybridCompactor = class {
85
193
  const newContent = msg.content.map((b) => {
86
194
  if (b.type !== "tool_result") return b;
87
195
  const tokens = estimateToolResultTokens(b.content);
88
- if (tokens < this.eliseThreshold) return b;
196
+ if (tokens < eliseThreshold) return b;
89
197
  saved += tokens;
90
198
  const elided = {
91
199
  type: "tool_result",
@@ -105,9 +213,9 @@ var HybridCompactor = class {
105
213
  if (changed) ctx.state.replaceMessages(nextMessages);
106
214
  return saved;
107
215
  }
108
- collapseAncientTurns(ctx) {
216
+ collapseAncientTurns(ctx, preserveK = this.preserveK) {
109
217
  const messages = ctx.messages;
110
- const cutTarget = Math.max(0, messages.length - this.preserveK * 2);
218
+ const cutTarget = Math.max(0, messages.length - preserveK * 2);
111
219
  if (cutTarget <= 0) return 0;
112
220
  let boundary = -1;
113
221
  for (let i = cutTarget; i < messages.length; i++) {
@@ -148,6 +256,15 @@ var HybridCompactor = class {
148
256
  return total;
149
257
  }
150
258
  };
259
+ function readContextWindowPolicy(ctx) {
260
+ const policy = ctx.meta?.["contextWindowPolicy"];
261
+ if (!policy || typeof policy !== "object") return null;
262
+ const candidate = policy;
263
+ if (typeof candidate.preserveK !== "number" || typeof candidate.eliseThreshold !== "number") {
264
+ return null;
265
+ }
266
+ return candidate;
267
+ }
151
268
  function hasTextContent(m) {
152
269
  if (typeof m.content === "string") return m.content.trim().length > 0;
153
270
  return m.content.some((b) => b.type === "text" && b.text.trim().length > 0);
@@ -194,8 +311,19 @@ var IntelligentCompactor = class {
194
311
  const saved2 = this.lightweightCompact(ctx);
195
312
  if (saved2 > 0) reductions.push({ phase: "elision", saved: saved2 });
196
313
  }
314
+ const repaired = repairToolUseAdjacency(ctx.messages);
315
+ if (repaired.report.changed) ctx.state.replaceMessages(repaired.messages);
197
316
  const afterTokens = this.estimateTokens(ctx.messages);
198
- return { before: beforeTokens, after: afterTokens, reductions };
317
+ return {
318
+ before: beforeTokens,
319
+ after: afterTokens,
320
+ reductions,
321
+ repaired: repaired.report.changed ? {
322
+ removedToolUses: repaired.report.removedToolUses,
323
+ removedToolResults: repaired.report.removedToolResults,
324
+ removedMessages: repaired.report.removedMessages
325
+ } : void 0
326
+ };
199
327
  }
200
328
  async summarizeAncientTurns(ctx) {
201
329
  const messages = ctx.messages;
@@ -235,8 +363,8 @@ var IntelligentCompactor = class {
235
363
  const m = messages[i];
236
364
  if (!m) continue;
237
365
  if (m.role === "assistant") {
238
- const hasToolUse = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
239
- if (!hasToolUse) {
366
+ const hasToolUse2 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
367
+ if (!hasToolUse2) {
240
368
  return i + 1;
241
369
  }
242
370
  } else if (m.role !== "user") ; else {
@@ -542,8 +670,9 @@ var SelectiveCompactor = class {
542
670
  if (!shouldCompact) {
543
671
  const saved = this.eliseOldToolResults(ctx);
544
672
  if (saved > 0) reductions.push({ phase: "elision", saved });
673
+ const repair2 = this.repairProtocolAdjacency(ctx);
545
674
  const afterTokens2 = this.estimateTokens(ctx.messages);
546
- return { before: beforeTokens, after: afterTokens2, reductions };
675
+ return { before: beforeTokens, after: afterTokens2, reductions, repaired: repair2 };
547
676
  }
548
677
  const savedElision = this.eliseOldToolResults(ctx);
549
678
  if (savedElision > 0) reductions.push({ phase: "elision", saved: savedElision });
@@ -553,8 +682,18 @@ var SelectiveCompactor = class {
553
682
  const savedSelective = await this.runSelector(ctx, targetBudget);
554
683
  if (savedSelective > 0) reductions.push({ phase: "selective", saved: savedSelective });
555
684
  }
685
+ const repair = this.repairProtocolAdjacency(ctx);
556
686
  const afterTokens = this.estimateTokens(ctx.messages);
557
- return { before: beforeTokens, after: afterTokens, reductions };
687
+ return { before: beforeTokens, after: afterTokens, reductions, repaired: repair };
688
+ }
689
+ repairProtocolAdjacency(ctx) {
690
+ const repaired = repairToolUseAdjacency(ctx.messages);
691
+ if (repaired.report.changed) ctx.state.replaceMessages(repaired.messages);
692
+ return repaired.report.changed ? {
693
+ removedToolUses: repaired.report.removedToolUses,
694
+ removedToolResults: repaired.report.removedToolResults,
695
+ removedMessages: repaired.report.removedMessages
696
+ } : void 0;
558
697
  }
559
698
  /**
560
699
  * Run the LLM selector to decide what to keep vs collapse.
@@ -795,6 +934,7 @@ var AutoCompactionMiddleware = class {
795
934
  aggressiveOn;
796
935
  events;
797
936
  failureMode;
937
+ policyProvider;
798
938
  /**
799
939
  * @param compactor Compactor to use for compaction.
800
940
  * @param maxContext Provider's max context window in tokens.
@@ -817,17 +957,25 @@ var AutoCompactionMiddleware = class {
817
957
  this.aggressiveOn = opts.aggressiveOn ?? "soft";
818
958
  this.events = opts.events;
819
959
  this.failureMode = opts.failureMode ?? "throw_on_hard";
960
+ this.policyProvider = opts.policyProvider;
820
961
  }
821
962
  handler() {
822
963
  return async (ctx, next) => {
823
964
  const tokens = this.estimator(ctx);
824
965
  const load = tokens / this.maxContext;
825
- if (load >= this.hardThreshold) {
966
+ const policy = this.policyProvider?.(ctx);
967
+ const thresholds = policy?.thresholds ?? {
968
+ warn: this.warnThreshold,
969
+ soft: this.softThreshold,
970
+ hard: this.hardThreshold
971
+ };
972
+ const aggressiveOn = policy?.aggressiveOn ?? this.aggressiveOn;
973
+ if (load >= thresholds.hard) {
826
974
  await this.compact(ctx, true, { level: "hard", tokens, load });
827
- } else if (load >= this.softThreshold) {
828
- await this.compact(ctx, this.aggressiveOn !== "hard", { level: "soft", tokens, load });
829
- } else if (load >= this.warnThreshold) {
830
- await this.compact(ctx, false, { level: "warn", tokens, load });
975
+ } else if (load >= thresholds.soft) {
976
+ await this.compact(ctx, aggressiveOn !== "hard", { level: "soft", tokens, load });
977
+ } else if (load >= thresholds.warn) {
978
+ await this.compact(ctx, aggressiveOn === "warn", { level: "warn", tokens, load });
831
979
  }
832
980
  return next(ctx);
833
981
  };