@t2000/engine 0.40.4 → 0.41.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.
package/dist/index.js CHANGED
@@ -1121,12 +1121,15 @@ async function queryHistoryByDate(rpcUrl, address, targetDate, limit) {
1121
1121
  }
1122
1122
  return results.slice(0, limit);
1123
1123
  }
1124
+ var HISTORY_ACTIONS = ["send", "lending", "swap", "transaction"];
1125
+ var DEFAULT_LOOKBACK_DAYS = 30;
1124
1126
  var transactionHistoryTool = buildTool({
1125
1127
  name: "transaction_history",
1126
- description: "Retrieve transaction history: past sends, saves, withdrawals, borrows, repayments, and rewards claims. Pass a date (YYYY-MM-DD) to find transactions from a specific day, or omit for the most recent.",
1128
+ description: "Retrieve recent transaction history (last 30 days by default): sends, saves, withdrawals, borrows, repayments, and rewards claims. Pass `date` (YYYY-MM-DD) for a specific day, `action` to filter by category (send/lending/swap), or both.",
1127
1129
  inputSchema: z.object({
1128
1130
  limit: z.number().int().min(1).max(50).optional(),
1129
- date: z.string().optional().describe("Specific date to search for transactions (YYYY-MM-DD format). Paginates back to find that day.")
1131
+ date: z.string().optional().describe("Specific date to search for transactions (YYYY-MM-DD format). Paginates back to find that day."),
1132
+ action: z.enum(HISTORY_ACTIONS).optional().describe("Filter by action: send, lending, swap, or transaction.")
1130
1133
  }),
1131
1134
  jsonSchema: {
1132
1135
  type: "object",
@@ -1138,6 +1141,11 @@ var transactionHistoryTool = buildTool({
1138
1141
  date: {
1139
1142
  type: "string",
1140
1143
  description: "Specific date to search for transactions (YYYY-MM-DD format). Paginates back to find that day."
1144
+ },
1145
+ action: {
1146
+ type: "string",
1147
+ enum: [...HISTORY_ACTIONS],
1148
+ description: "Filter results by action category: send, lending, swap, or transaction."
1141
1149
  }
1142
1150
  }
1143
1151
  },
@@ -1145,29 +1153,55 @@ var transactionHistoryTool = buildTool({
1145
1153
  maxResultSizeChars: 8e3,
1146
1154
  async call(input, context) {
1147
1155
  const limit = input.limit ?? 10;
1156
+ const action = input.action;
1157
+ const finalize = (records2) => {
1158
+ let scoped = records2;
1159
+ if (action) scoped = scoped.filter((r) => r.action === action);
1160
+ return scoped.slice(0, limit);
1161
+ };
1148
1162
  if (context.agent) {
1149
1163
  const agent = requireAgent(context);
1150
- const records2 = await agent.history({ limit });
1164
+ const records2 = await agent.history({ limit: input.date ? limit : Math.max(limit * 4, 50) });
1165
+ const filtered2 = finalize(records2);
1151
1166
  return {
1152
- data: { transactions: records2, count: records2.length, date: input.date ?? null },
1153
- displayText: `${records2.length} recent transaction(s)`
1167
+ data: { transactions: filtered2, count: filtered2.length, date: input.date ?? null, action: action ?? null },
1168
+ displayText: `${filtered2.length} recent transaction(s)`
1154
1169
  };
1155
1170
  }
1156
1171
  if (!context.walletAddress || !context.suiRpcUrl) {
1157
1172
  throw new Error("Transaction history requires a wallet address");
1158
1173
  }
1159
1174
  if (input.date) {
1160
- const records2 = await queryHistoryByDate(context.suiRpcUrl, context.walletAddress, input.date, limit);
1175
+ const records2 = await queryHistoryByDate(
1176
+ context.suiRpcUrl,
1177
+ context.walletAddress,
1178
+ input.date,
1179
+ Math.max(limit * 4, 50)
1180
+ );
1181
+ const filtered2 = finalize(records2);
1161
1182
  const dateLabel = new Date(input.date).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
1162
1183
  return {
1163
- data: { transactions: records2, count: records2.length, date: input.date },
1164
- displayText: records2.length > 0 ? `${records2.length} transaction(s) on ${dateLabel}` : `No transactions found on ${dateLabel}`
1184
+ data: { transactions: filtered2, count: filtered2.length, date: input.date, action: action ?? null },
1185
+ displayText: filtered2.length > 0 ? `${filtered2.length} transaction(s) on ${dateLabel}` : `No transactions found on ${dateLabel}`
1165
1186
  };
1166
1187
  }
1167
- const records = await queryHistoryRpc(context.suiRpcUrl, context.walletAddress, limit);
1188
+ const cutoffMs = Date.now() - DEFAULT_LOOKBACK_DAYS * 864e5;
1189
+ const records = await queryHistoryRpc(
1190
+ context.suiRpcUrl,
1191
+ context.walletAddress,
1192
+ Math.max(limit * 4, 50)
1193
+ );
1194
+ const recent = records.filter((r) => r.timestamp >= cutoffMs);
1195
+ const filtered = finalize(recent);
1168
1196
  return {
1169
- data: { transactions: records, count: records.length, date: null },
1170
- displayText: `${records.length} recent transaction(s)`
1197
+ data: {
1198
+ transactions: filtered,
1199
+ count: filtered.length,
1200
+ date: null,
1201
+ action: action ?? null,
1202
+ lookbackDays: DEFAULT_LOOKBACK_DAYS
1203
+ },
1204
+ displayText: `${filtered.length} transaction(s) in the last ${DEFAULT_LOOKBACK_DAYS} days`
1171
1205
  };
1172
1206
  }
1173
1207
  });
@@ -1547,16 +1581,21 @@ function matchesQuery(service, q) {
1547
1581
  }
1548
1582
  var mppServicesTool = buildTool({
1549
1583
  name: "mpp_services",
1550
- description: "Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Use this BEFORE calling pay_api to find the correct URL and body format for any real-world API (weather, search, translation, image generation, email, maps, etc.).",
1584
+ description: "Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Pass `query` for keyword search or `category` to filter by category. Calling with NO filters returns a category summary (not the full catalog) \u2014 narrow first, then fetch endpoints. Use this BEFORE calling pay_api.",
1551
1585
  inputSchema: z.object({
1552
- query: z.string().optional().describe('Filter by keyword (e.g. "postcard", "translate", "weather"). Omit to list all services.')
1586
+ query: z.string().optional().describe('Filter by keyword (e.g. "postcard", "translate", "weather").'),
1587
+ category: z.string().optional().describe('Filter by category exactly (e.g. "weather", "image"). See category summary returned when called without filters.')
1553
1588
  }),
1554
1589
  jsonSchema: {
1555
1590
  type: "object",
1556
1591
  properties: {
1557
1592
  query: {
1558
1593
  type: "string",
1559
- description: 'Filter by keyword (e.g. "postcard", "translate", "weather"). Omit to list all.'
1594
+ description: 'Filter by keyword (e.g. "postcard", "translate", "weather").'
1595
+ },
1596
+ category: {
1597
+ type: "string",
1598
+ description: 'Filter by category exactly (e.g. "weather", "image").'
1560
1599
  }
1561
1600
  },
1562
1601
  required: []
@@ -1565,7 +1604,34 @@ var mppServicesTool = buildTool({
1565
1604
  maxResultSizeChars: 5e3,
1566
1605
  async call(input) {
1567
1606
  const catalog = await fetchCatalog();
1568
- const filtered = input.query ? catalog.filter((s) => matchesQuery(s, input.query)) : catalog;
1607
+ if (!input.query && !input.category) {
1608
+ const counts = /* @__PURE__ */ new Map();
1609
+ for (const svc of catalog) {
1610
+ for (const cat of svc.categories) {
1611
+ counts.set(cat, (counts.get(cat) ?? 0) + 1);
1612
+ }
1613
+ }
1614
+ const categories = [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([category, services2]) => ({ category, services: services2 }));
1615
+ return {
1616
+ data: {
1617
+ _refine: {
1618
+ reason: "MPP catalog has many services \u2014 pick a category or supply a query first.",
1619
+ suggestedParams: { category: categories[0]?.category ?? "weather" }
1620
+ },
1621
+ categories,
1622
+ totalServices: catalog.length
1623
+ },
1624
+ displayText: `${catalog.length} services across ${categories.length} categories. Re-call with a category or query.`
1625
+ };
1626
+ }
1627
+ let filtered = catalog;
1628
+ if (input.category) {
1629
+ const cat = input.category.toLowerCase();
1630
+ filtered = filtered.filter((s) => s.categories.some((c) => c.toLowerCase() === cat));
1631
+ }
1632
+ if (input.query) {
1633
+ filtered = filtered.filter((s) => matchesQuery(s, input.query));
1634
+ }
1569
1635
  const services = filtered.map((s) => ({
1570
1636
  id: s.id,
1571
1637
  name: s.name,
@@ -1578,7 +1644,11 @@ var mppServicesTool = buildTool({
1578
1644
  price: `$${e.price}`
1579
1645
  }))
1580
1646
  }));
1581
- const summary = input.query ? `Found ${services.length} service(s) matching "${input.query}"` : `${services.length} services available on MPP gateway`;
1647
+ const filterDesc = [
1648
+ input.query ? `query "${input.query}"` : null,
1649
+ input.category ? `category "${input.category}"` : null
1650
+ ].filter(Boolean).join(" + ");
1651
+ const summary = `Found ${services.length} service(s) matching ${filterDesc}`;
1582
1652
  return {
1583
1653
  data: { services, total: services.length },
1584
1654
  displayText: summary
@@ -2830,6 +2900,10 @@ async function cachedFetch(url) {
2830
2900
  apiCache.set(url, { data, ts: Date.now() });
2831
2901
  return data;
2832
2902
  }
2903
+ async function fetchDefillamaYieldPools() {
2904
+ const data = await cachedFetch(`${YIELDS_API2}/pools`);
2905
+ return data.data ?? [];
2906
+ }
2833
2907
  function fmtToolTvl(tvl) {
2834
2908
  if (tvl >= 1e9) return `$${(tvl / 1e9).toFixed(1)}B`;
2835
2909
  if (tvl >= 1e6) return `$${(tvl / 1e6).toFixed(1)}M`;
@@ -2858,8 +2932,25 @@ var defillamaYieldPoolsTool = buildTool({
2858
2932
  isReadOnly: true,
2859
2933
  maxResultSizeChars: 6e3,
2860
2934
  async call(input) {
2861
- const data = await cachedFetch(`${YIELDS_API2}/pools`);
2862
- let pools = data.data ?? [];
2935
+ if (!input.chain && !input.project) {
2936
+ const all = await fetchDefillamaYieldPools();
2937
+ const chainCounts = /* @__PURE__ */ new Map();
2938
+ for (const p of all) {
2939
+ chainCounts.set(p.chain, (chainCounts.get(p.chain) ?? 0) + 1);
2940
+ }
2941
+ const topChains = [...chainCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([chain, count]) => ({ chain, pools: count }));
2942
+ return {
2943
+ data: {
2944
+ _refine: {
2945
+ reason: "Cross-chain yield search is too broad; pick a chain.",
2946
+ suggestedParams: { chain: "Sui" },
2947
+ availableChains: topChains
2948
+ }
2949
+ },
2950
+ displayText: "Yield query needs a chain filter. Common chains: " + topChains.map((c) => c.chain).join(", ")
2951
+ };
2952
+ }
2953
+ let pools = await fetchDefillamaYieldPools();
2863
2954
  if (input.chain) {
2864
2955
  const chain = input.chain.toLowerCase();
2865
2956
  pools = pools.filter((p) => p.chain.toLowerCase() === chain);
@@ -3149,6 +3240,40 @@ function getDefaultTools() {
3149
3240
  return applyToolFlags([...READ_TOOLS, ...WRITE_TOOLS]);
3150
3241
  }
3151
3242
 
3243
+ // src/tools/tool-modifiable-fields.ts
3244
+ var TOOL_MODIFIABLE_FIELDS = {
3245
+ save_deposit: [
3246
+ { name: "amount", kind: "amount", asset: "USDC" }
3247
+ ],
3248
+ withdraw: [
3249
+ { name: "amount", kind: "amount", asset: "USDC" }
3250
+ ],
3251
+ send_transfer: [
3252
+ // `amount` first so the UI surfaces it prominently; the recipient
3253
+ // address field is also editable in case the user typed the wrong one.
3254
+ { name: "amount", kind: "amount" },
3255
+ { name: "to", kind: "address" }
3256
+ ],
3257
+ swap_execute: [
3258
+ { name: "amount", kind: "amount" }
3259
+ ],
3260
+ borrow: [
3261
+ { name: "amount", kind: "amount", asset: "USDC" }
3262
+ ],
3263
+ repay_debt: [
3264
+ { name: "amount", kind: "amount", asset: "USDC" }
3265
+ ],
3266
+ volo_stake: [
3267
+ { name: "amount", kind: "amount", asset: "SUI" }
3268
+ ],
3269
+ volo_unstake: [
3270
+ { name: "amount", kind: "amount", asset: "vSUI" }
3271
+ ]
3272
+ };
3273
+ function getModifiableFields(toolName) {
3274
+ return TOOL_MODIFIABLE_FIELDS[toolName];
3275
+ }
3276
+
3152
3277
  // src/prompt.ts
3153
3278
  var DEFAULT_SYSTEM_PROMPT = `You are Audric \u2014 a financial agent on Sui. Audric is exactly five products: Audric Passport (the trust layer \u2014 Google sign-in, non-custodial wallet, tap-to-confirm consent, sponsored gas \u2014 wraps every other product), Audric Intelligence (you \u2014 the 5-system brain: Agent Harness with 40 tools, Reasoning Engine with 9 guards and 7 skill recipes, Silent Profile, Chain Memory, AdviceLog), Audric Finance (manage money on Sui \u2014 Save via NAVI lending at 3-8% APY USDC, Credit via NAVI borrowing with health factor, Swap via Cetus aggregator across 20+ DEXs at 0.1% fee, Charts for yield/health/portfolio viz), Audric Pay (move money \u2014 send USDC, receive via payment links / invoices / QR; free, global, instant on Sui), and Audric Store (creator marketplace, ships Phase 5 \u2014 say "coming soon" if asked). Save, swap, borrow, repay, withdraw, charts \u2192 Audric Finance. Send, receive, payment-link, invoice, QR \u2192 Audric Pay. Your silent context (profile, memory, chain facts, advice log) shapes your replies but never surfaces as a notification \u2014 you act only when the user asks, and every write waits on their tap-to-confirm via Passport. You can also call 41 paid APIs (music, image, research, translation, weather, fulfilment) via MPP micropayments using the pay_api tool \u2014 this is an internal capability, not a promoted product, so only mention it when the user asks for something that needs it.
3154
3279
 
@@ -3248,6 +3373,11 @@ var CostTracker = class {
3248
3373
  };
3249
3374
 
3250
3375
  // src/guards.ts
3376
+ function guardVerdictToAction(verdict) {
3377
+ if (verdict === "pass" || verdict === "hint") return "allow";
3378
+ if (verdict === "warn") return "warn";
3379
+ return "block";
3380
+ }
3251
3381
  var DEFAULT_GUARD_CONFIG = {
3252
3382
  balanceValidation: true,
3253
3383
  healthFactor: { warnBelow: 2, blockBelow: 1.5 },
@@ -3464,9 +3594,22 @@ function createGuardRunnerState() {
3464
3594
  lastHealthFactor: null
3465
3595
  };
3466
3596
  }
3467
- function runGuards(tool, call, state, config, conversationContext) {
3597
+ function runGuards(tool, call, state, config, conversationContext, onGuardFired) {
3468
3598
  const results = [];
3469
3599
  const now = Date.now();
3600
+ const fire = (verdict, tier, gate, hadInjection) => {
3601
+ if (!onGuardFired) return;
3602
+ try {
3603
+ onGuardFired({
3604
+ name: gate,
3605
+ tier,
3606
+ action: guardVerdictToAction(verdict),
3607
+ injectionAdded: hadInjection
3608
+ });
3609
+ } catch (err) {
3610
+ console.warn("[guards] onGuardFired threw (ignored):", err);
3611
+ }
3612
+ };
3470
3613
  if (config.inputValidation !== false && tool.preflight) {
3471
3614
  const check = tool.preflight(call.input);
3472
3615
  if (!check.valid) {
@@ -3479,6 +3622,7 @@ function runGuards(tool, call, state, config, conversationContext) {
3479
3622
  tier: "safety",
3480
3623
  message: check.error
3481
3624
  };
3625
+ fire("block", "safety", "input_validation", false);
3482
3626
  return {
3483
3627
  blocked: true,
3484
3628
  blockReason: check.error,
@@ -3520,6 +3664,10 @@ function runGuards(tool, call, state, config, conversationContext) {
3520
3664
  }));
3521
3665
  const block = results.find((r) => r.verdict === "block");
3522
3666
  if (block) {
3667
+ for (const r of results) {
3668
+ if (r.verdict === "pass") continue;
3669
+ fire(r.verdict, r.tier, r.gate, false);
3670
+ }
3523
3671
  return {
3524
3672
  blocked: true,
3525
3673
  blockReason: block.message ?? `Blocked by ${block.gate}`,
@@ -3532,6 +3680,10 @@ function runGuards(tool, call, state, config, conversationContext) {
3532
3680
  _gate: r.gate,
3533
3681
  ...r.verdict === "hint" ? { _hint: r.message } : { _warning: r.message }
3534
3682
  }));
3683
+ for (const r of results) {
3684
+ if (r.verdict === "pass") continue;
3685
+ fire(r.verdict, r.tier, r.gate, r.verdict === "hint" || r.verdict === "warn");
3686
+ }
3535
3687
  return { blocked: false, injections, events };
3536
3688
  }
3537
3689
  function updateGuardStateAfterToolResult(toolName, tool, input, result, isError, state) {
@@ -3576,6 +3728,7 @@ function microcompact(messages) {
3576
3728
  const seen = /* @__PURE__ */ new Map();
3577
3729
  let toolUseIndex = 0;
3578
3730
  const toolUseInputs = /* @__PURE__ */ new Map();
3731
+ const dedupedToolUseIds = /* @__PURE__ */ new Set();
3579
3732
  for (const msg of messages) {
3580
3733
  for (const block of msg.content) {
3581
3734
  if (block.type === "tool_use") {
@@ -3583,7 +3736,7 @@ function microcompact(messages) {
3583
3736
  }
3584
3737
  }
3585
3738
  }
3586
- return messages.map((msg) => {
3739
+ const out = messages.map((msg) => {
3587
3740
  if (msg.role !== "user") return { role: msg.role, content: [...msg.content] };
3588
3741
  const hasToolResults = msg.content.some((b) => b.type === "tool_result");
3589
3742
  if (!hasToolResults) return { role: msg.role, content: [...msg.content] };
@@ -3594,6 +3747,7 @@ function microcompact(messages) {
3594
3747
  toolUseIndex++;
3595
3748
  const prior = seen.get(key);
3596
3749
  if (prior && !block.isError) {
3750
+ dedupedToolUseIds.add(block.toolUseId);
3597
3751
  return {
3598
3752
  ...block,
3599
3753
  content: `[Same result as call #${prior.turnIndex} \u2014 ${key.split(":")[0]} with identical inputs. Result unchanged.]`
@@ -3606,6 +3760,13 @@ function microcompact(messages) {
3606
3760
  });
3607
3761
  return { role: msg.role, content: newContent };
3608
3762
  });
3763
+ Object.defineProperty(out, "dedupedToolUseIds", {
3764
+ value: dedupedToolUseIds,
3765
+ enumerable: false,
3766
+ writable: false,
3767
+ configurable: false
3768
+ });
3769
+ return out;
3609
3770
  }
3610
3771
  function stableStringify(value) {
3611
3772
  if (value === null || value === void 0) return "";
@@ -3845,13 +4006,18 @@ var PERMISSION_PRESETS = {
3845
4006
  ]
3846
4007
  }
3847
4008
  };
3848
- function resolvePermissionTier(operation, amountUsd, config) {
4009
+ function resolvePermissionTier(operation, amountUsd, config, sessionSpendUsd) {
3849
4010
  const rule = config.rules.find((r) => r.operation === operation);
3850
4011
  const autoBelow = rule?.autoBelow ?? config.globalAutoBelow;
3851
4012
  const confirmBetween = rule?.confirmBetween ?? 1e3;
3852
- if (amountUsd < autoBelow) return "auto";
3853
- if (amountUsd < confirmBetween) return "confirm";
3854
- return "explicit";
4013
+ let tier;
4014
+ if (amountUsd < autoBelow) tier = "auto";
4015
+ else if (amountUsd < confirmBetween) tier = "confirm";
4016
+ else tier = "explicit";
4017
+ if (tier === "auto" && typeof sessionSpendUsd === "number" && sessionSpendUsd + amountUsd > config.autonomousDailyLimit) {
4018
+ return "confirm";
4019
+ }
4020
+ return tier;
3855
4021
  }
3856
4022
  var TOOL_TO_OPERATION = {
3857
4023
  save_deposit: "save",
@@ -3945,7 +4111,8 @@ var EarlyToolDispatcher = class {
3945
4111
  toolName: entry.call.name,
3946
4112
  toolUseId: entry.call.id,
3947
4113
  result: budgeted,
3948
- isError: result.isError
4114
+ isError: result.isError,
4115
+ wasEarlyDispatched: true
3949
4116
  };
3950
4117
  } catch (err) {
3951
4118
  yield {
@@ -3953,7 +4120,8 @@ var EarlyToolDispatcher = class {
3953
4120
  toolName: entry.call.name,
3954
4121
  toolUseId: entry.call.id,
3955
4122
  result: { error: err instanceof Error ? err.message : "Tool execution failed" },
3956
- isError: true
4123
+ isError: true,
4124
+ wasEarlyDispatched: true
3957
4125
  };
3958
4126
  }
3959
4127
  }
@@ -4005,6 +4173,10 @@ var QueryEngine = class {
4005
4173
  contextSummarizer;
4006
4174
  priceCache;
4007
4175
  permissionConfig;
4176
+ // [v1.4] Session-scoped autonomous spend tracking.
4177
+ sessionSpendUsd;
4178
+ onAutoExecuted;
4179
+ onGuardFired;
4008
4180
  matchedRecipe = null;
4009
4181
  messages = [];
4010
4182
  abortController = null;
@@ -4034,6 +4206,9 @@ var QueryEngine = class {
4034
4206
  this.contextSummarizer = config.contextSummarizer;
4035
4207
  this.priceCache = config.priceCache;
4036
4208
  this.permissionConfig = config.permissionConfig;
4209
+ this.sessionSpendUsd = config.sessionSpendUsd;
4210
+ this.onAutoExecuted = config.onAutoExecuted;
4211
+ this.onGuardFired = config.onGuardFired;
4037
4212
  this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
4038
4213
  }
4039
4214
  /**
@@ -4155,7 +4330,8 @@ var QueryEngine = class {
4155
4330
  env: this.env,
4156
4331
  signal,
4157
4332
  priceCache: this.priceCache,
4158
- permissionConfig: this.permissionConfig
4333
+ permissionConfig: this.permissionConfig,
4334
+ sessionSpendUsd: this.sessionSpendUsd
4159
4335
  };
4160
4336
  let turns = 0;
4161
4337
  let hasRetriedWithCleanHistory = false;
@@ -4174,13 +4350,25 @@ var QueryEngine = class {
4174
4350
  };
4175
4351
  const dispatcher = new EarlyToolDispatcher(this.tools, context);
4176
4352
  try {
4177
- this.messages = microcompact(this.messages);
4353
+ const microcompacted = microcompact(this.messages);
4354
+ this.messages = microcompacted;
4355
+ for (const dedupedId of microcompacted.dedupedToolUseIds) {
4356
+ yield {
4357
+ type: "tool_result",
4358
+ toolName: "__deduped__",
4359
+ toolUseId: dedupedId,
4360
+ result: null,
4361
+ isError: false,
4362
+ resultDeduped: true
4363
+ };
4364
+ }
4178
4365
  if (this.contextBudget.shouldCompact()) {
4179
4366
  this.messages = await compactMessages(this.messages, {
4180
4367
  maxTokens: 1e5,
4181
4368
  keepRecentCount: 8,
4182
4369
  summarizer: this.contextSummarizer
4183
4370
  });
4371
+ yield { type: "compaction" };
4184
4372
  }
4185
4373
  this.messages = validateHistory(this.messages);
4186
4374
  if (process.env.NODE_ENV !== "test") {
@@ -4340,7 +4528,12 @@ ${recipeCtx}`;
4340
4528
  const operation = toolNameToOperation(call.name);
4341
4529
  if (operation) {
4342
4530
  const usdValue = resolveUsdValue(call.name, call.input, context.priceCache);
4343
- const tier = resolvePermissionTier(operation, usdValue, context.permissionConfig);
4531
+ const tier = resolvePermissionTier(
4532
+ operation,
4533
+ usdValue,
4534
+ context.permissionConfig,
4535
+ context.sessionSpendUsd
4536
+ );
4344
4537
  return tier !== "auto";
4345
4538
  }
4346
4539
  }
@@ -4363,7 +4556,14 @@ ${recipeCtx}`;
4363
4556
  guardedApproved.push(call);
4364
4557
  continue;
4365
4558
  }
4366
- const check = runGuards(tool, call, this.guardState, this.guardConfig, convCtx);
4559
+ const check = runGuards(
4560
+ tool,
4561
+ call,
4562
+ this.guardState,
4563
+ this.guardConfig,
4564
+ convCtx,
4565
+ this.onGuardFired
4566
+ );
4367
4567
  this.guardEvents.push(...check.events);
4368
4568
  if (check.blocked) {
4369
4569
  yield {
@@ -4445,6 +4645,22 @@ ${recipeCtx}`;
4445
4645
  toolUseId: finalEvent.toolUseId
4446
4646
  };
4447
4647
  }
4648
+ if (tool && !tool.isReadOnly && this.onAutoExecuted && this.permissionConfig && this.priceCache) {
4649
+ const operation = toolNameToOperation(toolEvent.toolName);
4650
+ if (operation && originalCall) {
4651
+ const usdValue = resolveUsdValue(
4652
+ toolEvent.toolName,
4653
+ originalCall.input,
4654
+ this.priceCache
4655
+ );
4656
+ Promise.resolve().then(() => this.onAutoExecuted({
4657
+ toolName: toolEvent.toolName,
4658
+ usdValue
4659
+ })).catch((err) => {
4660
+ console.warn("[engine] onAutoExecuted callback failed:", err);
4661
+ });
4662
+ }
4663
+ }
4448
4664
  }
4449
4665
  toolResultBlocks.push({
4450
4666
  type: "tool_result",
@@ -4463,7 +4679,8 @@ ${recipeCtx}`;
4463
4679
  pendingWrite.call,
4464
4680
  this.guardState,
4465
4681
  this.guardConfig,
4466
- convCtx
4682
+ convCtx,
4683
+ this.onGuardFired
4467
4684
  );
4468
4685
  this.guardEvents.push(...check.events);
4469
4686
  if (check.blocked) {
@@ -4490,6 +4707,8 @@ ${recipeCtx}`;
4490
4707
  }
4491
4708
  if (pendingWrite) {
4492
4709
  const writeGuardInjections = pendingWrite.call._guardInjections;
4710
+ const modifiableFields = getModifiableFields(pendingWrite.call.name);
4711
+ const turnIndex = this.messages.filter((m) => m.role === "assistant").length;
4493
4712
  yield {
4494
4713
  type: "pending_action",
4495
4714
  action: {
@@ -4503,7 +4722,9 @@ ${recipeCtx}`;
4503
4722
  content: b.content,
4504
4723
  isError: b.isError ?? false
4505
4724
  })),
4506
- ...writeGuardInjections?.length ? { guardInjections: writeGuardInjections } : {}
4725
+ ...writeGuardInjections?.length ? { guardInjections: writeGuardInjections } : {},
4726
+ ...modifiableFields?.length ? { modifiableFields } : {},
4727
+ turnIndex
4507
4728
  }
4508
4729
  };
4509
4730
  return;
@@ -5670,6 +5891,6 @@ function sanitizeAnthropicMessages(messages) {
5670
5891
  return merged;
5671
5892
  }
5672
5893
 
5673
- export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYSTEM_PROMPT, EarlyToolDispatcher, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, classifyEffort, clearPriceCache, compactMessages, createGuardRunnerState, defillamaChainTvlTool, defillamaPriceChangeTool, defillamaProtocolFeesTool, defillamaProtocolInfoTool, defillamaSuiProtocolsTool, defillamaTokenPricesTool, defillamaYieldPoolsTool, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getToolFlags, getWalletAddress, guardArtifactPreview, guardStaleData, hasNaviMcp, healthCheckTool, loadRecipes, microcompact, mppServicesTool, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resolvePermissionTier, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
5894
+ export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYSTEM_PROMPT, EarlyToolDispatcher, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, classifyEffort, clearPriceCache, compactMessages, createGuardRunnerState, defillamaChainTvlTool, defillamaPriceChangeTool, defillamaProtocolFeesTool, defillamaProtocolInfoTool, defillamaSuiProtocolsTool, defillamaTokenPricesTool, defillamaYieldPoolsTool, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getModifiableFields, getToolFlags, getWalletAddress, guardArtifactPreview, guardStaleData, hasNaviMcp, healthCheckTool, loadRecipes, microcompact, mppServicesTool, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resolvePermissionTier, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
5674
5895
  //# sourceMappingURL=index.js.map
5675
5896
  //# sourceMappingURL=index.js.map