@graphrefly/graphrefly 0.14.0 → 0.15.0

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.
@@ -32,14 +32,14 @@ import {
32
32
  observeSSE,
33
33
  observeSubscription
34
34
  } from "../../chunk-2ZICUAUJ.js";
35
+ import "../../chunk-ZHTHUX5D.js";
36
+ import "../../chunk-YW6LFCFS.js";
35
37
  import {
36
38
  observeGraph$,
37
39
  observeNode$,
38
40
  toMessages$,
39
41
  toObservable
40
42
  } from "../../chunk-QVYZD65U.js";
41
- import "../../chunk-ZHTHUX5D.js";
42
- import "../../chunk-YW6LFCFS.js";
43
43
  import "../../chunk-WZ2Z2CRV.js";
44
44
  import "../../chunk-CRACCCJY.js";
45
45
  import "../../chunk-XQ4UMAU7.js";
package/dist/index.cjs CHANGED
@@ -4645,7 +4645,7 @@ var Graph = class _Graph {
4645
4645
  _createObserveResult(path, target, options) {
4646
4646
  const timeline = options.timeline === true;
4647
4647
  const causal = options.causal === true;
4648
- const derived3 = options.derived === true;
4648
+ const derived2 = options.derived === true;
4649
4649
  const minimal = options.detail === "minimal";
4650
4650
  const result = {
4651
4651
  values: {},
@@ -4658,14 +4658,14 @@ var Graph = class _Graph {
4658
4658
  let lastTriggerDepIndex;
4659
4659
  let lastRunDepValues;
4660
4660
  let detachInspectorHook;
4661
- if ((causal || derived3) && target instanceof NodeImpl) {
4661
+ if ((causal || derived2) && target instanceof NodeImpl) {
4662
4662
  detachInspectorHook = target._setInspectorHook((event) => {
4663
4663
  if (event.kind === "dep_message") {
4664
4664
  lastTriggerDepIndex = event.depIndex;
4665
4665
  return;
4666
4666
  }
4667
4667
  lastRunDepValues = [...event.depValues];
4668
- if (derived3) {
4668
+ if (derived2) {
4669
4669
  result.events.push({
4670
4670
  type: "derived",
4671
4671
  path,
@@ -13523,7 +13523,9 @@ function promptNode(adapter, deps, prompt, opts) {
13523
13523
  const messagesNode = derived(
13524
13524
  deps,
13525
13525
  (values) => {
13526
+ if (values.some((v) => v == null)) return [];
13526
13527
  const text = typeof prompt === "string" ? prompt : prompt(...values);
13528
+ if (!text) return [];
13527
13529
  const msgs = [];
13528
13530
  if (opts?.systemPrompt) msgs.push({ role: "system", content: opts.systemPrompt });
13529
13531
  msgs.push({ role: "user", content: text });
@@ -18428,6 +18430,9 @@ function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
18428
18430
  }
18429
18431
 
18430
18432
  // src/patterns/harness/loop.ts
18433
+ function baseSummary(summary) {
18434
+ return summary.replace(/^\[RETRY \d+\/\d+\]\s*/, "");
18435
+ }
18431
18436
  var DEFAULT_TRIAGE_PROMPT = `You are a triage classifier for a reactive collaboration harness.
18432
18437
 
18433
18438
  Given an intake item, classify it and output JSON:
@@ -18489,13 +18494,19 @@ var HarnessGraph = class extends Graph {
18489
18494
  strategy;
18490
18495
  /** Verify results topic — subscribe to see verification outcomes. */
18491
18496
  verifyResults;
18492
- constructor(name, intake, queues, gates, strategy, verifyResults) {
18497
+ /** Per-item fast-retry counts (keyed by base summary). */
18498
+ retryTracker;
18499
+ /** Per-item reingestion counts (keyed by base summary). */
18500
+ reingestionTracker;
18501
+ constructor(name, intake, queues, gates, strategy, verifyResults, retryTracker, reingestionTracker) {
18493
18502
  super(name);
18494
18503
  this.intake = intake;
18495
18504
  this.queues = queues;
18496
18505
  this.gates = gates;
18497
18506
  this.strategy = strategy;
18498
18507
  this.verifyResults = verifyResults;
18508
+ this.retryTracker = retryTracker;
18509
+ this.reingestionTracker = reingestionTracker;
18499
18510
  }
18500
18511
  };
18501
18512
  function harnessLoop(name, opts) {
@@ -18512,14 +18523,20 @@ function harnessLoop(name, opts) {
18512
18523
  }
18513
18524
  const intake = new TopicGraph("intake", { retainedLimit });
18514
18525
  const strategy = strategyModel();
18526
+ const triageInput = withLatestFrom(
18527
+ intake.latest,
18528
+ strategy.node
18529
+ );
18515
18530
  const triageNode = promptNode(
18516
18531
  adapter,
18517
- [intake.latest, strategy.node],
18518
- opts.triagePrompt ?? ((item, strat) => {
18519
- return DEFAULT_TRIAGE_PROMPT.replace("{{strategy}}", JSON.stringify(strat)).replace(
18520
- "{{item}}",
18521
- JSON.stringify(item)
18522
- );
18532
+ [triageInput],
18533
+ opts.triagePrompt ?? ((pair) => {
18534
+ const [item, strat] = pair;
18535
+ if (!item) return "";
18536
+ return DEFAULT_TRIAGE_PROMPT.replace(
18537
+ "{{strategy}}",
18538
+ JSON.stringify(Array.from(strat.entries()))
18539
+ ).replace("{{item}}", JSON.stringify(item));
18523
18540
  }),
18524
18541
  {
18525
18542
  name: "triage",
@@ -18531,12 +18548,14 @@ function harnessLoop(name, opts) {
18531
18548
  for (const route of QUEUE_NAMES) {
18532
18549
  queueTopics.set(route, new TopicGraph(`queue/${route}`, { retainedLimit }));
18533
18550
  }
18534
- const _router = effect([triageNode], ([triaged]) => {
18551
+ const router = effect([triageNode], ([triaged]) => {
18535
18552
  const item = triaged;
18536
18553
  if (!item || !item.route) return;
18537
18554
  const topic2 = queueTopics.get(item.route);
18538
18555
  if (topic2) topic2.publish(item);
18539
18556
  });
18557
+ router.subscribe(() => {
18558
+ });
18540
18559
  const gateGraph = new Graph("gates");
18541
18560
  const gateControllers = /* @__PURE__ */ new Map();
18542
18561
  for (const route of QUEUE_NAMES) {
@@ -18566,9 +18585,7 @@ function harnessLoop(name, opts) {
18566
18585
  const executeNode = promptNode(
18567
18586
  adapter,
18568
18587
  [executeInput],
18569
- opts.executePrompt ?? ((item) => {
18570
- return DEFAULT_EXECUTE_PROMPT.replace("{{item}}", JSON.stringify(item));
18571
- }),
18588
+ opts.executePrompt ?? ((item) => DEFAULT_EXECUTE_PROMPT.replace("{{item}}", JSON.stringify(item))),
18572
18589
  {
18573
18590
  name: "execute",
18574
18591
  format: "json",
@@ -18579,66 +18596,87 @@ function harnessLoop(name, opts) {
18579
18596
  const verifyNode = promptNode(
18580
18597
  adapter,
18581
18598
  [executeNode, executeInput],
18582
- opts.verifyPrompt ?? ((execution, item) => {
18583
- return DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
18584
- "{{item}}",
18585
- JSON.stringify(item)
18586
- );
18587
- }),
18599
+ opts.verifyPrompt ?? ((execution, item) => DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
18600
+ "{{item}}",
18601
+ JSON.stringify(item)
18602
+ )),
18588
18603
  {
18589
18604
  name: "verify",
18590
18605
  format: "json",
18591
18606
  retries: 1
18592
18607
  }
18593
18608
  );
18609
+ const verifyWithExec = withLatestFrom(verifyNode, executeNode);
18610
+ const verifyContext = withLatestFrom(
18611
+ verifyWithExec,
18612
+ executeInput
18613
+ );
18594
18614
  const maxReingestions = opts.maxReingestions ?? 1;
18595
- let reingestionCount = 0;
18596
- const _fastRetry = effect([verifyNode], ([result]) => {
18597
- const vr = result;
18598
- if (!vr) return;
18615
+ const retryTracker = /* @__PURE__ */ new Map();
18616
+ const reingestionTracker = /* @__PURE__ */ new Map();
18617
+ const fastRetry = effect([verifyContext], ([ctx]) => {
18618
+ const [[vo, execRaw], item] = ctx;
18619
+ if (!vo || !item) return;
18620
+ const exec = {
18621
+ item,
18622
+ outcome: execRaw?.outcome ?? "failure",
18623
+ detail: execRaw?.detail ?? "unknown"
18624
+ };
18625
+ const vr = {
18626
+ item,
18627
+ execution: exec,
18628
+ verified: vo.verified,
18629
+ findings: vo.findings ?? [],
18630
+ errorClass: vo.errorClass
18631
+ };
18599
18632
  if (vr.verified) {
18600
- strategy.record(vr.item.rootCause, vr.item.intervention, true);
18633
+ strategy.record(item.rootCause, item.intervention, true);
18601
18634
  verifyResults.publish(vr);
18602
18635
  return;
18603
18636
  }
18604
18637
  const errClass = vr.errorClass ?? errorClassifier({
18605
- item: vr.item,
18638
+ item,
18606
18639
  outcome: "failure",
18607
- detail: vr.findings.join("; "),
18608
- retryCount: 0
18640
+ detail: vr.findings.join("; ")
18609
18641
  });
18610
- const exec = vr.execution;
18611
- const retryCount = exec?.retryCount ?? 0;
18642
+ const key = baseSummary(item.summary);
18643
+ const retryCount = retryTracker.get(key) ?? 0;
18612
18644
  if (errClass === "self-correctable" && retryCount < maxRetries) {
18645
+ retryTracker.set(key, retryCount + 1);
18613
18646
  const retryItem = {
18614
- ...vr.item,
18615
- summary: `[RETRY ${retryCount + 1}/${maxRetries}] ${vr.item.summary} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`
18647
+ ...item,
18648
+ summary: `[RETRY ${retryCount + 1}/${maxRetries}] ${baseSummary(item.summary)} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`
18616
18649
  };
18617
18650
  retryTopic.publish(retryItem);
18618
18651
  } else {
18619
- strategy.record(vr.item.rootCause, vr.item.intervention, false);
18652
+ strategy.record(item.rootCause, item.intervention, false);
18620
18653
  verifyResults.publish(vr);
18621
- if (reingestionCount < maxReingestions) {
18622
- reingestionCount++;
18654
+ const itemReingestions = reingestionTracker.get(key) ?? 0;
18655
+ if (itemReingestions < maxReingestions) {
18656
+ reingestionTracker.set(key, itemReingestions + 1);
18623
18657
  intake.publish({
18624
18658
  source: "eval",
18625
- summary: `Verification failed for: ${vr.item.summary}`,
18659
+ summary: `Verification failed for: ${baseSummary(item.summary)}`,
18626
18660
  evidence: vr.findings.join("\n"),
18627
- affectsAreas: vr.item.affectsAreas,
18628
- affectsEvalTasks: vr.item.affectsEvalTasks,
18661
+ affectsAreas: item.affectsAreas,
18662
+ affectsEvalTasks: item.affectsEvalTasks,
18629
18663
  severity: "high",
18630
- relatedTo: [vr.item.summary]
18664
+ relatedTo: [baseSummary(item.summary)]
18631
18665
  });
18632
18666
  }
18633
18667
  }
18634
18668
  });
18669
+ fastRetry.subscribe(() => {
18670
+ });
18635
18671
  const harness = new HarnessGraph(
18636
18672
  name,
18637
18673
  intake,
18638
18674
  queueTopics,
18639
18675
  gateControllers,
18640
18676
  strategy,
18641
- verifyResults
18677
+ verifyResults,
18678
+ retryTracker,
18679
+ reingestionTracker
18642
18680
  );
18643
18681
  harness.mount("intake", intake);
18644
18682
  for (const [route, topic2] of queueTopics) {