@wrongstack/core 0.256.1 → 0.257.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.
@@ -1,5 +1,5 @@
1
1
  export { C as CompactorOptions, a as DefaultErrorHandler, b as DefaultRetryPolicy, E as EternalAutonomyEngine, c as EternalAutonomyOptions, d as EternalEngineState, H as HybridCompactor, I as IterationStage, P as ParallelEngineState, e as ParallelEternalEngine, f as ParallelEternalOptions, g as ParallelIterationStage, T as ToolExecutor } from '../parallel-eternal-engine-C0juOszP.js';
2
- export { A as AutoCompactionMiddleware, a as AutonomousRunner, b as AutonomousRunnerOptions, c as AutonomyPromptContributorOptions, C as CompactorStrategy, D as DefaultSkillLoader, d as DoneCheckResult, e as DoneConditionChecker, I as IntelligentCompactor, f as IntelligentCompactorOptions, S as SelectiveCompactor, g as SelectiveCompactorOptions, h as SkillLoaderOptions, i as StrategyCompactorOptions, j as buildGoalPreamble, k as createStrategyCompactor, m as makeAutonomyPromptContributor } from '../goal-preamble-UiEkbNmW.js';
2
+ export { A as AutoCompactionMiddleware, a as AutonomousRunner, b as AutonomousRunnerOptions, c as AutonomyPromptContributorOptions, C as CompactorStrategy, D as DefaultSkillLoader, d as DoneCheckResult, e as DoneConditionChecker, I as IntelligentCompactor, f as IntelligentCompactorOptions, S as SelectiveCompactor, g as SelectiveCompactorOptions, h as SkillLoaderOptions, i as StrategyCompactorOptions, j as buildGoalPreamble, k as createStrategyCompactor, m as makeAutonomyPromptContributor } from '../goal-preamble-CznHTZqP.js';
3
3
  import { P as Provider } from '../context-CGdgA0q6.js';
4
4
  import { b as BrainDecision, e as BrainDecisionRequest, B as BrainArbiter } from '../brain-TjEEwSpw.js';
5
5
  import '../retry-policy-Tg7LXkoK.js';
@@ -6,16 +6,6 @@ import * as path2 from 'path';
6
6
  import * as os from 'os';
7
7
  import { EventEmitter } from 'events';
8
8
 
9
- // src/utils/expect-defined.ts
10
- function expectDefined(value, label) {
11
- if (value === null || value === void 0) {
12
- const err = new Error("Expected value to be defined");
13
- err.name = "ExpectDefinedError";
14
- throw err;
15
- }
16
- return value;
17
- }
18
-
19
9
  // src/utils/token-estimate.ts
20
10
  var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
21
11
  var CALIBRATION_GLOBAL_KEY = "__global__";
@@ -35,12 +25,15 @@ function getCachedEstimate(key, compute) {
35
25
  const existing = ESTIMATE_CACHE.get(key);
36
26
  if (existing !== void 0) return existing;
37
27
  if (ESTIMATE_CACHE.size >= ESTIMATE_CACHE_MAX_SIZE) {
38
- const keys = [...ESTIMATE_CACHE.keys()];
39
- for (let i = 0; i < Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4); i++) {
40
- ESTIMATE_CACHE.delete(expectDefined(keys[i]));
28
+ let evicted = 0;
29
+ const maxEvict = Math.floor(ESTIMATE_CACHE_MAX_SIZE / 4);
30
+ for (const k of ESTIMATE_CACHE.keys()) {
31
+ if (evicted >= maxEvict) break;
32
+ ESTIMATE_CACHE.delete(k);
33
+ evicted++;
41
34
  }
42
35
  }
43
- const estimate = compute();
36
+ const estimate = compute(key);
44
37
  ESTIMATE_CACHE.set(key, estimate);
45
38
  return estimate;
46
39
  }
