@t2000/engine 1.24.8 → 1.24.10

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/index.js CHANGED
@@ -5786,6 +5786,120 @@ Only offer to execute actions you have tools for. If you retrieved a quote, data
5786
5786
  - Cap: at most ONE proactive block per turn.
5787
5787
  - Skip proactive blocks when nothing notable changed since the last turn, when the user is mid-flow on something else, or when you'd just be restating the financial-context block. Quality over quantity \u2014 a block ignored is worse than no block.`;
5788
5788
 
5789
+ // src/post-write-poll.ts
5790
+ async function pollForIndexerCatchup(options) {
5791
+ const { suiRpcUrl, address, ceilingMs, pollIntervalMs, signal } = options;
5792
+ const start = Date.now();
5793
+ if (!suiRpcUrl) {
5794
+ await sleepWithFallback(ceilingMs, signal);
5795
+ return {
5796
+ outcome: "fallback_no_rpc",
5797
+ attempts: 0,
5798
+ resolvedAtMs: Date.now() - start
5799
+ };
5800
+ }
5801
+ if (!address) {
5802
+ await sleepWithFallback(ceilingMs, signal);
5803
+ return {
5804
+ outcome: "fallback_no_address",
5805
+ attempts: 0,
5806
+ resolvedAtMs: Date.now() - start
5807
+ };
5808
+ }
5809
+ let baseline;
5810
+ try {
5811
+ const coins = await fetchWalletCoins(address, suiRpcUrl);
5812
+ baseline = new Map(
5813
+ coins.map((c) => [c.coinType, BigInt(c.totalBalance)])
5814
+ );
5815
+ } catch (err) {
5816
+ console.warn(
5817
+ "[post-write-poll] baseline fetch failed; falling back to fixed sleep:",
5818
+ err
5819
+ );
5820
+ await sleepWithFallback(ceilingMs, signal);
5821
+ return {
5822
+ outcome: "fallback_no_baseline",
5823
+ attempts: 0,
5824
+ resolvedAtMs: Date.now() - start
5825
+ };
5826
+ }
5827
+ const maxAttempts = Math.max(1, Math.floor(ceilingMs / pollIntervalMs));
5828
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
5829
+ if (signal.aborted) {
5830
+ return {
5831
+ outcome: "aborted",
5832
+ attempts: attempt - 1,
5833
+ resolvedAtMs: Date.now() - start
5834
+ };
5835
+ }
5836
+ await new Promise((resolve) => {
5837
+ const t = setTimeout(resolve, pollIntervalMs);
5838
+ signal.addEventListener(
5839
+ "abort",
5840
+ () => {
5841
+ clearTimeout(t);
5842
+ resolve();
5843
+ },
5844
+ { once: true }
5845
+ );
5846
+ });
5847
+ if (signal.aborted) {
5848
+ return {
5849
+ outcome: "aborted",
5850
+ attempts: attempt,
5851
+ resolvedAtMs: Date.now() - start
5852
+ };
5853
+ }
5854
+ let current;
5855
+ try {
5856
+ const coins = await fetchWalletCoins(address, suiRpcUrl);
5857
+ current = new Map(
5858
+ coins.map((c) => [c.coinType, BigInt(c.totalBalance)])
5859
+ );
5860
+ } catch (err) {
5861
+ console.warn(
5862
+ `[post-write-poll] poll attempt ${attempt} failed; continuing:`,
5863
+ err
5864
+ );
5865
+ continue;
5866
+ }
5867
+ if (balancesDiffer(baseline, current)) {
5868
+ return {
5869
+ outcome: "detected_change",
5870
+ attempts: attempt,
5871
+ resolvedAtMs: Date.now() - start
5872
+ };
5873
+ }
5874
+ }
5875
+ return {
5876
+ outcome: "ceiling",
5877
+ attempts: maxAttempts,
5878
+ resolvedAtMs: Date.now() - start
5879
+ };
5880
+ }
5881
+ function balancesDiffer(a, b) {
5882
+ if (a.size !== b.size) return true;
5883
+ for (const [coinType, balance] of a) {
5884
+ if (b.get(coinType) !== balance) return true;
5885
+ }
5886
+ return false;
5887
+ }
5888
+ async function sleepWithFallback(ms, signal) {
5889
+ if (signal.aborted) return;
5890
+ await new Promise((resolve) => {
5891
+ const t = setTimeout(resolve, ms);
5892
+ signal.addEventListener(
5893
+ "abort",
5894
+ () => {
5895
+ clearTimeout(t);
5896
+ resolve();
5897
+ },
5898
+ { once: true }
5899
+ );
5900
+ });
5901
+ }
5902
+
5789
5903
  // src/proactive-marker.ts
