@ycodium-ai/agent-fake 0.2.3056 → 0.2.3064

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 (2) hide show
  1. package/dist/index.js +74 -15
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -650,16 +650,64 @@ function parsePlaybook(text) {
650
650
  }
651
651
  var UnresolvedPlaceholder = class extends Error {
652
652
  };
653
- function placeholderValue(raw, threadId, results) {
653
+ function placeholderValue(raw, threadId, results, history) {
654
654
  if (raw === "{{thread}}") return threadId;
655
- const [id, ...path] = raw.slice(7, -2).split(".");
656
- const value = id === void 0 || !results.has(id) ? void 0 : valueAt(results.get(id), path);
657
- if (value === void 0) throw new UnresolvedPlaceholder(`unresolved placeholder ${raw}`);
658
- return value;
655
+ const [id, ...path] = raw.slice(7, -2).split(/\.(?![^\[]*\])/u);
656
+ const unresolved = () => new UnresolvedPlaceholder(`unresolved placeholder ${raw}`);
657
+ const nthAt = path.findIndex((part) => {
658
+ const selector = parseSelector(part);
659
+ return selector !== null && selector !== "invalid" && selector.nth !== void 0;
660
+ });
661
+ if (id === "*" && nthAt >= 0) {
662
+ const selector = parseSelector(path[nthAt]);
663
+ if (selector === null || selector === "invalid") throw unresolved();
664
+ const prefix = [...path.slice(0, nthAt), selector.name];
665
+ let count = 0;
666
+ for (const result of history) {
667
+ const array = valueAt(result, prefix);
668
+ if (!Array.isArray(array)) continue;
669
+ for (const entry of array) {
670
+ if (!matchesSelector(entry, selector)) continue;
671
+ count += 1;
672
+ if (count !== selector.nth) continue;
673
+ const value = valueAt(entry, path.slice(nthAt + 1));
674
+ if (value === void 0) throw unresolved();
675
+ return value;
676
+ }
677
+ }
678
+ throw unresolved();
679
+ }
680
+ const candidates = id === "*" ? [...history].reverse() : [results.get(id ?? "")];
681
+ for (const result of candidates) {
682
+ const value = valueAt(result, path);
683
+ if (value !== void 0) return value;
684
+ }
685
+ throw unresolved();
659
686
  }
687
+ function parseSelector(part) {
688
+ const match = /^([^\[\]]+)\[([^=\[\]]+)=([^=\[\]#]*)(?:#(\d+))?\]$/u.exec(part);
689
+ if (match === null) return null;
690
+ const [, name, field, encoded, nth] = match;
691
+ if (name === void 0 || field === void 0 || encoded === void 0) return "invalid";
692
+ try {
693
+ const expected = decodeURIComponent(encoded);
694
+ return nth === void 0 ? { name, field, expected } : { name, field, expected, nth: Number(nth) };
695
+ } catch {
696
+ return "invalid";
697
+ }
698
+ }
699
+ var matchesSelector = (entry, selector) => isRecord2(entry) && Object.hasOwn(entry, selector.field) && entry[selector.field] === selector.expected;
660
700
  function valueAt(start, path) {
661
701
  let value = start;
662
702
  for (const part of path) {
703
+ const selector = parseSelector(part);
704
+ if (selector === "invalid") return void 0;
705
+ if (selector !== null) {
706
+ const array = valueAt(value, [selector.name]);
707
+ if (!Array.isArray(array)) return void 0;
708
+ value = array.filter((entry) => matchesSelector(entry, selector))[(selector.nth ?? 1) - 1];
709
+ continue;
710
+ }
663
711
  if (Array.isArray(value) && /^\d+$/.test(part) && Object.hasOwn(value, Number(part))) {
664
712
  value = value[Number(part)];
665
713
  } else if (isRecord2(value) && Object.hasOwn(value, part)) {
@@ -670,23 +718,27 @@ function valueAt(start, path) {
670
718
  }
671
719
  return value;
672
720
  }
673
- function resolveValue(value, threadId, results) {
721
+ function resolveValue(value, threadId, results, history) {
674
722
  if (typeof value === "string") {
675
723
  const placeholders = [...value.matchAll(/\{\{(?:thread|step:[^{}]*)\}\}/g)];
676
724
  if (placeholders.length === 1 && placeholders[0]?.[0] === value)
677
- return placeholderValue(value, threadId, results);
725
+ return placeholderValue(value, threadId, results, history);
678
726
  return value.replace(/\{\{(?:thread|step:[^{}]*)\}\}/g, (raw) => {
679
- const resolved = placeholderValue(raw, threadId, results);
727
+ const resolved = placeholderValue(raw, threadId, results, history);
680
728
  return typeof resolved === "string" ? resolved : JSON.stringify(resolved);
681
729
  });
682
730
  }
683
- if (Array.isArray(value)) return value.map((entry) => resolveValue(entry, threadId, results));
684
- if (isRecord2(value)) return resolveArguments(value, threadId, results);
731
+ if (Array.isArray(value))
732
+ return value.map((entry) => resolveValue(entry, threadId, results, history));
733
+ if (isRecord2(value)) return resolveArguments(value, threadId, results, history);
685
734
  return value;
686
735
  }
687
- function resolveArguments(args, threadId, results) {
736
+ function resolveArguments(args, threadId, results, history = [...results.values()]) {
688
737
  return Object.fromEntries(
689
- Object.entries(args).map(([key, value]) => [key, resolveValue(value, threadId, results)])
738
+ Object.entries(args).map(([key, value]) => [
739
+ key,
740
+ resolveValue(value, threadId, results, history)
741
+ ])
690
742
  );
691
743
  }
692
744
  function stepResult(result) {
@@ -750,7 +802,7 @@ async function runCall(step, playback, input) {
750
802
  let args = step.arguments ?? {};
751
803
  let failure;
752
804
  try {
753
- args = resolveArguments(args, input.threadId, playback.results);
805
+ args = resolveArguments(args, input.threadId, playback.results, playback.history);
754
806
  } catch (error) {
755
807
  failure = error instanceof UnresolvedPlaceholder ? error.message : String(error);
756
808
  }
@@ -775,7 +827,9 @@ async function runCall(step, playback, input) {
775
827
  }
776
828
  }
777
829
  if (failure !== void 0) result = { isError: true, content: [{ type: "text", text: failure }] };
778
- if (step.id !== void 0) playback.results.set(step.id, stepResult(result));
830
+ const resolved = stepResult(result);
831
+ if (step.id !== void 0) playback.results.set(step.id, resolved);
832
+ playback.history.push(resolved);
779
833
  const failed = failure !== void 0 || isRecord2(result) && result.isError === true;
780
834
  input.emit(
781
835
  "item.completed",
@@ -817,7 +871,12 @@ function createPlaybookRunner(input) {
817
871
  (line, index2) => !claimed.has(index2) && (line.match.threadId === void 0 || line.match.threadId.test(turn.threadId)) && (line.match.title === void 0 || title !== void 0 && title.includes(line.match.title))
818
872
  );
819
873
  if (index >= 0) claimed.add(index);
820
- playback = { line: parsed.threads[index] ?? null, cursor: 0, results: /* @__PURE__ */ new Map() };
874
+ playback = {
875
+ line: parsed.threads[index] ?? null,
876
+ cursor: 0,
877
+ results: /* @__PURE__ */ new Map(),
878
+ history: []
879
+ };
821
880
  sessions.set(turn.threadId, playback);
822
881
  }
823
882
  const batch = playback.line?.turns[playback.cursor];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-fake",
3
- "version": "0.2.3056",
3
+ "version": "0.2.3064",
4
4
  "description": "Minimal fake executor for plugin authors and host orchestration tests.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -21,7 +21,7 @@
21
21
  "@types/node": "24.12.4",
22
22
  "esbuild": "0.28.1",
23
23
  "vite-plus": "0.2.2",
24
- "@ycodium-ai/plugin-api": "0.2.3056",
24
+ "@ycodium-ai/plugin-api": "0.2.3064",
25
25
  "ycodium-executor-testing": "0.0.0"
26
26
  },
27
27
  "ycodium": {