@@ -49,13 +42,11 @@ function estimateToolInputTokens(input) {
49
42
  if (input === null || typeof input !== "object") {
50
43
  return RoughTokenEstimate(String(input));
51
44
  }
52
- const key = JSON.stringify(input);
53
- return getCachedEstimate(key, () => RoughTokenEstimate(key));
45
+ return getCachedEstimate(JSON.stringify(input), (key) => RoughTokenEstimate(key));
54
46
  }
55
47
  function estimateToolResultTokens(content) {
56
48
  if (typeof content === "string") return RoughTokenEstimate(content);
57
- const key = JSON.stringify(content);
58
- return getCachedEstimate(key, () => RoughTokenEstimate(key));
49
+ return getCachedEstimate(JSON.stringify(content), (key) => RoughTokenEstimate(key));
59
50
  }
60
51
  function estimateTextTokens(text) {
61
52
  return RoughTokenEstimate(text);
@@ -162,6 +153,16 @@ function estimateRequestTokensCalibrated(messages, systemPrompt, tools, calibrat
162
153
  return result;
163
154
  }
164
155
 
156
+ // src/utils/expect-defined.ts
157
+ function expectDefined(value, label) {
158
+ if (value === null || value === void 0) {
159
+ const err = new Error("Expected value to be defined");
160
+ err.name = "ExpectDefinedError";
161
+ throw err;
162
+ }
163
+ return value;
164
+ }
165
+
165
166
  // src/utils/message-invariants.ts
166
167
  function repairToolUseAdjacency(messages) {
167
168
  const removedToolUses = [];
@@ -260,6 +261,25 @@ function isTextBlock(b) {
260
261
  }
261
262
 
262
263
  // src/execution/compaction-core.ts
264
+ function emitCompactionMetrics(event, metrics) {
265
+ console.log(
266
+ JSON.stringify({
267
+ level: "debug",
268
+ event,
269
+ messageCount: metrics.messageCount,
270
+ preserveStart: metrics.preserveStart,
271
+ fastPathIterations: metrics.fastPathIterations,
272
+ fastPathInnerIterations: metrics.fastPathInnerIterations,
273
+ // Ratios — anything > 2.0 indicates the inner loop is running more than expected
274
+ fastPathInnerPerOuter: metrics.fastPathIterations > 0 ? metrics.fastPathInnerIterations / metrics.fastPathIterations : 0,
275
+ fullPassIterations: metrics.fullPassIterations,
276
+ fullPassInnerIterations: metrics.fullPassInnerIterations,
277
+ fullPassInnerPerOuter: metrics.fullPassIterations > 0 ? metrics.fullPassInnerIterations / metrics.fullPassIterations : 0,
278
+ tokensSaved: metrics.tokensSaved,
279
+ changed: metrics.changed
280
+ })
281
+ );
282
+ }
263
283
  var estimateMessages = estimateMessageTokens;
264
284
  function hasTextContent(m) {
265
285
  if (typeof m.content === "string") return m.content.trim().length > 0;
@@ -276,37 +296,78 @@ function findPreserveStart(messages, preserveK) {
276
296
  preserveStart = i;
277
297
  }
278
298
  }
299
+ let forwardWalkIterations = 0;
300
+ let forwardWalkInnerIterations = 0;
279
301
  for (let i = preserveStart; i < messages.length; i++) {
302
+ forwardWalkIterations++;
280
303
  const m = messages[i];
281
304
  if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
282
- const hasToolUse3 = m.content.some((b) => b.type === "tool_use");
305
+ const hasToolUse3 = m.content.some((b) => {
306
+ forwardWalkInnerIterations++;
307
+ return b.type === "tool_use";
308
+ });
283
309
  if (hasToolUse3 && i + 1 < messages.length) {
284
310
  const next = messages[i + 1];
285
- if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
311
+ if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => {
312
+ forwardWalkInnerIterations++;
313
+ return b.type === "tool_result";
314
+ })) {
286
315
  preserveStart = i + 1;
287
316
  }
288
317
  }
289
318
  }
