@t2000/engine 0.33.1 → 0.35.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
@@ -21,7 +21,9 @@ function buildTool(opts) {
21
21
  isConcurrencySafe: isReadOnly,
22
22
  permissionLevel: opts.permissionLevel ?? (isReadOnly ? "auto" : "confirm"),
23
23
  flags: opts.flags ?? {},
24
- preflight: opts.preflight
24
+ preflight: opts.preflight,
25
+ maxResultSizeChars: opts.maxResultSizeChars,
26
+ summarizeOnTruncate: opts.summarizeOnTruncate
25
27
  };
26
28
  }
27
29
  function toolsToDefinitions(tools) {
@@ -67,6 +69,9 @@ async function* runTools(pending, tools, context, txMutex) {
67
69
  return { call, result: { data: { error: `Unknown tool: ${call.name}` } }, isError: true };
68
70
  }
69
71
  const execResult = await executeSingleTool(tool, call, context);
72
+ if (!execResult.isError) {
73
+ execResult.data = budgetToolResult(execResult.data, tool);
74
+ }
70
75
  return { call, result: execResult, isError: execResult.isError };
71
76
  })
72
77
  );
@@ -108,6 +113,9 @@ async function* runTools(pending, tools, context, txMutex) {
108
113
  await txMutex.acquire();
109
114
  try {
110
115
  const result = await executeSingleTool(tool, call, context);
116
+ if (!result.isError) {
117
+ result.data = budgetToolResult(result.data, tool);
118
+ }
111
119
  yield {
112
120
  type: "tool_result",
113
121
  toolName: call.name,
@@ -158,6 +166,29 @@ async function executeSingleTool(tool, call, context) {
158
166
  const result = await tool.call(parsed.data, context);
159
167
  return { data: result.data, isError: false };
160
168
  }
169
+ function budgetToolResult(data, tool) {
170
+ if (!tool.maxResultSizeChars) return data;
171
+ const serialized = typeof data === "string" ? data : JSON.stringify(data);
172
+ if (serialized.length <= tool.maxResultSizeChars) return data;
173
+ if (tool.summarizeOnTruncate) {
174
+ const summarized = tool.summarizeOnTruncate(serialized, tool.maxResultSizeChars);
175
+ try {
176
+ return JSON.parse(summarized);
177
+ } catch {
178
+ return summarized;
179
+ }
180
+ }
181
+ const preview = serialized.slice(0, tool.maxResultSizeChars);
182
+ const linesOmitted = serialized.split("\n").length - preview.split("\n").length;
183
+ const truncated = `${preview}
184
+
185
+ [Truncated \u2014 ${linesOmitted} lines omitted. Call ${tool.name} with narrower parameters (e.g. smaller date range or limit) to see more.]`;
186
+ try {
187
+ return JSON.parse(truncated);
188
+ } catch {
189
+ return truncated;
190
+ }
191
+ }
161
192
 
162
193
  // src/tool-flags.ts
163
194
  var TOOL_FLAGS = {
@@ -1114,6 +1145,7 @@ var transactionHistoryTool = buildTool({
1114
1145
  }
1115
1146
  },
1116
1147
  isReadOnly: true,
1148
+ maxResultSizeChars: 8e3,
1117
1149
  async call(input, context) {
1118
1150
  const limit = input.limit ?? 10;
1119
1151
  if (context.agent) {
@@ -1533,6 +1565,7 @@ var mppServicesTool = buildTool({
1533
1565
  required: []
1534
1566
  },
1535
1567
  isReadOnly: true,
1568
+ maxResultSizeChars: 5e3,
1536
1569
  async call(input) {
1537
1570
  const catalog = await fetchCatalog();
1538
1571
  const filtered = input.query ? catalog.filter((s) => matchesQuery(s, input.query)) : catalog;
@@ -1771,6 +1804,7 @@ var webSearchTool = buildTool({
1771
1804
  required: ["query"]
1772
1805
  },
1773
1806
  isReadOnly: true,
1807
+ maxResultSizeChars: 8e3,
1774
1808
  async call(input, context) {
1775
1809
  const apiKey = context.env?.BRAVE_API_KEY ?? process.env.BRAVE_API_KEY;
1776
1810
  if (!apiKey) {
@@ -3051,12 +3085,11 @@ var createScheduleTool = buildTool({
3051
3085
  },
3052
3086
  required: ["actionType", "amount", "schedule"]
3053
3087
  },
3054
- isReadOnly: false,
3055
- permissionLevel: "confirm",
3088
+ isReadOnly: true,
3056
3089
  async call(input, context) {
3057
3090
  const { apiUrl, internalKey, address } = getApiConfig(context);
3058
3091
  if (!apiUrl || !address) {
3059
- return { data: null, displayText: "Scheduled actions are not available." };
3092
+ return { data: null, displayText: "Scheduled actions are not available \u2014 missing wallet or API configuration." };
3060
3093
  }
3061
3094
  let cronExpr;
3062
3095
  try {
@@ -3152,8 +3185,7 @@ var cancelScheduleTool = buildTool({
3152
3185
  },
3153
3186
  required: ["scheduleId"]
3154
3187
  },
3155
- isReadOnly: false,
3156
- permissionLevel: "confirm",
3188
+ isReadOnly: true,
3157
3189
  async call(input, context) {
3158
3190
  const { apiUrl, internalKey, address } = getApiConfig(context);
3159
3191
  if (!apiUrl || !address) {
@@ -3228,6 +3260,7 @@ var defillamaYieldPoolsTool = buildTool({
3228
3260
  required: []
3229
3261
  },
3230
3262
  isReadOnly: true,
3263
+ maxResultSizeChars: 6e3,
3231
3264
  async call(input) {
3232
3265
  const data = await cachedFetch(`${YIELDS_API2}/pools`);
3233
3266
  let pools = data.data ?? [];
@@ -3273,6 +3306,7 @@ var defillamaProtocolInfoTool = buildTool({
3273
3306
  required: ["name"]
3274
3307
  },
3275
3308
  isReadOnly: true,
3309
+ maxResultSizeChars: 4e3,
3276
3310
  async call(input) {
3277
3311
  const data = await cachedFetch(`${LLAMA_API2}/protocol/${encodeURIComponent(input.name)}`);
3278
3312
  const result = {
@@ -3505,7 +3539,9 @@ var READ_TOOLS = [
3505
3539
  spendingAnalyticsTool,
3506
3540
  yieldSummaryTool,
3507
3541
  activitySummaryTool,
3508
- listSchedulesTool
3542
+ listSchedulesTool,
3543
+ createScheduleTool,
3544
+ cancelScheduleTool
3509
3545
  ];
3510
3546
  var WRITE_TOOLS = [
3511
3547
  saveDepositTool,
@@ -3518,9 +3554,7 @@ var WRITE_TOOLS = [
3518
3554
  swapExecuteTool,
3519
3555
  voloStakeTool,
3520
3556
  voloUnstakeTool,
3521
- saveContactTool,
3522
- createScheduleTool,
3523
- cancelScheduleTool
3557
+ saveContactTool
3524
3558
  ];
3525
3559
  function getDefaultTools() {
3526
3560
  return applyToolFlags([...READ_TOOLS, ...WRITE_TOOLS]);
@@ -3948,6 +3982,52 @@ function extractConversationText(messages) {
3948
3982
  };
3949
3983
  }
3950
3984
 
3985
+ // src/compact/microcompact.ts
3986
+ function microcompact(messages) {
3987
+ const seen = /* @__PURE__ */ new Map();
3988
+ let toolUseIndex = 0;
3989
+ const toolUseInputs = /* @__PURE__ */ new Map();
3990
+ for (const msg of messages) {
3991
+ for (const block of msg.content) {
3992
+ if (block.type === "tool_use") {
3993
+ toolUseInputs.set(block.id, `${block.name}:${stableStringify(block.input)}`);
3994
+ }
3995
+ }
3996
+ }
3997
+ return messages.map((msg) => {
3998
+ if (msg.role !== "user") return { role: msg.role, content: [...msg.content] };
3999
+ const hasToolResults = msg.content.some((b) => b.type === "tool_result");
4000
+ if (!hasToolResults) return { role: msg.role, content: [...msg.content] };
4001
+ const newContent = msg.content.map((block) => {
4002
+ if (block.type !== "tool_result") return block;
4003
+ const key = toolUseInputs.get(block.toolUseId);
4004
+ if (!key) return block;
4005
+ toolUseIndex++;
4006
+ const prior = seen.get(key);
4007
+ if (prior && !block.isError) {
4008
+ return {
4009
+ ...block,
4010
+ content: `[Same result as call #${prior.turnIndex} \u2014 ${key.split(":")[0]} with identical inputs. Result unchanged.]`
4011
+ };
4012
+ }
4013
+ if (!block.isError) {
4014
+ seen.set(key, { turnIndex: toolUseIndex });
4015
+ }
4016
+ return block;
4017
+ });
4018
+ return { role: msg.role, content: newContent };
4019
+ });
4020
+ }
4021
+ function stableStringify(value) {
4022
+ if (value === null || value === void 0) return "";
4023
+ if (typeof value !== "object") return JSON.stringify(value);
4024
+ if (Array.isArray(value)) return JSON.stringify(value);
4025
+ const sorted = Object.keys(value).sort();
4026
+ const obj = {};
4027
+ for (const k of sorted) obj[k] = value[k];
4028
+ return JSON.stringify(obj);
4029
+ }
4030
+
3951
4031
  // src/context.ts
3952
4032
  var CHARS_PER_TOKEN = 4;
3953
4033
  var DEFAULT_CONTEXT_LIMIT = 2e5;
@@ -4018,7 +4098,8 @@ async function compactMessages(messages, opts = {}) {
4018
4098
  const systemTokens = opts.systemPromptTokens ?? 500;
4019
4099
  const budget = maxTokens - systemTokens;
4020
4100
  if (messages.length === 0) return [];
4021
- const mutable = messages.map((m) => ({
4101
+ const deduped = microcompact(messages);
4102
+ const mutable = deduped.map((m) => ({
4022
4103
  role: m.role,
4023
4104
  content: m.content.map((b) => ({ ...b }))
4024
4105
  }));
@@ -4132,6 +4213,179 @@ function truncateToolResult(content) {
4132
4213
  }
4133
4214
  }
4134
4215
 
4216
+ // src/permission-rules.ts
4217
+ var DEFAULT_PERMISSION_CONFIG = {
4218
+ globalAutoBelow: 10,
4219
+ autonomousDailyLimit: 200,
4220
+ rules: [
4221
+ { operation: "save", autoBelow: 50, confirmBetween: 1e3 },
4222
+ { operation: "send", autoBelow: 10, confirmBetween: 200 },
4223
+ { operation: "borrow", autoBelow: 0, confirmBetween: 500 },
4224
+ { operation: "withdraw", autoBelow: 25, confirmBetween: 500 },
4225
+ { operation: "swap", autoBelow: 25, confirmBetween: 300 },
4226
+ { operation: "pay", autoBelow: 1, confirmBetween: 50 },
4227
+ { operation: "repay", autoBelow: 50, confirmBetween: 1e3 }
4228
+ ]
4229
+ };
4230
+ var PERMISSION_PRESETS = {
4231
+ conservative: {
4232
+ globalAutoBelow: 5,
4233
+ autonomousDailyLimit: 100,
4234
+ rules: [
4235
+ { operation: "save", autoBelow: 5, confirmBetween: 100 },
4236
+ { operation: "send", autoBelow: 5, confirmBetween: 100 },
4237
+ { operation: "borrow", autoBelow: 0, confirmBetween: 100 },
4238
+ { operation: "withdraw", autoBelow: 5, confirmBetween: 100 },
4239
+ { operation: "swap", autoBelow: 5, confirmBetween: 100 },
4240
+ { operation: "pay", autoBelow: 1, confirmBetween: 25 },
4241
+ { operation: "repay", autoBelow: 5, confirmBetween: 100 }
4242
+ ]
4243
+ },
4244
+ balanced: DEFAULT_PERMISSION_CONFIG,
4245
+ aggressive: {
4246
+ globalAutoBelow: 25,
4247
+ autonomousDailyLimit: 500,
4248
+ rules: [
4249
+ { operation: "save", autoBelow: 100, confirmBetween: 2e3 },
4250
+ { operation: "send", autoBelow: 25, confirmBetween: 500 },
4251
+ { operation: "borrow", autoBelow: 10, confirmBetween: 1e3 },
4252
+ { operation: "withdraw", autoBelow: 50, confirmBetween: 1e3 },
4253
+ { operation: "swap", autoBelow: 50, confirmBetween: 500 },
4254
+ { operation: "pay", autoBelow: 5, confirmBetween: 100 },
4255
+ { operation: "repay", autoBelow: 100, confirmBetween: 2e3 }
4256
+ ]
4257
+ }
4258
+ };
4259
+ function resolvePermissionTier(operation, amountUsd, config) {
4260
+ const rule = config.rules.find((r) => r.operation === operation);
4261
+ const autoBelow = rule?.autoBelow ?? config.globalAutoBelow;
4262
+ const confirmBetween = rule?.confirmBetween ?? 1e3;
4263
+ if (amountUsd < autoBelow) return "auto";
4264
+ if (amountUsd < confirmBetween) return "confirm";
4265
+ return "explicit";
4266
+ }
4267
+ var TOOL_TO_OPERATION = {
4268
+ save_deposit: "save",
4269
+ withdraw: "withdraw",
4270
+ send_transfer: "send",
4271
+ borrow: "borrow",
4272
+ repay_debt: "repay",
4273
+ swap_execute: "swap",
4274
+ pay_api: "pay",
4275
+ volo_stake: "save",
4276
+ volo_unstake: "withdraw"
4277
+ };
4278
+ function toolNameToOperation(toolName) {
4279
+ return TOOL_TO_OPERATION[toolName];
4280
+ }
4281
+ function resolveUsdValue(toolName, input, priceCache) {
4282
+ switch (toolName) {
4283
+ case "save_deposit":
4284
+ case "withdraw":
4285
+ case "repay_debt":
4286
+ case "borrow":
4287
+ return safeNum(input.amount);
4288
+ case "send_transfer": {
4289
+ const amount = safeNum(input.amount);
4290
+ const asset = String(input.asset ?? "USDC").toUpperCase();
4291
+ if (asset === "USDC" || asset === "USDT") return amount;
4292
+ return amount * (priceCache.get(asset) ?? 0);
4293
+ }
4294
+ case "swap_execute": {
4295
+ const amount = safeNum(input.fromAmount);
4296
+ const fromAsset = String(input.fromAsset ?? "").toUpperCase();
4297
+ if (fromAsset === "USDC" || fromAsset === "USDT") return amount;
4298
+ return amount * (priceCache.get(fromAsset) ?? 0);
4299
+ }
4300
+ case "pay_api":
4301
+ return safeNum(input.maxCost ?? input.price);
4302
+ case "volo_stake":
4303
+ case "volo_unstake":
4304
+ return safeNum(input.amount) * (priceCache.get("SUI") ?? 0);
4305
+ default:
4306
+ return 0;
4307
+ }
4308
+ }
4309
+ function safeNum(v) {
4310
+ const n = Number(v);
4311
+ return isNaN(n) ? 0 : n;
4312
+ }
4313
+
4314
+ // src/early-dispatcher.ts
4315
+ var EarlyToolDispatcher = class {
4316
+ entries = [];
4317
+ tools;
4318
+ context;
4319
+ abortController;
4320
+ constructor(tools, context) {
4321
+ this.tools = tools;
4322
+ this.context = context;
4323
+ this.abortController = new AbortController();
4324
+ }
4325
+ /**
4326
+ * Attempt to dispatch a tool call. Returns true if the tool was dispatched
4327
+ * (read-only + concurrency-safe), false if it should be queued for later.
4328
+ */
4329
+ tryDispatch(call) {
4330
+ const tool = findTool(this.tools, call.name);
4331
+ if (!tool || !tool.isReadOnly || !tool.isConcurrencySafe) return false;
4332
+ const childContext = { ...this.context, signal: this.abortController.signal };
4333
+ const promise = executeTool(tool, call, childContext);
4334
+ this.entries.push({ call, tool, promise });
4335
+ return true;
4336
+ }
4337
+ /** True if any tools have been dispatched. */
4338
+ hasPending() {
4339
+ return this.entries.length > 0;
4340
+ }
4341
+ /** List of call IDs that were early-dispatched. */
4342
+ dispatchedIds() {
4343
+ return new Set(this.entries.map((e) => e.call.id));
4344
+ }
4345
+ /**
4346
+ * Collect all results in original dispatch order.
4347
+ * Yields `tool_result` events as each promise resolves.
4348
+ */
4349
+ async *collectResults() {
4350
+ for (const entry of this.entries) {
4351
+ try {
4352
+ const result = await entry.promise;
4353
+ const budgeted = result.isError ? result.data : budgetToolResult(result.data, entry.tool);
4354
+ yield {
4355
+ type: "tool_result",
4356
+ toolName: entry.call.name,
4357
+ toolUseId: entry.call.id,
4358
+ result: budgeted,
4359
+ isError: result.isError
4360
+ };
4361
+ } catch (err) {
4362
+ yield {
4363
+ type: "tool_result",
4364
+ toolName: entry.call.name,
4365
+ toolUseId: entry.call.id,
4366
+ result: { error: err instanceof Error ? err.message : "Tool execution failed" },
4367
+ isError: true
4368
+ };
4369
+ }
4370
+ }
4371
+ }
4372
+ /** Cancel all in-flight tool calls. */
4373
+ abort() {
4374
+ this.abortController.abort();
4375
+ }
4376
+ };
4377
+ async function executeTool(tool, call, context) {
4378
+ const parsed = tool.inputSchema.safeParse(call.input);
4379
+ if (!parsed.success) {
4380
+ return {
4381
+ data: { error: `Invalid input: ${parsed.error.issues.map((i) => i.message).join(", ")}` },
4382
+ isError: true
4383
+ };
4384
+ }
4385
+ const result = await tool.call(parsed.data, context);
4386
+ return { data: result.data, isError: false };
4387
+ }
4388
+
4135
4389
  // src/engine.ts
4136
4390
  var DEFAULT_MAX_TURNS = 10;
4137
4391
  var DEFAULT_MAX_TOKENS = 4096;
@@ -4160,6 +4414,8 @@ var QueryEngine = class {
4160
4414
  recipes;
4161
4415
  contextBudget;
4162
4416
  contextSummarizer;
4417
+ priceCache;
4418
+ permissionConfig;
4163
4419
  matchedRecipe = null;
4164
4420
  messages = [];
4165
4421
  abortController = null;
@@ -4187,6 +4443,8 @@ var QueryEngine = class {
4187
4443
  this.recipes = config.recipes;
4188
4444
  this.contextBudget = new ContextBudget(config.contextBudget);
4189
4445
  this.contextSummarizer = config.contextSummarizer;
4446
+ this.priceCache = config.priceCache;
4447
+ this.permissionConfig = config.permissionConfig;
4190
4448
  this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
4191
4449
  }
4192
4450
  /**
@@ -4306,7 +4564,9 @@ var QueryEngine = class {
4306
4564
  serverPositions: this.serverPositions,
4307
4565
  positionFetcher: this.positionFetcher,
4308
4566
  env: this.env,
4309
- signal
4567
+ signal,
4568
+ priceCache: this.priceCache,
4569
+ permissionConfig: this.permissionConfig
4310
4570
  };
4311
4571
  let turns = 0;
4312
4572
  let hasRetriedWithCleanHistory = false;
@@ -4323,7 +4583,9 @@ var QueryEngine = class {
4323
4583
  assistantBlocks: [],
4324
4584
  pendingToolCalls: []
4325
4585
  };
4586
+ const dispatcher = new EarlyToolDispatcher(this.tools, context);
4326
4587
  try {
4588
+ this.messages = microcompact(this.messages);
4327
4589
  if (this.contextBudget.shouldCompact()) {
4328
4590
  this.messages = await compactMessages(this.messages, {
4329
4591
  maxTokens: 1e5,
@@ -4375,7 +4637,7 @@ ${recipeCtx}`;
4375
4637
  signal
4376
4638
  });
4377
4639
  for await (const event of stream) {
4378
- yield* this.handleProviderEvent(event, acc);
4640
+ yield* this.handleProviderEvent(event, acc, dispatcher);
4379
4641
  }
4380
4642
  } catch (err) {
4381
4643
  if (freshPrompt && !hasRetriedWithCleanHistory && isCorruptHistoryError(err)) {
@@ -4392,23 +4654,74 @@ ${recipeCtx}`;
4392
4654
  if (acc.text) {
4393
4655
  acc.assistantBlocks.push({ type: "text", text: acc.text });
4394
4656
  }
4395
- if (acc.pendingToolCalls.length === 0) {
4657
+ const earlyResultBlocks = [];
4658
+ if (dispatcher.hasPending()) {
4659
+ if (signal.aborted) {
4660
+ dispatcher.abort();
4661
+ }
4662
+ for await (const earlyEvent of dispatcher.collectResults()) {
4663
+ if (earlyEvent.type === "tool_result") {
4664
+ if (!earlyEvent.isError) {
4665
+ const warning = flagSuspiciousResult(earlyEvent.toolName, earlyEvent.result);
4666
+ if (warning) {
4667
+ const flagged = {
4668
+ ...earlyEvent,
4669
+ result: typeof earlyEvent.result === "object" && earlyEvent.result ? { ...earlyEvent.result, _warning: warning } : { data: earlyEvent.result, _warning: warning }
4670
+ };
4671
+ yield flagged;
4672
+ earlyResultBlocks.push({
4673
+ type: "tool_result",
4674
+ toolUseId: flagged.toolUseId,
4675
+ content: JSON.stringify(flagged.result),
4676
+ isError: flagged.isError
4677
+ });
4678
+ continue;
4679
+ }
4680
+ }
4681
+ yield earlyEvent;
4682
+ earlyResultBlocks.push({
4683
+ type: "tool_result",
4684
+ toolUseId: earlyEvent.toolUseId,
4685
+ content: JSON.stringify(earlyEvent.result),
4686
+ isError: earlyEvent.isError
4687
+ });
4688
+ }
4689
+ }
4690
+ }
4691
+ const hasEarlyResults = earlyResultBlocks.length > 0;
4692
+ const hasRemainingCalls = acc.pendingToolCalls.length > 0;
4693
+ if (!hasEarlyResults && !hasRemainingCalls) {
4396
4694
  this.messages.push({ role: "assistant", content: acc.assistantBlocks });
4397
4695
  yield { type: "turn_complete", stopReason: acc.stopReason };
4398
4696
  return;
4399
4697
  }
4400
4698
  if (signal.aborted) {
4401
4699
  this.messages.push({ role: "assistant", content: acc.assistantBlocks });
4700
+ if (hasEarlyResults) {
4701
+ this.messages.push({ role: "user", content: earlyResultBlocks });
4702
+ }
4402
4703
  this.addErrorResults(acc.pendingToolCalls, "Aborted");
4403
4704
  yield { type: "error", error: new Error("Aborted") };
4404
4705
  return;
4405
4706
  }
4406
4707
  const approved = [];
4407
- const toolResultBlocks = [];
4708
+ const toolResultBlocks = [...earlyResultBlocks];
4408
4709
  let pendingWrite = null;
4409
4710
  for (const call of acc.pendingToolCalls) {
4410
4711
  const tool = findTool(this.tools, call.name);
4411
- const needsConfirmation = tool && !tool.isReadOnly && tool.permissionLevel !== "auto";
4712
+ const needsConfirmation = (() => {
4713
+ if (!tool || tool.isReadOnly) return false;
4714
+ if (tool.permissionLevel === "explicit") return true;
4715
+ if (context.permissionConfig && context.priceCache) {
4716
+ const operation = toolNameToOperation(call.name);
4717
+ if (operation) {
4718
+ const usdValue = resolveUsdValue(call.name, call.input, context.priceCache);
4719
+ const tier = resolvePermissionTier(operation, usdValue, context.permissionConfig);
4720
+ return tier !== "auto";
4721
+ }
4722
+ }
4723
+ return tool.permissionLevel !== "auto";
4724
+ })();
4412
4725
  if (!needsConfirmation) {
4413
4726
  approved.push(call);
4414
4727
  yield { type: "tool_start", toolName: call.name, toolUseId: call.id, input: call.input };
@@ -4594,7 +4907,7 @@ ${recipeCtx}`;
4594
4907
  this.messages.push({ role: "user", content: errorBlocks });
4595
4908
  }
4596
4909
  }
4597
- *handleProviderEvent(event, acc) {
4910
+ *handleProviderEvent(event, acc, dispatcher) {
4598
4911
  switch (event.type) {
4599
4912
  case "thinking_delta": {
4600
4913
  yield { type: "thinking_delta", text: event.text };
@@ -4632,11 +4945,12 @@ ${recipeCtx}`;
4632
4945
  name: event.name,
4633
4946
  input: event.input
4634
4947
  });
4635
- acc.pendingToolCalls.push({
4636
- id: event.id,
4637
- name: event.name,
4638
- input: event.input
4639
- });
4948
+ const call = { id: event.id, name: event.name, input: event.input };
4949
+ if (dispatcher?.tryDispatch(call)) {
4950
+ yield { type: "tool_start", toolName: call.name, toolUseId: call.id, input: call.input };
4951
+ } else {
4952
+ acc.pendingToolCalls.push(call);
4953
+ }
4640
4954
  break;
4641
4955
  }
4642
4956
  case "usage": {
@@ -5732,6 +6046,6 @@ function sanitizeAnthropicMessages(messages) {
5732
6046
  return merged;
5733
6047
  }
5734
6048
 
5735
- export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_SYSTEM_PROMPT, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, balanceCheckTool, borrowTool, 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, mppServicesTool, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
6049
+ 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 };
5736
6050
  //# sourceMappingURL=index.js.map
5737
6051
  //# sourceMappingURL=index.js.map