@t2000/engine 0.31.3 → 0.32.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
@@ -7,15 +7,18 @@ import Anthropic from '@anthropic-ai/sdk';
7
7
 
8
8
  // src/tool.ts
9
9
  function buildTool(opts) {
10
+ const isReadOnly = opts.isReadOnly ?? true;
10
11
  return {
11
12
  name: opts.name,
12
13
  description: opts.description,
13
14
  inputSchema: opts.inputSchema,
14
15
  jsonSchema: opts.jsonSchema,
15
16
  call: opts.call,
16
- isReadOnly: opts.isReadOnly ?? true,
17
- isConcurrencySafe: opts.isReadOnly ?? true,
18
- permissionLevel: opts.permissionLevel ?? (opts.isReadOnly === false ? "confirm" : "auto")
17
+ isReadOnly,
18
+ isConcurrencySafe: isReadOnly,
19
+ permissionLevel: opts.permissionLevel ?? (isReadOnly ? "auto" : "confirm"),
20
+ flags: opts.flags ?? {},
21
+ preflight: opts.preflight
19
22
  };
20
23
  }
21
24
  function toolsToDefinitions(tools) {
@@ -152,6 +155,45 @@ async function executeSingleTool(tool, call, context) {
152
155
  const result = await tool.call(parsed.data, context);
153
156
  return { data: result.data, isError: false };
154
157
  }
158
+
159
+ // src/tool-flags.ts
160
+ var TOOL_FLAGS = {
161
+ // Write tools — financial
162
+ save_deposit: { mutating: true, requiresBalance: true },
163
+ withdraw: { mutating: true, affectsHealth: true },
164
+ send_transfer: { mutating: true, requiresBalance: true, irreversible: true },
165
+ swap_execute: { mutating: true, requiresBalance: true },
166
+ borrow: { mutating: true, affectsHealth: true },
167
+ repay_debt: { mutating: true, requiresBalance: true },
168
+ claim_rewards: { mutating: true },
169
+ volo_stake: { mutating: true, requiresBalance: true },
170
+ volo_unstake: { mutating: true },
171
+ // Write tools — pay / services
172
+ pay_api: { mutating: true, requiresBalance: true, costAware: true, producesArtifact: true, maxRetries: 1 },
173
+ // Write tools — lightweight (no financial guards)
174
+ save_contact: {},
175
+ create_schedule: { mutating: true },
176
+ cancel_schedule: { mutating: true },
177
+ // Allowance tools — API mutations disguised as reads
178
+ toggle_allowance: { mutating: true },
179
+ update_daily_limit: { mutating: true },
180
+ update_permissions: { mutating: true },
181
+ // Receive tools — create/cancel mutate server state
182
+ create_payment_link: { mutating: true },
183
+ cancel_payment_link: { mutating: true },
184
+ create_invoice: { mutating: true },
185
+ cancel_invoice: { mutating: true }
186
+ };
187
+ function applyToolFlags(tools) {
188
+ return tools.map((tool) => {
189
+ const flags = TOOL_FLAGS[tool.name];
190
+ if (!flags) return tool;
191
+ return { ...tool, flags: { ...tool.flags, ...flags } };
192
+ });
193
+ }
194
+ function getToolFlags(name) {
195
+ return TOOL_FLAGS[name] ?? {};
196
+ }
155
197
  var SUI_MAINNET_URL = "https://fullnode.mainnet.sui.io:443";
156
198
  var EXTRA_COINS = {
157
199
  "0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN": { symbol: "USDT", decimals: 6 }
@@ -1119,6 +1161,13 @@ var saveDepositTool = buildTool({
1119
1161
  },
1120
1162
  isReadOnly: false,
1121
1163
  permissionLevel: "confirm",
1164
+ flags: { mutating: true, requiresBalance: true },
1165
+ preflight: (input) => {
1166
+ if (input.asset && input.asset.toUpperCase() !== "USDC") {
1167
+ return { valid: false, error: `Only USDC deposits are supported. Got: "${input.asset}"` };
1168
+ }
1169
+ return { valid: true };
1170
+ },
1122
1171
  async call(input, context) {
1123
1172
  assertAllowedAsset("save", input.asset);
1124
1173
  const agent = requireAgent(context);
@@ -1160,6 +1209,7 @@ var withdrawTool = buildTool({
1160
1209
  },
1161
1210
  isReadOnly: false,
1162
1211
  permissionLevel: "confirm",
1212
+ flags: { mutating: true, affectsHealth: true },
1163
1213
  async call(input, context) {
1164
1214
  const agent = requireAgent(context);
1165
1215
  const result = await agent.withdraw({
@@ -1207,6 +1257,16 @@ var sendTransferTool = buildTool({
1207
1257
  },
1208
1258
  isReadOnly: false,
1209
1259
  permissionLevel: "confirm",
1260
+ flags: { mutating: true, requiresBalance: true, irreversible: true },
1261
+ preflight: (input) => {
1262
+ if (input.to.startsWith("0x") && !/^0x[a-fA-F0-9]{64}$/.test(input.to)) {
1263
+ return { valid: false, error: `Invalid Sui address format: "${input.to}". Must be 0x followed by 64 hex characters.` };
1264
+ }
1265
+ if (input.amount <= 0) {
1266
+ return { valid: false, error: "Amount must be positive." };
1267
+ }
1268
+ return { valid: true };
1269
+ },
1210
1270
  async call(input, context) {
1211
1271
  const agent = requireAgent(context);
1212
1272
  const result = await agent.send({ to: input.to, amount: input.amount });
@@ -1249,6 +1309,13 @@ var borrowTool = buildTool({
1249
1309
  },
1250
1310
  isReadOnly: false,
1251
1311
  permissionLevel: "confirm",
1312
+ flags: { mutating: true, affectsHealth: true },
1313
+ preflight: (input) => {
1314
+ if (input.asset && input.asset.toUpperCase() !== "USDC") {
1315
+ return { valid: false, error: `Only USDC borrows are supported. Got: "${input.asset}"` };
1316
+ }
1317
+ return { valid: true };
1318
+ },
1252
1319
  async call(input, context) {
1253
1320
  assertAllowedAsset("borrow", input.asset);
1254
1321
  const agent = requireAgent(context);
@@ -1283,6 +1350,7 @@ var repayDebtTool = buildTool({
1283
1350
  },
1284
1351
  isReadOnly: false,
1285
1352
  permissionLevel: "confirm",
1353
+ flags: { mutating: true, requiresBalance: true },
1286
1354
  async call(input, context) {
1287
1355
  const agent = requireAgent(context);
1288
1356
  const result = await agent.repay({ amount: input.amount });
@@ -1305,6 +1373,7 @@ var claimRewardsTool = buildTool({
1305
1373
  jsonSchema: { type: "object", properties: {}, required: [] },
1306
1374
  isReadOnly: false,
1307
1375
  permissionLevel: "confirm",
1376
+ flags: { mutating: true },
1308
1377
  async call(_input, context) {
1309
1378
  const agent = requireAgent(context);
1310
1379
  const result = await agent.claimRewards();
@@ -1379,6 +1448,28 @@ Always use ISO-3166 country codes (GB not UK, US not USA). A return address ("fr
1379
1448
  },
1380
1449
  isReadOnly: false,
1381
1450
  permissionLevel: "confirm",
1451
+ flags: { mutating: true, requiresBalance: true, costAware: true, producesArtifact: true, maxRetries: 1 },
1452
+ preflight: (input) => {
1453
+ if (!input.url.startsWith(MPP_GATEWAY)) {
1454
+ return { valid: false, error: `URL must start with ${MPP_GATEWAY}. Got: "${input.url}"` };
1455
+ }
1456
+ if (input.body) {
1457
+ try {
1458
+ JSON.parse(input.body);
1459
+ } catch {
1460
+ return { valid: false, error: "body must be valid JSON." };
1461
+ }
1462
+ if (input.url.includes("lob/")) {
1463
+ const body = JSON.parse(input.body);
1464
+ const to = body.to;
1465
+ const country = to?.address_country;
1466
+ if (typeof country === "string" && country.length !== 2) {
1467
+ return { valid: false, error: `Country must be ISO-3166 2-letter code (got "${country}")` };
1468
+ }
1469
+ }
1470
+ }
1471
+ return { valid: true };
1472
+ },
1382
1473
  async call(input, context) {
1383
1474
  const agent = requireAgent(context);
1384
1475
  const result = await agent.pay({
@@ -1480,6 +1571,13 @@ var swapExecuteTool = buildTool({
1480
1571
  },
1481
1572
  isReadOnly: false,
1482
1573
  permissionLevel: "confirm",
1574
+ flags: { mutating: true, requiresBalance: true },
1575
+ preflight: (input) => {
1576
+ if (input.from.toLowerCase() === input.to.toLowerCase()) {
1577
+ return { valid: false, error: `Cannot swap ${input.from} to itself.` };
1578
+ }
1579
+ return { valid: true };
1580
+ },
1483
1581
  async call(input, context) {
1484
1582
  const agent = requireAgent(context);
1485
1583
  const result = await agent.swap({
@@ -1554,6 +1652,7 @@ var voloStakeTool = buildTool({
1554
1652
  },
1555
1653
  isReadOnly: false,
1556
1654
  permissionLevel: "confirm",
1655
+ flags: { mutating: true, requiresBalance: true },
1557
1656
  async call(input, context) {
1558
1657
  const agent = requireAgent(context);
1559
1658
  const result = await agent.stakeVSui({ amount: input.amount });
@@ -1584,6 +1683,7 @@ var voloUnstakeTool = buildTool({
1584
1683
  },
1585
1684
  isReadOnly: false,
1586
1685
  permissionLevel: "confirm",
1686
+ flags: { mutating: true },
1587
1687
  async call(input, context) {
1588
1688
  const agent = requireAgent(context);
1589
1689
  const result = await agent.unstakeVSui({ amount: input.amount });
@@ -3416,7 +3516,7 @@ var WRITE_TOOLS = [
3416
3516
  cancelScheduleTool
3417
3517
  ];
3418
3518
  function getDefaultTools() {
3419
- return [...READ_TOOLS, ...WRITE_TOOLS];
3519
+ return applyToolFlags([...READ_TOOLS, ...WRITE_TOOLS]);
3420
3520
  }
3421
3521
 
3422
3522
  // src/prompt.ts
@@ -3517,6 +3617,330 @@ var CostTracker = class {
3517
3617
  }
3518
3618
  };
3519
3619
 
3620
+ // src/guards.ts
3621
+ var DEFAULT_GUARD_CONFIG = {
3622
+ balanceValidation: true,
3623
+ healthFactor: { warnBelow: 2, blockBelow: 1.5 },
3624
+ largeTransfer: { warnAbove: 50, strongWarnAbove: 500 },
3625
+ slippage: true,
3626
+ staleData: true,
3627
+ irreversibility: true,
3628
+ artifactPreview: true,
3629
+ costWarning: true,
3630
+ retryProtection: true,
3631
+ inputValidation: true
3632
+ };
3633
+ var BalanceTracker = class {
3634
+ lastBalanceAt = 0;
3635
+ lastWriteAt = 0;
3636
+ recordRead() {
3637
+ this.lastBalanceAt = Date.now();
3638
+ }
3639
+ recordWrite() {
3640
+ this.lastWriteAt = Date.now();
3641
+ }
3642
+ isStale() {
3643
+ return this.lastWriteAt > this.lastBalanceAt;
3644
+ }
3645
+ hasEverRead() {
3646
+ return this.lastBalanceAt > 0;
3647
+ }
3648
+ };
3649
+ var BALANCE_READ_TOOLS = /* @__PURE__ */ new Set([
3650
+ "balance_check",
3651
+ "savings_info",
3652
+ "health_check"
3653
+ ]);
3654
+ var RetryTracker = class {
3655
+ executed = /* @__PURE__ */ new Map();
3656
+ key(toolName, input) {
3657
+ const url = input?.url ?? "";
3658
+ return `${toolName}:${url}`;
3659
+ }
3660
+ record(toolName, input, result) {
3661
+ const r = result;
3662
+ if (r?.paymentConfirmed || r?.doNotRetry) {
3663
+ this.executed.set(this.key(toolName, input), { result, paidAt: Date.now() });
3664
+ }
3665
+ }
3666
+ isBlocked(toolName, input) {
3667
+ const prev = this.executed.get(this.key(toolName, input));
3668
+ if (!prev) return { blocked: false };
3669
+ return { blocked: true, previousResult: prev.result };
3670
+ }
3671
+ };
3672
+ function guardRetryProtection(tool, call, retryTracker) {
3673
+ const check = retryTracker.isBlocked(tool.name, call.input);
3674
+ if (check.blocked) {
3675
+ return {
3676
+ verdict: "block",
3677
+ gate: "retry_blocked",
3678
+ tier: "safety",
3679
+ message: `Blocked: ${tool.name} was already called and payment was confirmed. Do not retry.`
3680
+ };
3681
+ }
3682
+ return { verdict: "pass", gate: "retry_blocked", tier: "safety" };
3683
+ }
3684
+ function guardIrreversibility(tool, _call, conversationText) {
3685
+ if (!tool.flags.irreversible) {
3686
+ return { verdict: "pass", gate: "irreversibility", tier: "safety" };
3687
+ }
3688
+ const hasPreview = /preview|here.s what|confirm.*send|looks? good/i.test(conversationText);
3689
+ if (hasPreview) {
3690
+ return { verdict: "pass", gate: "irreversibility", tier: "safety" };
3691
+ }
3692
+ return {
3693
+ verdict: "hint",
3694
+ gate: "irreversibility",
3695
+ tier: "safety",
3696
+ message: "This action is irreversible. Show a preview and ask the user to confirm before proceeding."
3697
+ };
3698
+ }
3699
+ function guardBalanceValidation(tool, _call, balanceTracker) {
3700
+ if (!tool.flags.requiresBalance) {
3701
+ return { verdict: "pass", gate: "balance_required", tier: "financial" };
3702
+ }
3703
+ if (!balanceTracker.hasEverRead()) {
3704
+ return {
3705
+ verdict: "hint",
3706
+ gate: "balance_required",
3707
+ tier: "financial",
3708
+ message: "Balance has not been checked this session. Call balance_check first to verify sufficient funds."
3709
+ };
3710
+ }
3711
+ if (balanceTracker.isStale()) {
3712
+ return {
3713
+ verdict: "hint",
3714
+ gate: "balance_required",
3715
+ tier: "financial",
3716
+ message: "Balance data is stale (a write action occurred since last check). Call balance_check first to verify sufficient funds."
3717
+ };
3718
+ }
3719
+ return { verdict: "pass", gate: "balance_required", tier: "financial" };
3720
+ }
3721
+ function guardHealthFactor(tool, _call, lastHealthFactor, config) {
3722
+ if (!tool.flags.affectsHealth) {
3723
+ return { verdict: "pass", gate: "health_factor", tier: "financial" };
3724
+ }
3725
+ if (lastHealthFactor === null) {
3726
+ return {
3727
+ verdict: "hint",
3728
+ gate: "health_factor",
3729
+ tier: "financial",
3730
+ message: "Health factor has not been checked this session. Call health_check before this action."
3731
+ };
3732
+ }
3733
+ if (lastHealthFactor < config.blockBelow) {
3734
+ return {
3735
+ verdict: "block",
3736
+ gate: "health_factor",
3737
+ tier: "financial",
3738
+ message: `Health factor is ${lastHealthFactor.toFixed(2)} \u2014 this action risks liquidation. Refusing.`
3739
+ };
3740
+ }
3741
+ if (lastHealthFactor < config.warnBelow) {
3742
+ return {
3743
+ verdict: "warn",
3744
+ gate: "health_factor",
3745
+ tier: "financial",
3746
+ message: `Health factor is ${lastHealthFactor.toFixed(2)} \u2014 this action may reduce it further.`
3747
+ };
3748
+ }
3749
+ return { verdict: "pass", gate: "health_factor", tier: "financial" };
3750
+ }
3751
+ function guardLargeTransfer(tool, call, config) {
3752
+ if (tool.name !== "send_transfer") {
3753
+ return { verdict: "pass", gate: "large_transfer", tier: "financial" };
3754
+ }
3755
+ const input = call.input;
3756
+ const amount = Number(input.amount ?? 0);
3757
+ if (!amount || amount <= 0) {
3758
+ return { verdict: "pass", gate: "large_transfer", tier: "financial" };
3759
+ }
3760
+ const recipient = String(input.recipient ?? input.to ?? "");
3761
+ const shortAddr = recipient.length > 10 ? `${recipient.slice(0, 6)}...${recipient.slice(-4)}` : recipient;
3762
+ if (amount > config.strongWarnAbove) {
3763
+ return {
3764
+ verdict: "warn",
3765
+ gate: "large_transfer",
3766
+ tier: "financial",
3767
+ message: `High-value transfer ($${amount}). Double-check the address: ${shortAddr}`
3768
+ };
3769
+ }
3770
+ if (amount > config.warnAbove) {
3771
+ return {
3772
+ verdict: "hint",
3773
+ gate: "large_transfer",
3774
+ tier: "financial",
3775
+ message: `This is a large transfer ($${amount}). Verify the recipient address.`
3776
+ };
3777
+ }
3778
+ return { verdict: "pass", gate: "large_transfer", tier: "financial" };
3779
+ }
3780
+ function guardSlippage(tool, _call, lastAssistantText) {
3781
+ if (tool.name !== "swap_execute") {
3782
+ return { verdict: "pass", gate: "slippage_warning", tier: "financial" };
3783
+ }
3784
+ const hasEstimate = /~?\$?[\d,]+\.?\d*\s*(SUI|USDC|USDT|WETH)/i.test(lastAssistantText) || /approximately|≈|about|expect|receive/i.test(lastAssistantText);
3785
+ if (hasEstimate) {
3786
+ return { verdict: "pass", gate: "slippage_warning", tier: "financial" };
3787
+ }
3788
+ return {
3789
+ verdict: "hint",
3790
+ gate: "slippage_warning",
3791
+ tier: "financial",
3792
+ message: "State the expected output amount to the user before executing the swap."
3793
+ };
3794
+ }
3795
+ function guardCostWarning(tool, _call, conversationText) {
3796
+ if (!tool.flags.costAware) {
3797
+ return { verdict: "pass", gate: "cost_warning", tier: "ux" };
3798
+ }
3799
+ const hasCostMention = /\$\d+\.?\d*|cost|fee|charge|price|pay/i.test(conversationText);
3800
+ if (hasCostMention) {
3801
+ return { verdict: "pass", gate: "cost_warning", tier: "ux" };
3802
+ }
3803
+ return {
3804
+ verdict: "hint",
3805
+ gate: "cost_warning",
3806
+ tier: "ux",
3807
+ message: "This action has a monetary cost. Confirm the user is aware before proceeding."
3808
+ };
3809
+ }
3810
+ function guardArtifactPreview(result) {
3811
+ if (!result || typeof result !== "object") return null;
3812
+ const r = result;
3813
+ const hasImage = typeof r.url === "string" && /\.(png|jpg|jpeg|webp|gif|svg)(\?|$)/i.test(r.url) || Array.isArray(r.images) && r.images.length > 0 || typeof r.image_url === "string";
3814
+ const hasPdf = typeof r.url === "string" && /\.pdf(\?|$)/i.test(r.url);
3815
+ if (hasImage || hasPdf) {
3816
+ return {
3817
+ _gate: "artifact_preview",
3818
+ _hint: "Show this to the user before proceeding. Output as ![description](url)."
3819
+ };
3820
+ }
3821
+ return null;
3822
+ }
3823
+ function guardStaleData(toolFlags) {
3824
+ if (!toolFlags.mutating) return null;
3825
+ return {
3826
+ _gate: "stale_data",
3827
+ _hint: "A write action just completed. The balance snapshot is outdated. Do NOT calculate new balances from old data \u2014 call balance_check for fresh numbers, or use only the data returned by the write tool."
3828
+ };
3829
+ }
3830
+ function createGuardRunnerState() {
3831
+ return {
3832
+ balanceTracker: new BalanceTracker(),
3833
+ retryTracker: new RetryTracker(),
3834
+ lastHealthFactor: null
3835
+ };
3836
+ }
3837
+ function runGuards(tool, call, state, config, conversationContext) {
3838
+ const results = [];
3839
+ const now = Date.now();
3840
+ if (config.inputValidation !== false && tool.preflight) {
3841
+ const check = tool.preflight(call.input);
3842
+ if (!check.valid) {
3843
+ const event = {
3844
+ timestamp: now,
3845
+ toolName: tool.name,
3846
+ toolUseId: call.id,
3847
+ gate: "input_validation",
3848
+ verdict: "block",
3849
+ tier: "safety",
3850
+ message: check.error
3851
+ };
3852
+ return {
3853
+ blocked: true,
3854
+ blockReason: check.error,
3855
+ blockGate: "input_validation",
3856
+ injections: [],
3857
+ events: [event]
3858
+ };
3859
+ }
3860
+ }
3861
+ if (config.retryProtection !== false) {
3862
+ results.push(guardRetryProtection(tool, call, state.retryTracker));
3863
+ }
3864
+ if (config.irreversibility !== false) {
3865
+ results.push(guardIrreversibility(tool, call, conversationContext.fullText));
3866
+ }
3867
+ if (config.balanceValidation !== false) {
3868
+ results.push(guardBalanceValidation(tool, call, state.balanceTracker));
3869
+ }
3870
+ if (config.healthFactor) {
3871
+ results.push(guardHealthFactor(tool, call, state.lastHealthFactor, config.healthFactor));
3872
+ }
3873
+ if (config.largeTransfer) {
3874
+ results.push(guardLargeTransfer(tool, call, config.largeTransfer));
3875
+ }
3876
+ if (config.slippage !== false) {
3877
+ results.push(guardSlippage(tool, call, conversationContext.lastAssistantText));
3878
+ }
3879
+ if (config.costWarning !== false) {
3880
+ results.push(guardCostWarning(tool, call, conversationContext.fullText));
3881
+ }
3882
+ const events = results.filter((r) => r.verdict !== "pass").map((r) => ({
3883
+ timestamp: now,
3884
+ toolName: tool.name,
3885
+ toolUseId: call.id,
3886
+ gate: r.gate,
3887
+ verdict: r.verdict,
3888
+ tier: r.tier,
3889
+ message: r.message
3890
+ }));
3891
+ const block = results.find((r) => r.verdict === "block");
3892
+ if (block) {
3893
+ return {
3894
+ blocked: true,
3895
+ blockReason: block.message ?? `Blocked by ${block.gate}`,
3896
+ blockGate: block.gate,
3897
+ injections: [],
3898
+ events
3899
+ };
3900
+ }
3901
+ const injections = results.filter((r) => r.verdict === "hint" || r.verdict === "warn").map((r) => ({
3902
+ _gate: r.gate,
3903
+ ...r.verdict === "hint" ? { _hint: r.message } : { _warning: r.message }
3904
+ }));
3905
+ return { blocked: false, injections, events };
3906
+ }
3907
+ function updateGuardStateAfterToolResult(toolName, tool, input, result, isError, state) {
3908
+ if (isError) return;
3909
+ if (BALANCE_READ_TOOLS.has(toolName)) {
3910
+ state.balanceTracker.recordRead();
3911
+ }
3912
+ if (tool?.flags.mutating) {
3913
+ state.balanceTracker.recordWrite();
3914
+ }
3915
+ if (toolName === "health_check" && result && typeof result === "object") {
3916
+ const r = result;
3917
+ const hf = Number(r.healthFactor ?? r.health_factor ?? r.hf);
3918
+ if (!isNaN(hf) && hf > 0) {
3919
+ state.lastHealthFactor = hf;
3920
+ }
3921
+ }
3922
+ state.retryTracker.record(toolName, input, result);
3923
+ }
3924
+ function extractConversationText(messages) {
3925
+ const textParts = [];
3926
+ let lastAssistantText = "";
3927
+ for (const msg of messages) {
3928
+ if (!Array.isArray(msg.content)) continue;
3929
+ for (const block of msg.content) {
3930
+ if (block.type === "text" && typeof block.text === "string") {
3931
+ textParts.push(block.text);
3932
+ if (msg.role === "assistant") {
3933
+ lastAssistantText = block.text;
3934
+ }
3935
+ }
3936
+ }
3937
+ }
3938
+ return {
3939
+ fullText: textParts.join("\n"),
3940
+ lastAssistantText
3941
+ };
3942
+ }
3943
+
3520
3944
  // src/engine.ts
3521
3945
  var DEFAULT_MAX_TURNS = 10;
3522
3946
  var DEFAULT_MAX_TOKENS = 4096;
@@ -3529,6 +3953,8 @@ var QueryEngine = class {
3529
3953
  maxTokens;
3530
3954
  temperature;
3531
3955
  toolChoice;
3956
+ thinking;
3957
+ outputConfig;
3532
3958
  agent;
3533
3959
  mcpManager;
3534
3960
  walletAddress;
@@ -3538,8 +3964,11 @@ var QueryEngine = class {
3538
3964
  env;
3539
3965
  txMutex = new TxMutex();
3540
3966
  costTracker;
3967
+ guardConfig;
3968
+ guardState;
3541
3969
  messages = [];
3542
3970
  abortController = null;
3971
+ guardEvents = [];
3543
3972
  constructor(config) {
3544
3973
  this.provider = config.provider;
3545
3974
  this.agent = config.agent;
@@ -3554,8 +3983,12 @@ var QueryEngine = class {
3554
3983
  this.maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;
3555
3984
  this.temperature = config.temperature;
3556
3985
  this.toolChoice = config.toolChoice;
3986
+ this.thinking = config.thinking;
3987
+ this.outputConfig = config.outputConfig;
3557
3988
  this.systemPrompt = config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
3558
3989
  this.costTracker = new CostTracker(config.costTracker);
3990
+ this.guardConfig = config.guards;
3991
+ this.guardState = createGuardRunnerState();
3559
3992
  this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
3560
3993
  }
3561
3994
  /**
@@ -3634,6 +4067,10 @@ var QueryEngine = class {
3634
4067
  reset() {
3635
4068
  this.messages = [];
3636
4069
  this.costTracker.reset();
4070
+ this.guardEvents = [];
4071
+ }
4072
+ getGuardEvents() {
4073
+ return this.guardEvents;
3637
4074
  }
3638
4075
  loadMessages(messages) {
3639
4076
  this.messages = [...messages];
@@ -3685,6 +4122,8 @@ var QueryEngine = class {
3685
4122
  const summary = this.messages.map((m, idx) => {
3686
4123
  const blocks = m.content.map((b) => {
3687
4124
  if (b.type === "text") return `text(${b.text.slice(0, 40)}\u2026)`;
4125
+ if (b.type === "thinking") return `thinking(${b.thinking.length}ch)`;
4126
+ if (b.type === "redacted_thinking") return `redacted_thinking`;
3688
4127
  if (b.type === "tool_use") return `tool_use:${b.id.slice(-8)}/${b.name}`;
3689
4128
  return `tool_result:${b.toolUseId.slice(-8)}`;
3690
4129
  });
@@ -3693,6 +4132,8 @@ var QueryEngine = class {
3693
4132
  console.log(`[engine] provider.chat turn=${turns} msgs=${this.messages.length}
3694
4133
  ${summary.join("\n")}`);
3695
4134
  }
4135
+ const thinkingEnabled = this.thinking && this.thinking.type !== "disabled";
4136
+ const effectiveToolChoice = thinkingEnabled ? applyToolChoice && turns === 1 ? "auto" : void 0 : applyToolChoice && turns === 1 ? this.toolChoice : void 0;
3696
4137
  const stream = this.provider.chat({
3697
4138
  messages: this.messages,
3698
4139
  systemPrompt: this.systemPrompt,
@@ -3700,7 +4141,9 @@ ${summary.join("\n")}`);
3700
4141
  model: this.model,
3701
4142
  maxTokens: this.maxTokens,
3702
4143
  temperature: this.temperature,
3703
- toolChoice: applyToolChoice && turns === 1 ? this.toolChoice : void 0,
4144
+ toolChoice: effectiveToolChoice,
4145
+ thinking: this.thinking,
4146
+ outputConfig: this.outputConfig,
3704
4147
  signal
3705
4148
  });
3706
4149
  for await (const event of stream) {
@@ -3746,7 +4189,42 @@ ${summary.join("\n")}`);
3746
4189
  pendingWrite = { call, tool };
3747
4190
  break;
3748
4191
  }
3749
- for await (const toolEvent of runTools(approved, this.tools, context, this.txMutex)) {
4192
+ const guardedApproved = [];
4193
+ if (this.guardConfig) {
4194
+ const convCtx = extractConversationText(this.messages);
4195
+ for (const call of approved) {
4196
+ const tool = findTool(this.tools, call.name);
4197
+ if (!tool) {
4198
+ guardedApproved.push(call);
4199
+ continue;
4200
+ }
4201
+ const check = runGuards(tool, call, this.guardState, this.guardConfig, convCtx);
4202
+ this.guardEvents.push(...check.events);
4203
+ if (check.blocked) {
4204
+ yield {
4205
+ type: "tool_result",
4206
+ toolName: call.name,
4207
+ toolUseId: call.id,
4208
+ result: { error: check.blockReason, _gate: check.blockGate },
4209
+ isError: true
4210
+ };
4211
+ toolResultBlocks.push({
4212
+ type: "tool_result",
4213
+ toolUseId: call.id,
4214
+ content: JSON.stringify({ error: check.blockReason, _gate: check.blockGate }),
4215
+ isError: true
4216
+ });
4217
+ continue;
4218
+ }
4219
+ if (check.injections.length > 0) {
4220
+ call._guardInjections = check.injections;
4221
+ }
4222
+ guardedApproved.push(call);
4223
+ }
4224
+ } else {
4225
+ guardedApproved.push(...approved);
4226
+ }
4227
+ for await (const toolEvent of runTools(guardedApproved, this.tools, context, this.txMutex)) {
3750
4228
  if (toolEvent.type === "tool_result" && !toolEvent.isError) {
3751
4229
  const warning = flagSuspiciousResult(toolEvent.toolName, toolEvent.result);
3752
4230
  if (warning) {
@@ -3764,29 +4242,89 @@ ${summary.join("\n")}`);
3764
4242
  continue;
3765
4243
  }
3766
4244
  }
3767
- yield toolEvent;
3768
- if (toolEvent.type === "tool_result" && !toolEvent.isError) {
3769
- const r = toolEvent.result;
3770
- if (r && r.__canvas === true) {
3771
- yield {
3772
- type: "canvas",
3773
- template: String(r.template ?? ""),
3774
- title: String(r.title ?? ""),
3775
- data: r.templateData ?? null,
3776
- toolUseId: toolEvent.toolUseId
3777
- };
4245
+ if (toolEvent.type === "tool_result") {
4246
+ const tool = findTool(this.tools, toolEvent.toolName);
4247
+ const originalCall = guardedApproved.find((c) => c.id === toolEvent.toolUseId);
4248
+ updateGuardStateAfterToolResult(
4249
+ toolEvent.toolName,
4250
+ tool,
4251
+ originalCall?.input ?? null,
4252
+ toolEvent.result,
4253
+ toolEvent.isError,
4254
+ this.guardState
4255
+ );
4256
+ let enrichedResult = toolEvent.result;
4257
+ if (this.guardConfig && !toolEvent.isError && tool) {
4258
+ const artifactInj = this.guardConfig.artifactPreview !== false ? guardArtifactPreview(toolEvent.result) : null;
4259
+ const staleInj = this.guardConfig.staleData !== false ? guardStaleData(tool.flags) : null;
4260
+ const preInjections = guardedApproved.find((c) => c.id === toolEvent.toolUseId)?._guardInjections ?? [];
4261
+ const allInjections = [
4262
+ ...preInjections,
4263
+ ...artifactInj ? [artifactInj] : [],
4264
+ ...staleInj ? [staleInj] : []
4265
+ ];
4266
+ if (allInjections.length > 0 && typeof enrichedResult === "object" && enrichedResult) {
4267
+ enrichedResult = { ...enrichedResult, _guards: allInjections };
4268
+ }
4269
+ }
4270
+ const finalEvent = enrichedResult !== toolEvent.result ? { ...toolEvent, result: enrichedResult } : toolEvent;
4271
+ yield finalEvent;
4272
+ if (finalEvent.type === "tool_result" && !finalEvent.isError) {
4273
+ const r = finalEvent.result;
4274
+ if (r && r.__canvas === true) {
4275
+ yield {
4276
+ type: "canvas",
4277
+ template: String(r.template ?? ""),
4278
+ title: String(r.title ?? ""),
4279
+ data: r.templateData ?? null,
4280
+ toolUseId: finalEvent.toolUseId
4281
+ };
4282
+ }
3778
4283
  }
4284
+ toolResultBlocks.push({
4285
+ type: "tool_result",
4286
+ toolUseId: finalEvent.toolUseId,
4287
+ content: JSON.stringify(finalEvent.result),
4288
+ isError: finalEvent.isError
4289
+ });
4290
+ continue;
3779
4291
  }
3780
- if (toolEvent.type === "tool_result") {
4292
+ yield toolEvent;
4293
+ }
4294
+ if (pendingWrite && this.guardConfig) {
4295
+ const convCtx = extractConversationText(this.messages);
4296
+ const check = runGuards(
4297
+ pendingWrite.tool,
4298
+ pendingWrite.call,
4299
+ this.guardState,
4300
+ this.guardConfig,
4301
+ convCtx
4302
+ );
4303
+ this.guardEvents.push(...check.events);
4304
+ if (check.blocked) {
4305
+ yield {
4306
+ type: "tool_result",
4307
+ toolName: pendingWrite.call.name,
4308
+ toolUseId: pendingWrite.call.id,
4309
+ result: { error: check.blockReason, _gate: check.blockGate },
4310
+ isError: true
4311
+ };
3781
4312
  toolResultBlocks.push({
3782
4313
  type: "tool_result",
3783
- toolUseId: toolEvent.toolUseId,
3784
- content: JSON.stringify(toolEvent.result),
3785
- isError: toolEvent.isError
4314
+ toolUseId: pendingWrite.call.id,
4315
+ content: JSON.stringify({ error: check.blockReason, _gate: check.blockGate }),
4316
+ isError: true
3786
4317
  });
4318
+ this.messages.push({ role: "assistant", content: acc.assistantBlocks });
4319
+ this.messages.push({ role: "user", content: toolResultBlocks });
4320
+ continue;
4321
+ }
4322
+ if (check.injections.length > 0) {
4323
+ pendingWrite.call._guardInjections = check.injections;
3787
4324
  }
3788
4325
  }
3789
4326
  if (pendingWrite) {
4327
+ const writeGuardInjections = pendingWrite.call._guardInjections;
3790
4328
  yield {
3791
4329
  type: "pending_action",
3792
4330
  action: {
@@ -3799,7 +4337,8 @@ ${summary.join("\n")}`);
3799
4337
  toolUseId: b.toolUseId,
3800
4338
  content: b.content,
3801
4339
  isError: b.isError ?? false
3802
- }))
4340
+ })),
4341
+ ...writeGuardInjections?.length ? { guardInjections: writeGuardInjections } : {}
3803
4342
  }
3804
4343
  };
3805
4344
  return;
@@ -3829,6 +4368,26 @@ ${summary.join("\n")}`);
3829
4368
  }
3830
4369
  *handleProviderEvent(event, acc) {
3831
4370
  switch (event.type) {
4371
+ case "thinking_delta": {
4372
+ yield { type: "thinking_delta", text: event.text };
4373
+ break;
4374
+ }
4375
+ case "thinking_done": {
4376
+ acc.assistantBlocks.push({
4377
+ type: "thinking",
4378
+ thinking: event.thinking,
4379
+ signature: event.signature
4380
+ });
4381
+ yield { type: "thinking_done", signature: event.signature };
4382
+ break;
4383
+ }
4384
+ case "redacted_thinking": {
4385
+ acc.assistantBlocks.push({
4386
+ type: "redacted_thinking",
4387
+ data: event.data
4388
+ });
4389
+ break;
4390
+ }
3832
4391
  case "text_delta": {
3833
4392
  acc.text += event.text;
3834
4393
  yield { type: "text_delta", text: event.text };
@@ -4076,6 +4635,165 @@ var MemorySessionStore = class {
4076
4635
  }
4077
4636
  };
4078
4637
 
4638
+ // src/classify-effort.ts
4639
+ function classifyEffort(model, userMessage, matchedRecipe, sessionWriteCount) {
4640
+ const supportsMax = model.includes("opus-4-6");
4641
+ const msg = userMessage.toLowerCase();
4642
+ if (supportsMax) {
4643
+ if (matchedRecipe?.name === "portfolio_rebalance") return "max";
4644
+ if (matchedRecipe?.name === "emergency_withdraw") return "max";
4645
+ if (/rebalance|reallocate|dca setup|close.*position/i.test(msg)) return "max";
4646
+ }
4647
+ if (matchedRecipe && matchedRecipe.steps.length >= 3) return "high";
4648
+ if (matchedRecipe?.name === "safe_borrow" || matchedRecipe?.name === "bulk_mail") return "high";
4649
+ if (sessionWriteCount > 0 && /borrow|withdraw|send|swap/i.test(msg)) return "high";
4650
+ if (/balance|rate|how much|what is|check|history|show|price/i.test(msg)) return "low";
4651
+ if (!matchedRecipe && !/deposit|send|swap|borrow|withdraw|save|pay/i.test(msg)) return "low";
4652
+ return "medium";
4653
+ }
4654
+
4655
+ // src/prompt-cache.ts
4656
+ function buildCachedSystemPrompt(staticParts, dynamicPart) {
4657
+ const blocks = staticParts.map((text, i) => ({
4658
+ type: "text",
4659
+ text,
4660
+ ...i === staticParts.length - 1 && { cache_control: { type: "ephemeral" } }
4661
+ }));
4662
+ if (dynamicPart) {
4663
+ blocks.push({ type: "text", text: dynamicPart });
4664
+ }
4665
+ return blocks;
4666
+ }
4667
+
4668
+ // src/intelligence.ts
4669
+ function buildProfileContext(profile) {
4670
+ if (!profile || profile.riskConfidence < 0.3) return "";
4671
+ const lines = ["User financial profile (inferred from conversation history):"];
4672
+ if (profile.riskConfidence >= 0.5) {
4673
+ lines.push(`- Risk appetite: ${profile.riskAppetite}`);
4674
+ }
4675
+ if (profile.literacyConfidence >= 0.5) {
4676
+ lines.push(`- Financial literacy: ${profile.financialLiteracy}`);
4677
+ if (profile.financialLiteracy === "advanced") {
4678
+ lines.push(" \u2192 Skip basic DeFi explanations (health factor, APY, etc). User knows these.");
4679
+ }
4680
+ if (profile.financialLiteracy === "novice") {
4681
+ lines.push(" \u2192 Always explain DeFi concepts in plain language.");
4682
+ }
4683
+ }
4684
+ if (profile.currencyFraming === "fiat") {
4685
+ lines.push('- Frame amounts as dollars (e.g. "$50" not "50 USDC")');
4686
+ }
4687
+ if (profile.prefersBriefResponses) {
4688
+ lines.push("- Prefers brief responses \u2014 be concise");
4689
+ }
4690
+ if (profile.primaryGoals.length > 0) {
4691
+ lines.push(`- Stated goals: ${profile.primaryGoals.join(", ")}`);
4692
+ }
4693
+ if (profile.knownPatterns.length > 0) {
4694
+ lines.push(`- Behavioural patterns: ${profile.knownPatterns.join(", ")}`);
4695
+ }
4696
+ return lines.join("\n");
4697
+ }
4698
+ function buildProactivenessInstructions(profile) {
4699
+ const brevityGuidance = profile?.prefersBriefResponses ? "This user prefers brevity \u2014 only surface context if urgent or directly actionable." : "Surface relevant context when criteria are met.";
4700
+ const styleGuidance = profile?.financialLiteracy === "novice" ? "Frame observations in plain English, no DeFi jargon." : "Technical framing is fine.";
4701
+ return `Proactive awareness:
4702
+ After completing the user's request, consider whether ONE additional piece of financial
4703
+ context is worth mentioning. ${brevityGuidance}
4704
+
4705
+ \u2713 Mention if:
4706
+ - Their savings goal is materially off-track (>20% behind pace)
4707
+ - Yield rate changed significantly since last session (>0.5%)
4708
+ - They have idle USDC >$50 sitting for >48h
4709
+ - An action they just took interacts with an active goal or debt position
4710
+ - A pattern would materially benefit from their attention
4711
+
4712
+ \u2717 Do NOT mention if:
4713
+ - Tangentially related but not actionable
4714
+ - Already surfaced this session
4715
+ - Requires more explanation than the original answer
4716
+ - Would seem pushy or sales-y
4717
+
4718
+ ${styleGuidance}
4719
+ Format: One sentence maximum, after main response, separated by a line break.
4720
+ Frame as observation, not advice: "Your Tokyo goal is $80 behind pace." \u2014 not "You should deposit more."`;
4721
+ }
4722
+ function buildSelfEvaluationInstruction() {
4723
+ return `Self-evaluation (apply silently before composing your response):
4724
+
4725
+ 1. ACCURACY \u2014 Quote exact values from tool results, not estimates or rounded figures.
4726
+ Never combine post-action tool results with pre-action snapshot numbers.
4727
+ If the tool returned an error, label it as an error \u2014 do not paraphrase it as success.
4728
+
4729
+ 2. STATE CONSISTENCY \u2014 Describe the actual outcome of all steps.
4730
+ Partial success (swap ok, deposit failed): describe both clearly.
4731
+ Never describe a failed action as if it succeeded.
4732
+
4733
+ 3. COMPLETENESS \u2014 If the user asked multiple things, answer all of them.
4734
+ If you couldn't complete something, explain why and what the current state is.
4735
+
4736
+ 4. TONE \u2014 Match tone to outcome.
4737
+ Success: confirming and forward-looking.
4738
+ Failure: clear about what failed, unchanged, and what to do next.
4739
+ Warning: specific risk, not generic caution.
4740
+
4741
+ If any check fails, rewrite before outputting.`;
4742
+ }
4743
+
4744
+ // src/state/conversation-state.ts
4745
+ function buildStateContext(state) {
4746
+ switch (state.type) {
4747
+ case "idle":
4748
+ return "";
4749
+ case "mid_recipe": {
4750
+ const elapsed = Math.round((Date.now() - state.startedAt) / 6e4);
4751
+ const outputs = JSON.stringify(state.completedStepOutputs);
4752
+ return [
4753
+ `Conversation state: MID-RECIPE`,
4754
+ `Active recipe: ${state.recipeName} (step ${state.currentStep + 1} of ${state.totalSteps})`,
4755
+ `Started: ${elapsed} minutes ago`,
4756
+ `Completed step key outputs: ${outputs}`,
4757
+ `If the user asks an unrelated question: answer briefly, then offer to continue the ${state.recipeName} flow.`,
4758
+ `If the user says "cancel" or "stop": confirm you have abandoned the recipe and return to idle.`
4759
+ ].join("\n");
4760
+ }
4761
+ case "awaiting_confirmation": {
4762
+ const expiryMins = Math.max(0, Math.round((state.expiresAt - Date.now()) / 6e4));
4763
+ const expired = state.expiresAt < Date.now();
4764
+ return [
4765
+ `Conversation state: AWAITING CONFIRMATION`,
4766
+ `Proposed action: ${state.action}${state.amount ? ` for $${state.amount}` : ""}${state.recipient ? ` to ${state.recipient}` : ""}`,
4767
+ expired ? `Status: EXPIRED \u2014 ask if user still wants to proceed` : `Expires in: ${expiryMins} minutes`,
4768
+ `"yes/confirm/do it" \u2192 execute. "no/cancel/wait" \u2192 abort, reset to idle.`
4769
+ ].join("\n");
4770
+ }
4771
+ case "post_error":
4772
+ return [
4773
+ `Conversation state: POST-ERROR`,
4774
+ `Failed action: ${state.failedAction}`,
4775
+ `Error: ${state.errorMessage}`,
4776
+ state.partialState ? `Partial state: ${state.partialState}` : "",
4777
+ `Acknowledge failure clearly. Offer a specific recovery path if one exists.`,
4778
+ `This state clears automatically on the next successful action.`
4779
+ ].filter(Boolean).join("\n");
4780
+ case "post_liquidation_warning":
4781
+ return [
4782
+ `Conversation state: LIQUIDATION WARNING ACTIVE`,
4783
+ `Health factor: ${state.healthFactor.toFixed(2)} \u2014 below safe threshold`,
4784
+ `Prioritise debt repayment or collateral deposit.`,
4785
+ `Do not proceed with any action that would further reduce health factor.`
4786
+ ].join("\n");
4787
+ case "onboarding":
4788
+ return [
4789
+ `Conversation state: ONBOARDING (session ${state.sessionNumber})`,
4790
+ state.sessionNumber === 1 ? "First session \u2014 introduce capabilities through context, not a feature list." : `Returning user \u2014 ${state.hasSavedBefore ? "has saved before" : "has not saved yet"}.`
4791
+ ].join("\n");
4792
+ default:
4793
+ return "";
4794
+ }
4795
+ }
4796
+
4079
4797
  // src/context.ts
4080
4798
  var CHARS_PER_TOKEN = 4;
4081
4799
  function estimateTokens(messages) {
@@ -4091,6 +4809,10 @@ function blockCharCount(block) {
4091
4809
  switch (block.type) {
4092
4810
  case "text":
4093
4811
  return block.text.length;
4812
+ case "thinking":
4813
+ return block.thinking.length;
4814
+ case "redacted_thinking":
4815
+ return block.data.length;
4094
4816
  case "tool_use":
4095
4817
  return block.name.length + JSON.stringify(block.input).length;
4096
4818
  case "tool_result":
@@ -4419,6 +5141,7 @@ function adaptMcpTool(mcpTool, config) {
4419
5141
  isReadOnly,
4420
5142
  isConcurrencySafe: isReadOnly,
4421
5143
  permissionLevel,
5144
+ flags: {},
4422
5145
  async call(input, _context) {
4423
5146
  const result = await config.manager.callTool(
4424
5147
  config.serverName,
@@ -4484,17 +5207,26 @@ var AnthropicProvider = class {
4484
5207
  toolChoice = { type: "tool", name: params.toolChoice.name };
4485
5208
  }
4486
5209
  }
4487
- const streamParams = {
5210
+ const thinkingParam = toAnthropicThinking(params.thinking);
5211
+ const systemParam = toAnthropicSystem(params.systemPrompt);
5212
+ const baseParams = {
4488
5213
  model: params.model ?? this.defaultModel,
4489
5214
  max_tokens: params.maxTokens ?? this.defaultMaxTokens,
4490
- system: params.systemPrompt,
5215
+ system: systemParam,
4491
5216
  messages,
5217
+ stream: true,
4492
5218
  tools: tools.length > 0 ? tools : void 0,
4493
- ...params.temperature !== void 0 && { temperature: params.temperature },
5219
+ ...!thinkingParam && params.temperature !== void 0 && { temperature: params.temperature },
4494
5220
  ...toolChoice && { tool_choice: toolChoice }
4495
5221
  };
5222
+ const streamParams = {
5223
+ ...baseParams,
5224
+ ...thinkingParam && { thinking: thinkingParam },
5225
+ ...params.outputConfig?.effort && { output_config: { effort: params.outputConfig.effort } }
5226
+ };
4496
5227
  const stream = params.signal ? this.client.messages.stream(streamParams, { signal: params.signal }) : this.client.messages.stream(streamParams);
4497
5228
  const toolInputBuffers = /* @__PURE__ */ new Map();
5229
+ const thinkingBuffers = /* @__PURE__ */ new Map();
4498
5230
  let outputTokensFromStart = 0;
4499
5231
  try {
4500
5232
  for await (const event of stream) {
@@ -4532,6 +5264,10 @@ var AnthropicProvider = class {
4532
5264
  id: block.id,
4533
5265
  name: block.name
4534
5266
  };
5267
+ } else if (block.type === "thinking") {
5268
+ thinkingBuffers.set(event.index, { type: "thinking", text: "", signature: "" });
5269
+ } else if (block.type === "redacted_thinking") {
5270
+ thinkingBuffers.set(event.index, { type: "redacted_thinking", data: block.data ?? "" });
4535
5271
  }
4536
5272
  break;
4537
5273
  }
@@ -4549,26 +5285,41 @@ var AnthropicProvider = class {
4549
5285
  partialJson: delta.partial_json
4550
5286
  };
4551
5287
  }
5288
+ } else if (delta.type === "thinking_delta") {
5289
+ const buf = thinkingBuffers.get(event.index);
5290
+ if (buf?.type === "thinking") buf.text += delta.thinking ?? "";
5291
+ yield { type: "thinking_delta", text: delta.thinking ?? "" };
5292
+ } else if (delta.type === "signature_delta") {
5293
+ const buf = thinkingBuffers.get(event.index);
5294
+ if (buf?.type === "thinking") buf.signature = delta.signature ?? "";
4552
5295
  }
4553
5296
  break;
4554
5297
  }
4555
5298
  case "content_block_stop": {
4556
- const buf = toolInputBuffers.get(event.index);
4557
- if (buf) {
5299
+ const toolBuf = toolInputBuffers.get(event.index);
5300
+ if (toolBuf) {
4558
5301
  let input = {};
4559
5302
  try {
4560
- input = JSON.parse(buf.json || "{}");
5303
+ input = JSON.parse(toolBuf.json || "{}");
4561
5304
  } catch {
4562
5305
  input = {};
4563
5306
  }
4564
5307
  yield {
4565
5308
  type: "tool_use_done",
4566
- id: buf.id,
4567
- name: buf.name,
5309
+ id: toolBuf.id,
5310
+ name: toolBuf.name,
4568
5311
  input
4569
5312
  };
4570
5313
  toolInputBuffers.delete(event.index);
4571
5314
  }
5315
+ const thinkBuf = thinkingBuffers.get(event.index);
5316
+ if (thinkBuf?.type === "thinking") {
5317
+ yield { type: "thinking_done", thinking: thinkBuf.text, signature: thinkBuf.signature };
5318
+ thinkingBuffers.delete(event.index);
5319
+ } else if (thinkBuf?.type === "redacted_thinking") {
5320
+ yield { type: "redacted_thinking", data: thinkBuf.data };
5321
+ thinkingBuffers.delete(event.index);
5322
+ }
4572
5323
  break;
4573
5324
  }
4574
5325
  case "message_delta": {
@@ -4598,11 +5349,28 @@ var AnthropicProvider = class {
4598
5349
  }
4599
5350
  }
4600
5351
  };
5352
+ function toAnthropicSystem(prompt) {
5353
+ if (typeof prompt === "string") return prompt;
5354
+ return prompt.map((block) => ({
5355
+ type: "text",
5356
+ text: block.text,
5357
+ ...block.cache_control && { cache_control: block.cache_control }
5358
+ }));
5359
+ }
5360
+ function toAnthropicThinking(config) {
5361
+ if (!config || config.type === "disabled") return void 0;
5362
+ if (config.type === "adaptive") return { type: "adaptive" };
5363
+ return { type: "enabled", budget_tokens: config.budgetTokens };
5364
+ }
4601
5365
  function toAnthropicMessage(msg) {
4602
5366
  const content = msg.content.map((block) => {
4603
5367
  switch (block.type) {
4604
5368
  case "text":
4605
5369
  return { type: "text", text: block.text };
5370
+ case "thinking":
5371
+ return { type: "thinking", thinking: block.thinking, signature: block.signature };
5372
+ case "redacted_thinking":
5373
+ return { type: "redacted_thinking", data: block.data };
4606
5374
  case "tool_use":
4607
5375
  return {
4608
5376
  type: "tool_use",
@@ -4618,7 +5386,7 @@ function toAnthropicMessage(msg) {
4618
5386
  is_error: block.isError
4619
5387
  };
4620
5388
  }
4621
- });
5389
+ }).filter((b) => b !== null);
4622
5390
  return { role: msg.role, content };
4623
5391
  }
4624
5392
  function toAnthropicTool(def) {
@@ -4707,6 +5475,6 @@ function sanitizeAnthropicMessages(messages) {
4707
5475
  return merged;
4708
5476
  }
4709
5477
 
4710
- export { AnthropicProvider, CANVAS_TEMPLATES, CostTracker, DEFAULT_SYSTEM_PROMPT, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, QueryEngine, READ_TOOLS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, balanceCheckTool, borrowTool, buildMcpTools, buildTool, claimRewardsTool, clearPriceCache, compactMessages, defillamaChainTvlTool, defillamaPriceChangeTool, defillamaProtocolFeesTool, defillamaProtocolInfoTool, defillamaSuiProtocolsTool, defillamaTokenPricesTool, defillamaYieldPoolsTool, engineToSSE, estimateTokens, explainTxTool, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getWalletAddress, hasNaviMcp, healthCheckTool, mppServicesTool, parseMcpJson, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
5478
+ export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_SYSTEM_PROMPT, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, QueryEngine, READ_TOOLS, 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, mppServicesTool, parseMcpJson, 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 };
4711
5479
  //# sourceMappingURL=index.js.map
4712
5480
  //# sourceMappingURL=index.js.map