319
+ console.log(
320
+ JSON.stringify({
321
+ level: "debug",
322
+ event: "compaction.find_preserve_start.ended",
323
+ messageCount: messages.length,
324
+ preserveK,
325
+ preserveStart,
326
+ forwardWalkIterations,
327
+ forwardWalkInnerIterations,
328
+ forwardWalkInnerPerOuter: forwardWalkIterations > 0 ? forwardWalkInnerIterations / forwardWalkIterations : 0
329
+ })
330
+ );
290
331
  return preserveStart;
291
332
  }
292
333
  function eliseOldToolResults(messages, opts) {
293
334
  const preserveStart = findPreserveStart(messages, opts.preserveK);
294
335
  let hasOversized = false;
336
+ let fastPathIterations = 0;
337
+ let fastPathInnerIterations = 0;
295
338
  for (let i = 0; i < preserveStart && !hasOversized; i++) {
339
+ fastPathIterations++;
296
340
  const msg = messages[i];
297
341
  if (!msg || !Array.isArray(msg.content)) continue;
298
342
  for (const b of msg.content) {
343
+ fastPathInnerIterations++;
299
344
  if (b.type === "tool_result" && estimateToolResultTokens(b.content) >= opts.eliseThreshold) {
300
345
  hasOversized = true;
301
346
  break;
302
347
  }
303
348
  }
304
349
  }
350
+ emitCompactionMetrics(
351
+ hasOversized ? "compaction.elision.fast_path.oversized_found" : "compaction.elision.fast_path.no_oversized",
352
+ {
353
+ messageCount: messages.length,
354
+ preserveStart,
355
+ fastPathIterations,
356
+ fastPathInnerIterations,
357
+ fullPassIterations: 0,
358
+ fullPassInnerIterations: 0,
359
+ tokensSaved: 0,
360
+ changed: false
361
+ }
362
+ );
305
363
  if (!hasOversized) return { messages, saved: 0, changed: false };
306
364
  let saved = 0;
307
365
  let changed = false;
366
+ let fullPassIterations = 0;
367
+ let fullPassInnerIterations = 0;
308
368
  const next = new Array(messages.length);
309
369
  for (let i = 0; i < messages.length; i++) {
370
+ fullPassIterations++;
310
371
  const msg = messages[i];
311
372
  if (i >= preserveStart || !msg || !Array.isArray(msg.content)) {
312
373
  next[i] = msg;
@@ -332,7 +393,33 @@ function eliseOldToolResults(messages, opts) {
332
393
  next[i] = { ...msg, content: newContent };
333
394
  changed = true;
334
395
  }
396
+ fullPassInnerIterations += original.length;
397
+ if (process.env["NODE_ENV"] === "development" || process.env["WRONGSTACK_DEBUG"] === "1") {
398
+ const ratio = fullPassInnerIterations / fullPassIterations;
399
+ if (ratio > 10) {
400
+ console.error(
401
+ JSON.stringify({
402
+ level: "error",
403
+ event: "compaction.elision.regression",
404
+ message: `fullPassInnerPerOuter=${ratio.toFixed(2)} exceeds threshold 10 \u2014 possible O(n\xB7m) regression`,
405
+ messageCount: messages.length,
406
+ fullPassIterations,
407
+ fullPassInnerIterations
408
+ })
409
+ );
410
+ }
411
+ }
335
412
  }
413
+ emitCompactionMetrics("compaction.elision.full_pass.ended", {
414
+ messageCount: messages.length,
415
+ preserveStart,
416
+ fastPathIterations,
417
+ fastPathInnerIterations,
418
+ fullPassIterations,
419
+ fullPassInnerIterations,
420
+ tokensSaved: saved,
421
+ changed
422
+ });
336
423
  return { messages: changed ? next : messages, saved, changed };
337
424
  }
338
425
  function buildLosslessDigest(messages) {
@@ -6568,17 +6655,17 @@ function normalize(text) {
6568
6655
  return ` ${text.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim()} `;
6569
6656
  }
6570
6657
  function scoreAgents(task, catalog = AGENT_CATALOG) {
6571
- const hay = normalize(task);
6658
+ const haySet = new Set(normalize(task).split(/\s+/).filter(Boolean));
6572
6659
  const out = [];
6573
6660
  for (const def of Object.values(catalog)) {
6574
6661
  if (!def?.config?.role) continue;
6575
6662
  let score = 0;
6576
6663
  const matched = [];
6577
6664
  for (const kw of def.capability.keywords) {
6578
- const needle = normalize(kw);
6579
- if (hay.includes(needle.trimEnd() + " ") || hay.includes(" " + needle.trimStart())) {
6580
- const words = kw.trim().split(/\s+/).length;
6581
- score += words;
6665
+ const needleWords = normalize(kw).split(/\s+/).filter(Boolean);
6666
+ const allPresent = needleWords.every((w) => haySet.has(w));
6667
+ if (allPresent) {
6668
+ score += needleWords.length;
6582
6669
  matched.push(kw);
6583
6670
  }
6584
6671
  }
@@ -8384,6 +8471,8 @@ function compactSkillBody(body) {
8384
8471
  var DefaultSkillLoader = class {
8385
8472
  dirs;
8386
8473
  cache;
8474
+ entriesCache;
8475
+ bodyCache = /* @__PURE__ */ new Map();
8387
8476
  constructor(opts) {
8388
8477
  this.dirs = [
8389
8478
  { dir: opts.paths.inProjectSkills, source: "project" },
@@ -8442,6 +8531,7 @@ var DefaultSkillLoader = class {
8442
8531
  return lines.join("\n");
8443
8532
  }
8444
8533
  async listEntries() {
8534
+ if (this.entriesCache) return this.entriesCache;
8445
8535
  const skills = await this.list();
8446
8536
  const entries = [];
8447
8537
  for (const s of skills) {
@@ -8452,33 +8542,47 @@ var DefaultSkillLoader = class {
8452
8542
  } catch {
8453
8543
  }
8454
8544
  }
8545
+ this.entriesCache = entries;
8455
8546
  return entries;
8456
8547
  }
8457
8548
  invalidateCache() {
8458
8549
  this.cache = void 0;
8550
+ this.entriesCache = void 0;
8551
+ this.bodyCache.clear();
8459
8552
  }
8460
8553
  async readBody(name) {
8554
+ const cached = this.bodyCache.get(name);
8555
+ if (cached !== void 0) return cached;
8461
8556
  const m = await this.find(name);
8462
8557
  if (!m) throw new Error(`Skill "${name}" not found`);
8463
- return fs.readFile(m.path, "utf8");
8558
+ const body = await fs.readFile(m.path, "utf8");
8559
+ this.bodyCache.set(name, body);
8560
+ return body;
8464
8561
  }
8465
8562
  async readSaveBody(name) {
8563
+ const key = `save:${name}`;
8564
+ const cached = this.bodyCache.get(key);
8565
+ if (cached !== void 0) return cached;
8466
8566
  const m = await this.find(name);
8467
8567
  if (!m) throw new Error(`Skill "${name}" not found`);
8468
8568
  const savePath = path2.join(path2.dirname(m.path), "SKILL.save.md");
8569
+ let result;
8469
8570
  try {
8470
- return await fs.readFile(savePath, "utf8");
8571
+ result = await fs.readFile(savePath, "utf8");
8471
8572
  } catch {
8472
8573
  const full = await fs.readFile(m.path, "utf8");
8473
8574
  const body = stripFrontmatter(full);
8474
8575
  const compact = compactSkillBody(body);
8475
8576
  if (compact) {
8476
- return `## Overview
8577
+ result = `## Overview
8477
8578
 
8478
8579
  ${compact}`;
8580
+ } else {
8581
+ result = body.trim().slice(0, 300);
8479
8582
  }
8480
- return body.trim().slice(0, 300);
8481
8583
  }
8584
+ this.bodyCache.set(key, result);
8585
+ return result;
8482
8586
  }
8483
8587
  };
8484
8588
  function parseFrontmatter(raw) {