@t2000/engine 0.31.1 → 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.d.ts +320 -18
- package/dist/index.js +854 -39
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
17
|
-
isConcurrencySafe:
|
|
18
|
-
permissionLevel: opts.permissionLevel ?? (
|
|
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 }
|
|
@@ -992,7 +1034,7 @@ function parseRpcTx(tx, address) {
|
|
|
992
1034
|
gasCost
|
|
993
1035
|
};
|
|
994
1036
|
}
|
|
995
|
-
async function
|
|
1037
|
+
async function queryHistoryPage(rpcUrl, address, limit, cursor) {
|
|
996
1038
|
const res = await fetch(rpcUrl, {
|
|
997
1039
|
method: "POST",
|
|
998
1040
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1002,7 +1044,7 @@ async function queryHistoryRpc(rpcUrl, address, limit) {
|
|
|
1002
1044
|
method: "suix_queryTransactionBlocks",
|
|
1003
1045
|
params: [
|
|
1004
1046
|
{ filter: { FromAddress: address }, options: { showEffects: true, showInput: true, showBalanceChanges: true } },
|
|
1005
|
-
|
|
1047
|
+
cursor,
|
|
1006
1048
|
limit,
|
|
1007
1049
|
true
|
|
1008
1050
|
]
|
|
@@ -1012,13 +1054,48 @@ async function queryHistoryRpc(rpcUrl, address, limit) {
|
|
|
1012
1054
|
if (!res.ok) throw new Error(`Sui RPC error: ${res.status}`);
|
|
1013
1055
|
const json = await res.json();
|
|
1014
1056
|
if (json.error) throw new Error(`RPC error: ${json.error.message}`);
|
|
1015
|
-
return
|
|
1057
|
+
return {
|
|
1058
|
+
data: json.result?.data ?? [],
|
|
1059
|
+
nextCursor: json.result?.nextCursor ?? null,
|
|
1060
|
+
hasNextPage: json.result?.hasNextPage ?? false
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
async function queryHistoryRpc(rpcUrl, address, limit) {
|
|
1064
|
+
const page = await queryHistoryPage(rpcUrl, address, limit, null);
|
|
1065
|
+
return page.data.map((tx) => parseRpcTx(tx, address));
|
|
1066
|
+
}
|
|
1067
|
+
async function queryHistoryByDate(rpcUrl, address, targetDate, limit) {
|
|
1068
|
+
const target = new Date(targetDate);
|
|
1069
|
+
const dayStart = new Date(target.getFullYear(), target.getMonth(), target.getDate()).getTime();
|
|
1070
|
+
const dayEnd = dayStart + 864e5;
|
|
1071
|
+
const MAX_PAGES = 20;
|
|
1072
|
+
const PAGE_SIZE = 50;
|
|
1073
|
+
const results = [];
|
|
1074
|
+
let cursor = null;
|
|
1075
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
1076
|
+
const res = await queryHistoryPage(rpcUrl, address, PAGE_SIZE, cursor);
|
|
1077
|
+
if (res.data.length === 0) break;
|
|
1078
|
+
for (const tx of res.data) {
|
|
1079
|
+
const ts = Number(tx.timestampMs ?? 0);
|
|
1080
|
+
if (ts === 0) continue;
|
|
1081
|
+
if (ts < dayStart) {
|
|
1082
|
+
return results.slice(0, limit);
|
|
1083
|
+
}
|
|
1084
|
+
if (ts >= dayStart && ts < dayEnd) {
|
|
1085
|
+
results.push(parseRpcTx(tx, address));
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (!res.hasNextPage || !res.nextCursor) break;
|
|
1089
|
+
cursor = res.nextCursor;
|
|
1090
|
+
}
|
|
1091
|
+
return results.slice(0, limit);
|
|
1016
1092
|
}
|
|
1017
1093
|
var transactionHistoryTool = buildTool({
|
|
1018
1094
|
name: "transaction_history",
|
|
1019
|
-
description: "Retrieve
|
|
1095
|
+
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.",
|
|
1020
1096
|
inputSchema: z.object({
|
|
1021
|
-
limit: z.number().int().min(1).max(50).optional()
|
|
1097
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
1098
|
+
date: z.string().optional().describe("Specific date to search for transactions (YYYY-MM-DD format). Paginates back to find that day.")
|
|
1022
1099
|
}),
|
|
1023
1100
|
jsonSchema: {
|
|
1024
1101
|
type: "object",
|
|
@@ -1026,6 +1103,10 @@ var transactionHistoryTool = buildTool({
|
|
|
1026
1103
|
limit: {
|
|
1027
1104
|
type: "number",
|
|
1028
1105
|
description: "Maximum number of transactions to return (1-50, default 10)"
|
|
1106
|
+
},
|
|
1107
|
+
date: {
|
|
1108
|
+
type: "string",
|
|
1109
|
+
description: "Specific date to search for transactions (YYYY-MM-DD format). Paginates back to find that day."
|
|
1029
1110
|
}
|
|
1030
1111
|
}
|
|
1031
1112
|
},
|
|
@@ -1036,16 +1117,24 @@ var transactionHistoryTool = buildTool({
|
|
|
1036
1117
|
const agent = requireAgent(context);
|
|
1037
1118
|
const records2 = await agent.history({ limit });
|
|
1038
1119
|
return {
|
|
1039
|
-
data: { transactions: records2, count: records2.length },
|
|
1120
|
+
data: { transactions: records2, count: records2.length, date: input.date ?? null },
|
|
1040
1121
|
displayText: `${records2.length} recent transaction(s)`
|
|
1041
1122
|
};
|
|
1042
1123
|
}
|
|
1043
1124
|
if (!context.walletAddress || !context.suiRpcUrl) {
|
|
1044
1125
|
throw new Error("Transaction history requires a wallet address");
|
|
1045
1126
|
}
|
|
1127
|
+
if (input.date) {
|
|
1128
|
+
const records2 = await queryHistoryByDate(context.suiRpcUrl, context.walletAddress, input.date, limit);
|
|
1129
|
+
const dateLabel = new Date(input.date).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
|
|
1130
|
+
return {
|
|
1131
|
+
data: { transactions: records2, count: records2.length, date: input.date },
|
|
1132
|
+
displayText: records2.length > 0 ? `${records2.length} transaction(s) on ${dateLabel}` : `No transactions found on ${dateLabel}`
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1046
1135
|
const records = await queryHistoryRpc(context.suiRpcUrl, context.walletAddress, limit);
|
|
1047
1136
|
return {
|
|
1048
|
-
data: { transactions: records, count: records.length },
|
|
1137
|
+
data: { transactions: records, count: records.length, date: null },
|
|
1049
1138
|
displayText: `${records.length} recent transaction(s)`
|
|
1050
1139
|
};
|
|
1051
1140
|
}
|
|
@@ -1072,6 +1161,13 @@ var saveDepositTool = buildTool({
|
|
|
1072
1161
|
},
|
|
1073
1162
|
isReadOnly: false,
|
|
1074
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
|
+
},
|
|
1075
1171
|
async call(input, context) {
|
|
1076
1172
|
assertAllowedAsset("save", input.asset);
|
|
1077
1173
|
const agent = requireAgent(context);
|
|
@@ -1113,6 +1209,7 @@ var withdrawTool = buildTool({
|
|
|
1113
1209
|
},
|
|
1114
1210
|
isReadOnly: false,
|
|
1115
1211
|
permissionLevel: "confirm",
|
|
1212
|
+
flags: { mutating: true, affectsHealth: true },
|
|
1116
1213
|
async call(input, context) {
|
|
1117
1214
|
const agent = requireAgent(context);
|
|
1118
1215
|
const result = await agent.withdraw({
|
|
@@ -1160,6 +1257,16 @@ var sendTransferTool = buildTool({
|
|
|
1160
1257
|
},
|
|
1161
1258
|
isReadOnly: false,
|
|
1162
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
|
+
},
|
|
1163
1270
|
async call(input, context) {
|
|
1164
1271
|
const agent = requireAgent(context);
|
|
1165
1272
|
const result = await agent.send({ to: input.to, amount: input.amount });
|
|
@@ -1202,6 +1309,13 @@ var borrowTool = buildTool({
|
|
|
1202
1309
|
},
|
|
1203
1310
|
isReadOnly: false,
|
|
1204
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
|
+
},
|
|
1205
1319
|
async call(input, context) {
|
|
1206
1320
|
assertAllowedAsset("borrow", input.asset);
|
|
1207
1321
|
const agent = requireAgent(context);
|
|
@@ -1236,6 +1350,7 @@ var repayDebtTool = buildTool({
|
|
|
1236
1350
|
},
|
|
1237
1351
|
isReadOnly: false,
|
|
1238
1352
|
permissionLevel: "confirm",
|
|
1353
|
+
flags: { mutating: true, requiresBalance: true },
|
|
1239
1354
|
async call(input, context) {
|
|
1240
1355
|
const agent = requireAgent(context);
|
|
1241
1356
|
const result = await agent.repay({ amount: input.amount });
|
|
@@ -1258,6 +1373,7 @@ var claimRewardsTool = buildTool({
|
|
|
1258
1373
|
jsonSchema: { type: "object", properties: {}, required: [] },
|
|
1259
1374
|
isReadOnly: false,
|
|
1260
1375
|
permissionLevel: "confirm",
|
|
1376
|
+
flags: { mutating: true },
|
|
1261
1377
|
async call(_input, context) {
|
|
1262
1378
|
const agent = requireAgent(context);
|
|
1263
1379
|
const result = await agent.claimRewards();
|
|
@@ -1332,6 +1448,28 @@ Always use ISO-3166 country codes (GB not UK, US not USA). A return address ("fr
|
|
|
1332
1448
|
},
|
|
1333
1449
|
isReadOnly: false,
|
|
1334
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
|
+
},
|
|
1335
1473
|
async call(input, context) {
|
|
1336
1474
|
const agent = requireAgent(context);
|
|
1337
1475
|
const result = await agent.pay({
|
|
@@ -1433,6 +1571,13 @@ var swapExecuteTool = buildTool({
|
|
|
1433
1571
|
},
|
|
1434
1572
|
isReadOnly: false,
|
|
1435
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
|
+
},
|
|
1436
1581
|
async call(input, context) {
|
|
1437
1582
|
const agent = requireAgent(context);
|
|
1438
1583
|
const result = await agent.swap({
|
|
@@ -1507,6 +1652,7 @@ var voloStakeTool = buildTool({
|
|
|
1507
1652
|
},
|
|
1508
1653
|
isReadOnly: false,
|
|
1509
1654
|
permissionLevel: "confirm",
|
|
1655
|
+
flags: { mutating: true, requiresBalance: true },
|
|
1510
1656
|
async call(input, context) {
|
|
1511
1657
|
const agent = requireAgent(context);
|
|
1512
1658
|
const result = await agent.stakeVSui({ amount: input.amount });
|
|
@@ -1537,6 +1683,7 @@ var voloUnstakeTool = buildTool({
|
|
|
1537
1683
|
},
|
|
1538
1684
|
isReadOnly: false,
|
|
1539
1685
|
permissionLevel: "confirm",
|
|
1686
|
+
flags: { mutating: true },
|
|
1540
1687
|
async call(input, context) {
|
|
1541
1688
|
const agent = requireAgent(context);
|
|
1542
1689
|
const result = await agent.unstakeVSui({ amount: input.amount });
|
|
@@ -3369,7 +3516,7 @@ var WRITE_TOOLS = [
|
|
|
3369
3516
|
cancelScheduleTool
|
|
3370
3517
|
];
|
|
3371
3518
|
function getDefaultTools() {
|
|
3372
|
-
return [...READ_TOOLS, ...WRITE_TOOLS];
|
|
3519
|
+
return applyToolFlags([...READ_TOOLS, ...WRITE_TOOLS]);
|
|
3373
3520
|
}
|
|
3374
3521
|
|
|
3375
3522
|
// src/prompt.ts
|
|
@@ -3470,6 +3617,330 @@ var CostTracker = class {
|
|
|
3470
3617
|
}
|
|
3471
3618
|
};
|
|
3472
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 ."
|
|
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
|
+
|
|
3473
3944
|
// src/engine.ts
|
|
3474
3945
|
var DEFAULT_MAX_TURNS = 10;
|
|
3475
3946
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
@@ -3482,6 +3953,8 @@ var QueryEngine = class {
|
|
|
3482
3953
|
maxTokens;
|
|
3483
3954
|
temperature;
|
|
3484
3955
|
toolChoice;
|
|
3956
|
+
thinking;
|
|
3957
|
+
outputConfig;
|
|
3485
3958
|
agent;
|
|
3486
3959
|
mcpManager;
|
|
3487
3960
|
walletAddress;
|
|
@@ -3491,8 +3964,11 @@ var QueryEngine = class {
|
|
|
3491
3964
|
env;
|
|
3492
3965
|
txMutex = new TxMutex();
|
|
3493
3966
|
costTracker;
|
|
3967
|
+
guardConfig;
|
|
3968
|
+
guardState;
|
|
3494
3969
|
messages = [];
|
|
3495
3970
|
abortController = null;
|
|
3971
|
+
guardEvents = [];
|
|
3496
3972
|
constructor(config) {
|
|
3497
3973
|
this.provider = config.provider;
|
|
3498
3974
|
this.agent = config.agent;
|
|
@@ -3507,8 +3983,12 @@ var QueryEngine = class {
|
|
|
3507
3983
|
this.maxTokens = config.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
3508
3984
|
this.temperature = config.temperature;
|
|
3509
3985
|
this.toolChoice = config.toolChoice;
|
|
3986
|
+
this.thinking = config.thinking;
|
|
3987
|
+
this.outputConfig = config.outputConfig;
|
|
3510
3988
|
this.systemPrompt = config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
3511
3989
|
this.costTracker = new CostTracker(config.costTracker);
|
|
3990
|
+
this.guardConfig = config.guards;
|
|
3991
|
+
this.guardState = createGuardRunnerState();
|
|
3512
3992
|
this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
|
|
3513
3993
|
}
|
|
3514
3994
|
/**
|
|
@@ -3587,6 +4067,10 @@ var QueryEngine = class {
|
|
|
3587
4067
|
reset() {
|
|
3588
4068
|
this.messages = [];
|
|
3589
4069
|
this.costTracker.reset();
|
|
4070
|
+
this.guardEvents = [];
|
|
4071
|
+
}
|
|
4072
|
+
getGuardEvents() {
|
|
4073
|
+
return this.guardEvents;
|
|
3590
4074
|
}
|
|
3591
4075
|
loadMessages(messages) {
|
|
3592
4076
|
this.messages = [...messages];
|
|
@@ -3638,6 +4122,8 @@ var QueryEngine = class {
|
|
|
3638
4122
|
const summary = this.messages.map((m, idx) => {
|
|
3639
4123
|
const blocks = m.content.map((b) => {
|
|
3640
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`;
|
|
3641
4127
|
if (b.type === "tool_use") return `tool_use:${b.id.slice(-8)}/${b.name}`;
|
|
3642
4128
|
return `tool_result:${b.toolUseId.slice(-8)}`;
|
|
3643
4129
|
});
|
|
@@ -3646,6 +4132,8 @@ var QueryEngine = class {
|
|
|
3646
4132
|
console.log(`[engine] provider.chat turn=${turns} msgs=${this.messages.length}
|
|
3647
4133
|
${summary.join("\n")}`);
|
|
3648
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;
|
|
3649
4137
|
const stream = this.provider.chat({
|
|
3650
4138
|
messages: this.messages,
|
|
3651
4139
|
systemPrompt: this.systemPrompt,
|
|
@@ -3653,7 +4141,9 @@ ${summary.join("\n")}`);
|
|
|
3653
4141
|
model: this.model,
|
|
3654
4142
|
maxTokens: this.maxTokens,
|
|
3655
4143
|
temperature: this.temperature,
|
|
3656
|
-
toolChoice:
|
|
4144
|
+
toolChoice: effectiveToolChoice,
|
|
4145
|
+
thinking: this.thinking,
|
|
4146
|
+
outputConfig: this.outputConfig,
|
|
3657
4147
|
signal
|
|
3658
4148
|
});
|
|
3659
4149
|
for await (const event of stream) {
|
|
@@ -3699,7 +4189,42 @@ ${summary.join("\n")}`);
|
|
|
3699
4189
|
pendingWrite = { call, tool };
|
|
3700
4190
|
break;
|
|
3701
4191
|
}
|
|
3702
|
-
|
|
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)) {
|
|
3703
4228
|
if (toolEvent.type === "tool_result" && !toolEvent.isError) {
|
|
3704
4229
|
const warning = flagSuspiciousResult(toolEvent.toolName, toolEvent.result);
|
|
3705
4230
|
if (warning) {
|
|
@@ -3717,29 +4242,89 @@ ${summary.join("\n")}`);
|
|
|
3717
4242
|
continue;
|
|
3718
4243
|
}
|
|
3719
4244
|
}
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
const
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
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
|
+
}
|
|
3731
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;
|
|
3732
4291
|
}
|
|
3733
|
-
|
|
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
|
+
};
|
|
3734
4312
|
toolResultBlocks.push({
|
|
3735
4313
|
type: "tool_result",
|
|
3736
|
-
toolUseId:
|
|
3737
|
-
content: JSON.stringify(
|
|
3738
|
-
isError:
|
|
4314
|
+
toolUseId: pendingWrite.call.id,
|
|
4315
|
+
content: JSON.stringify({ error: check.blockReason, _gate: check.blockGate }),
|
|
4316
|
+
isError: true
|
|
3739
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;
|
|
3740
4324
|
}
|
|
3741
4325
|
}
|
|
3742
4326
|
if (pendingWrite) {
|
|
4327
|
+
const writeGuardInjections = pendingWrite.call._guardInjections;
|
|
3743
4328
|
yield {
|
|
3744
4329
|
type: "pending_action",
|
|
3745
4330
|
action: {
|
|
@@ -3752,7 +4337,8 @@ ${summary.join("\n")}`);
|
|
|
3752
4337
|
toolUseId: b.toolUseId,
|
|
3753
4338
|
content: b.content,
|
|
3754
4339
|
isError: b.isError ?? false
|
|
3755
|
-
}))
|
|
4340
|
+
})),
|
|
4341
|
+
...writeGuardInjections?.length ? { guardInjections: writeGuardInjections } : {}
|
|
3756
4342
|
}
|
|
3757
4343
|
};
|
|
3758
4344
|
return;
|
|
@@ -3782,6 +4368,26 @@ ${summary.join("\n")}`);
|
|
|
3782
4368
|
}
|
|
3783
4369
|
*handleProviderEvent(event, acc) {
|
|
3784
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
|
+
}
|
|
3785
4391
|
case "text_delta": {
|
|
3786
4392
|
acc.text += event.text;
|
|
3787
4393
|
yield { type: "text_delta", text: event.text };
|
|
@@ -4029,6 +4635,165 @@ var MemorySessionStore = class {
|
|
|
4029
4635
|
}
|
|
4030
4636
|
};
|
|
4031
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
|
+
|
|
4032
4797
|
// src/context.ts
|
|
4033
4798
|
var CHARS_PER_TOKEN = 4;
|
|
4034
4799
|
function estimateTokens(messages) {
|
|
@@ -4044,6 +4809,10 @@ function blockCharCount(block) {
|
|
|
4044
4809
|
switch (block.type) {
|
|
4045
4810
|
case "text":
|
|
4046
4811
|
return block.text.length;
|
|
4812
|
+
case "thinking":
|
|
4813
|
+
return block.thinking.length;
|
|
4814
|
+
case "redacted_thinking":
|
|
4815
|
+
return block.data.length;
|
|
4047
4816
|
case "tool_use":
|
|
4048
4817
|
return block.name.length + JSON.stringify(block.input).length;
|
|
4049
4818
|
case "tool_result":
|
|
@@ -4372,6 +5141,7 @@ function adaptMcpTool(mcpTool, config) {
|
|
|
4372
5141
|
isReadOnly,
|
|
4373
5142
|
isConcurrencySafe: isReadOnly,
|
|
4374
5143
|
permissionLevel,
|
|
5144
|
+
flags: {},
|
|
4375
5145
|
async call(input, _context) {
|
|
4376
5146
|
const result = await config.manager.callTool(
|
|
4377
5147
|
config.serverName,
|
|
@@ -4437,17 +5207,26 @@ var AnthropicProvider = class {
|
|
|
4437
5207
|
toolChoice = { type: "tool", name: params.toolChoice.name };
|
|
4438
5208
|
}
|
|
4439
5209
|
}
|
|
4440
|
-
const
|
|
5210
|
+
const thinkingParam = toAnthropicThinking(params.thinking);
|
|
5211
|
+
const systemParam = toAnthropicSystem(params.systemPrompt);
|
|
5212
|
+
const baseParams = {
|
|
4441
5213
|
model: params.model ?? this.defaultModel,
|
|
4442
5214
|
max_tokens: params.maxTokens ?? this.defaultMaxTokens,
|
|
4443
|
-
system:
|
|
5215
|
+
system: systemParam,
|
|
4444
5216
|
messages,
|
|
5217
|
+
stream: true,
|
|
4445
5218
|
tools: tools.length > 0 ? tools : void 0,
|
|
4446
|
-
|
|
5219
|
+
...!thinkingParam && params.temperature !== void 0 && { temperature: params.temperature },
|
|
4447
5220
|
...toolChoice && { tool_choice: toolChoice }
|
|
4448
5221
|
};
|
|
5222
|
+
const streamParams = {
|
|
5223
|
+
...baseParams,
|
|
5224
|
+
...thinkingParam && { thinking: thinkingParam },
|
|
5225
|
+
...params.outputConfig?.effort && { output_config: { effort: params.outputConfig.effort } }
|
|
5226
|
+
};
|
|
4449
5227
|
const stream = params.signal ? this.client.messages.stream(streamParams, { signal: params.signal }) : this.client.messages.stream(streamParams);
|
|
4450
5228
|
const toolInputBuffers = /* @__PURE__ */ new Map();
|
|
5229
|
+
const thinkingBuffers = /* @__PURE__ */ new Map();
|
|
4451
5230
|
let outputTokensFromStart = 0;
|
|
4452
5231
|
try {
|
|
4453
5232
|
for await (const event of stream) {
|
|
@@ -4485,6 +5264,10 @@ var AnthropicProvider = class {
|
|
|
4485
5264
|
id: block.id,
|
|
4486
5265
|
name: block.name
|
|
4487
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 ?? "" });
|
|
4488
5271
|
}
|
|
4489
5272
|
break;
|
|
4490
5273
|
}
|
|
@@ -4502,26 +5285,41 @@ var AnthropicProvider = class {
|
|
|
4502
5285
|
partialJson: delta.partial_json
|
|
4503
5286
|
};
|
|
4504
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 ?? "";
|
|
4505
5295
|
}
|
|
4506
5296
|
break;
|
|
4507
5297
|
}
|
|
4508
5298
|
case "content_block_stop": {
|
|
4509
|
-
const
|
|
4510
|
-
if (
|
|
5299
|
+
const toolBuf = toolInputBuffers.get(event.index);
|
|
5300
|
+
if (toolBuf) {
|
|
4511
5301
|
let input = {};
|
|
4512
5302
|
try {
|
|
4513
|
-
input = JSON.parse(
|
|
5303
|
+
input = JSON.parse(toolBuf.json || "{}");
|
|
4514
5304
|
} catch {
|
|
4515
5305
|
input = {};
|
|
4516
5306
|
}
|
|
4517
5307
|
yield {
|
|
4518
5308
|
type: "tool_use_done",
|
|
4519
|
-
id:
|
|
4520
|
-
name:
|
|
5309
|
+
id: toolBuf.id,
|
|
5310
|
+
name: toolBuf.name,
|
|
4521
5311
|
input
|
|
4522
5312
|
};
|
|
4523
5313
|
toolInputBuffers.delete(event.index);
|
|
4524
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
|
+
}
|
|
4525
5323
|
break;
|
|
4526
5324
|
}
|
|
4527
5325
|
case "message_delta": {
|
|
@@ -4551,11 +5349,28 @@ var AnthropicProvider = class {
|
|
|
4551
5349
|
}
|
|
4552
5350
|
}
|
|
4553
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
|
+
}
|
|
4554
5365
|
function toAnthropicMessage(msg) {
|
|
4555
5366
|
const content = msg.content.map((block) => {
|
|
4556
5367
|
switch (block.type) {
|
|
4557
5368
|
case "text":
|
|
4558
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 };
|
|
4559
5374
|
case "tool_use":
|
|
4560
5375
|
return {
|
|
4561
5376
|
type: "tool_use",
|
|
@@ -4571,7 +5386,7 @@ function toAnthropicMessage(msg) {
|
|
|
4571
5386
|
is_error: block.isError
|
|
4572
5387
|
};
|
|
4573
5388
|
}
|
|
4574
|
-
});
|
|
5389
|
+
}).filter((b) => b !== null);
|
|
4575
5390
|
return { role: msg.role, content };
|
|
4576
5391
|
}
|
|
4577
5392
|
function toAnthropicTool(def) {
|
|
@@ -4660,6 +5475,6 @@ function sanitizeAnthropicMessages(messages) {
|
|
|
4660
5475
|
return merged;
|
|
4661
5476
|
}
|
|
4662
5477
|
|
|
4663
|
-
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 };
|
|
4664
5479
|
//# sourceMappingURL=index.js.map
|
|
4665
5480
|
//# sourceMappingURL=index.js.map
|