5790
5904
  var VALID_TYPES = /* @__PURE__ */ new Set([
5791
5905
  "idle_balance",
@@ -7814,6 +7928,7 @@ var QueryEngine = class {
7814
7928
  * the fresh tool results and narrates from them.
7815
7929
  */
7816
7930
  async *runPostWriteRefresh(action, response, signal) {
7931
+ const totalStart = Date.now();
7817
7932
  const isBundle = Array.isArray(action.steps) && action.steps.length > 0;
7818
7933
  const refreshSet = /* @__PURE__ */ new Set();
7819
7934
  if (isBundle) {
@@ -7855,27 +7970,48 @@ var QueryEngine = class {
7855
7970
  blockvisionApiKey: this.blockvisionApiKey,
7856
7971
  portfolioCache: this.portfolioCache
7857
7972
  };
7973
+ const cacheInvalidationStart = Date.now();
7858
7974
  if (this.walletAddress) {
7859
7975
  this.portfolioCache?.delete(this.walletAddress);
7860
7976
  await clearPortfolioCacheFor(this.walletAddress);
7861
7977
  }
7862
- if (!signal.aborted) {
7863
- await new Promise((resolve) => {
7864
- const t = setTimeout(resolve, 1500);
7865
- signal.addEventListener("abort", () => {
7866
- clearTimeout(t);
7867
- resolve();
7868
- }, { once: true });
7869
- });
7870
- }
7978
+ getTelemetrySink().histogram(
7979
+ "engine.pwr.cache_invalidation_ms",
7980
+ Date.now() - cacheInvalidationStart,
7981
+ { has_wallet: this.walletAddress ? "1" : "0" }
7982
+ );
7983
+ const sleepStart = Date.now();
7984
+ const pollResult = await pollForIndexerCatchup({
7985
+ suiRpcUrl: this.suiRpcUrl,
7986
+ address: this.walletAddress,
7987
+ ceilingMs: 1500,
7988
+ pollIntervalMs: 250,
7989
+ signal
7990
+ });
7991
+ getTelemetrySink().histogram(
7992
+ "engine.pwr.sleep_ms",
7993
+ Date.now() - sleepStart,
7994
+ {
7995
+ aborted: signal.aborted ? "1" : "0",
7996
+ outcome: pollResult.outcome,
7997
+ attempts: String(pollResult.attempts)
7998
+ }
7999
+ );
7871
8000
  if (signal.aborted) return;
8001
+ const refreshStart = Date.now();
7872
8002
  const idStem = `pwr_${action.toolUseId.slice(-6)}`;
7873
8003
  const refreshes = await Promise.all(
7874
8004
  refreshTools.map(async (tool, idx) => {
7875
8005
  const id = `${idStem}_${idx}_${tool.name}`;
8006
+ const toolStart = Date.now();
7876
8007
  try {
7877
8008
  const parsed = tool.inputSchema.safeParse({});
7878
8009
  if (!parsed.success) {
8010
+ getTelemetrySink().histogram(
8011
+ "engine.pwr.tool_ms",
8012
+ Date.now() - toolStart,
8013
+ { tool: tool.name, outcome: "invalid_input" }
8014
+ );
7879
8015
  return {
7880
8016
  tool,
7881
8017
  id,
@@ -7888,6 +8024,11 @@ var QueryEngine = class {
7888
8024
  }
7889
8025
  const { context: toolCtx, readAttemptCount } = withRetryStats(context);
7890
8026
  const result = await tool.call(parsed.data, toolCtx);
8027
+ getTelemetrySink().histogram(
8028
+ "engine.pwr.tool_ms",
8029
+ Date.now() - toolStart,
8030
+ { tool: tool.name, outcome: "success" }
8031
+ );
7891
8032
  return {
7892
8033
  tool,
7893
8034
  id,
@@ -7896,6 +8037,11 @@ var QueryEngine = class {
7896
8037
  attemptCount: readAttemptCount()
7897
8038
  };
7898
8039
  } catch (err) {
8040
+ getTelemetrySink().histogram(
8041
+ "engine.pwr.tool_ms",
8042
+ Date.now() - toolStart,
8043
+ { tool: tool.name, outcome: "error" }
8044
+ );
7899
8045
  return {
7900
8046
  tool,
7901
8047
  id,
@@ -7908,6 +8054,14 @@ var QueryEngine = class {
7908
8054
  }
7909
8055
  })
7910
8056
  );
8057
+ getTelemetrySink().histogram(
8058
+ "engine.pwr.refresh_total_ms",
8059
+ Date.now() - refreshStart,
8060
+ {
8061
+ tool_count: String(refreshTools.length),
8062
+ is_bundle: isBundle ? "1" : "0"
8063
+ }
8064
+ );
7911
8065
  const refreshUses = refreshes.map((r) => ({
7912
8066
  type: "tool_use",
7913
8067
  id: r.id,
@@ -7939,6 +8093,14 @@ var QueryEngine = class {
7939
8093
  ...r.attemptCount !== void 0 ? { attemptCount: r.attemptCount } : {}
7940
8094
  };
7941
8095
  }
8096
+ getTelemetrySink().histogram(
8097
+ "engine.pwr.total_ms",
8098
+ Date.now() - totalStart,
8099
+ {
8100
+ tool_count: String(refreshTools.length),
8101
+ is_bundle: isBundle ? "1" : "0"
8102
+ }
8103
+ );
7942
8104
  }
7943
8105
  interrupt() {
7944
8106
  this.abortController?.abort();