@t2000/engine 0.42.0 → 0.44.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 +30 -1
- package/dist/index.js +73 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -625,6 +625,18 @@ interface Tool<TInput = unknown, TOutput = unknown> {
|
|
|
625
625
|
maxResultSizeChars?: number;
|
|
626
626
|
/** Custom truncation strategy. Falls back to generic slice + hint when omitted. */
|
|
627
627
|
summarizeOnTruncate?: (result: string, maxChars: number) => string;
|
|
628
|
+
/**
|
|
629
|
+
* [v1.5.1] Whether `microcompact` may dedupe this tool's results across
|
|
630
|
+
* multiple calls with identical input. Default `true` — most tools are
|
|
631
|
+
* effectively pure within a session (price lookups, protocol info,
|
|
632
|
+
* yield pools). Set to `false` for tools whose result depends on
|
|
633
|
+
* mutable on-chain state and therefore changes after writes
|
|
634
|
+
* (`balance_check`, `savings_info`, `health_check`,
|
|
635
|
+
* `transaction_history`). Non-cacheable tools are excluded from the
|
|
636
|
+
* `seen` map entirely, so neither this call nor any later call with
|
|
637
|
+
* the same input gets replaced with a "[Same result …]" back-reference.
|
|
638
|
+
*/
|
|
639
|
+
cacheable?: boolean;
|
|
628
640
|
}
|
|
629
641
|
type ThinkingEffort = 'low' | 'medium' | 'high' | 'max';
|
|
630
642
|
type ThinkingConfig = {
|
|
@@ -945,6 +957,11 @@ interface BuildToolOptions<TInput, TOutput> {
|
|
|
945
957
|
preflight?: (input: TInput) => PreflightResult;
|
|
946
958
|
maxResultSizeChars?: number;
|
|
947
959
|
summarizeOnTruncate?: (result: string, maxChars: number) => string;
|
|
960
|
+
/**
|
|
961
|
+
* [v1.5.1] See `Tool.cacheable`. Default `true`. Set `false` for
|
|
962
|
+
* tools whose results depend on mutable on-chain state.
|
|
963
|
+
*/
|
|
964
|
+
cacheable?: boolean;
|
|
948
965
|
}
|
|
949
966
|
declare function buildTool<TInput, TOutput>(opts: BuildToolOptions<TInput, TOutput>): Tool<TInput, TOutput>;
|
|
950
967
|
declare function toolsToDefinitions(tools: Tool[]): {
|
|
@@ -1180,11 +1197,23 @@ interface MicrocompactResult extends Array<Message> {
|
|
|
1180
1197
|
* the full prior result with a compact back-reference. Runs before any
|
|
1181
1198
|
* LLM-based compaction and costs nothing.
|
|
1182
1199
|
*
|
|
1200
|
+
* [v1.5.1] Tools may opt out of dedupe by setting `cacheable: false` on
|
|
1201
|
+
* their `Tool` definition. Non-cacheable tools (e.g. `balance_check`,
|
|
1202
|
+
* `savings_info`, `health_check`, `transaction_history`) are excluded
|
|
1203
|
+
* from the `seen` map entirely, so neither the current call nor any
|
|
1204
|
+
* later call with identical inputs gets replaced — necessary because
|
|
1205
|
+
* their results depend on mutable on-chain state that writes invalidate.
|
|
1206
|
+
*
|
|
1183
1207
|
* Returns a new array — does not mutate the input. The returned array
|
|
1184
1208
|
* carries a `dedupedToolUseIds` property listing every tool-use ID whose
|
|
1185
1209
|
* tool_result block was replaced with a back-reference this pass.
|
|
1210
|
+
*
|
|
1211
|
+
* @param messages — conversation ledger to compact.
|
|
1212
|
+
* @param tools — optional tool registry consulted to resolve the
|
|
1213
|
+
* per-tool `cacheable` flag. Omit to dedupe every
|
|
1214
|
+
* tool (legacy behavior — back-compat).
|
|
1186
1215
|
*/
|
|
1187
|
-
declare function microcompact(messages: readonly Message[]): MicrocompactResult;
|
|
1216
|
+
declare function microcompact(messages: readonly Message[], tools?: readonly Tool[]): MicrocompactResult;
|
|
1188
1217
|
|
|
1189
1218
|
/**
|
|
1190
1219
|
* EarlyToolDispatcher — dispatches read-only tools mid-stream.
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,8 @@ function buildTool(opts) {
|
|
|
23
23
|
flags: opts.flags ?? {},
|
|
24
24
|
preflight: opts.preflight,
|
|
25
25
|
maxResultSizeChars: opts.maxResultSizeChars,
|
|
26
|
-
summarizeOnTruncate: opts.summarizeOnTruncate
|
|
26
|
+
summarizeOnTruncate: opts.summarizeOnTruncate,
|
|
27
|
+
cacheable: opts.cacheable
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
30
|
function toolsToDefinitions(tools) {
|
|
@@ -180,14 +181,13 @@ function budgetToolResult(data, tool) {
|
|
|
180
181
|
}
|
|
181
182
|
const preview = serialized.slice(0, tool.maxResultSizeChars);
|
|
182
183
|
const linesOmitted = serialized.split("\n").length - preview.split("\n").length;
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
return JSON.parse(truncated);
|
|
188
|
-
} catch {
|
|
189
|
-
return truncated;
|
|
184
|
+
const note = `[Truncated \u2014 ${linesOmitted} lines omitted. Call ${tool.name} with narrower parameters (e.g. smaller date range or limit) to see more.]`;
|
|
185
|
+
if (typeof data === "object" && data !== null) {
|
|
186
|
+
return { _truncated: true, _preview: preview, _note: note };
|
|
190
187
|
}
|
|
188
|
+
return `${preview}
|
|
189
|
+
|
|
190
|
+
${note}`;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
// src/tool-flags.ts
|
|
@@ -557,6 +557,10 @@ var balanceCheckTool = buildTool({
|
|
|
557
557
|
inputSchema: z.object({}),
|
|
558
558
|
jsonSchema: { type: "object", properties: {}, required: [] },
|
|
559
559
|
isReadOnly: true,
|
|
560
|
+
// [v1.5.1] Wallet contents change after every send/swap/save/etc.
|
|
561
|
+
// Microcompact must NEVER dedupe these calls — each one reflects a
|
|
562
|
+
// different on-chain state.
|
|
563
|
+
cacheable: false,
|
|
560
564
|
async call(_input, context) {
|
|
561
565
|
if (hasNaviMcp(context)) {
|
|
562
566
|
const address = getWalletAddress(context);
|
|
@@ -850,6 +854,9 @@ var savingsInfoTool = buildTool({
|
|
|
850
854
|
inputSchema: z.object({}),
|
|
851
855
|
jsonSchema: { type: "object", properties: {}, required: [] },
|
|
852
856
|
isReadOnly: true,
|
|
857
|
+
// [v1.5.1] NAVI deposits change on save_deposit / withdraw / claim.
|
|
858
|
+
// Each call reflects a fresh on-chain snapshot — never dedupe.
|
|
859
|
+
cacheable: false,
|
|
853
860
|
async call(_input, context) {
|
|
854
861
|
if (context.positionFetcher && context.walletAddress) {
|
|
855
862
|
const sp = await context.positionFetcher(context.walletAddress);
|
|
@@ -910,6 +917,9 @@ var healthCheckTool = buildTool({
|
|
|
910
917
|
inputSchema: z.object({}),
|
|
911
918
|
jsonSchema: { type: "object", properties: {}, required: [] },
|
|
912
919
|
isReadOnly: true,
|
|
920
|
+
// [v1.5.1] Health factor changes on every borrow / repay / collateral
|
|
921
|
+
// movement and even passively as oracle prices update. Never dedupe.
|
|
922
|
+
cacheable: false,
|
|
913
923
|
async call(_input, context) {
|
|
914
924
|
if (context.positionFetcher && context.walletAddress) {
|
|
915
925
|
const sp = await context.positionFetcher(context.walletAddress);
|
|
@@ -1151,6 +1161,46 @@ var transactionHistoryTool = buildTool({
|
|
|
1151
1161
|
},
|
|
1152
1162
|
isReadOnly: true,
|
|
1153
1163
|
maxResultSizeChars: 8e3,
|
|
1164
|
+
// [v1.5.1] New transactions land continuously. Even with an explicit
|
|
1165
|
+
// `date` filter the dedupe is wrong post-write because the just-
|
|
1166
|
+
// executed write may now be in history. Never dedupe.
|
|
1167
|
+
cacheable: false,
|
|
1168
|
+
/**
|
|
1169
|
+
* [v1.5.2] Custom truncation that preserves the structured shape.
|
|
1170
|
+
*
|
|
1171
|
+
* The default `budgetToolResult` slices the JSON string at the byte
|
|
1172
|
+
* limit, appends a "[Truncated…]" note, and tries `JSON.parse` — which
|
|
1173
|
+
* always fails for sliced JSON, so the engine falls back to returning
|
|
1174
|
+
* the raw string. The frontend's `transaction_history` card renderer
|
|
1175
|
+
* then sees `typeof data !== 'object'` and bails, so the rich card
|
|
1176
|
+
* never renders even though the LLM has the full text.
|
|
1177
|
+
*
|
|
1178
|
+
* Strategy: progressively halve the `transactions` array until the
|
|
1179
|
+
* serialized payload fits, then stamp `_truncated: true` and the
|
|
1180
|
+
* original length so the LLM knows to recall with `limit` if it needs
|
|
1181
|
+
* older entries. Result is always valid JSON, always object-shaped.
|
|
1182
|
+
*/
|
|
1183
|
+
summarizeOnTruncate(serialized, maxChars) {
|
|
1184
|
+
let parsed;
|
|
1185
|
+
try {
|
|
1186
|
+
parsed = JSON.parse(serialized);
|
|
1187
|
+
} catch {
|
|
1188
|
+
return JSON.stringify({
|
|
1189
|
+
transactions: [],
|
|
1190
|
+
count: 0,
|
|
1191
|
+
_truncated: true,
|
|
1192
|
+
_note: "Result exceeded size budget and could not be summarized."
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
const original = Array.isArray(parsed.transactions) ? parsed.transactions : [];
|
|
1196
|
+
let trimmed = original.slice();
|
|
1197
|
+
let payload = JSON.stringify({ ...parsed, transactions: trimmed, _truncated: true, _originalCount: original.length });
|
|
1198
|
+
while (payload.length > maxChars && trimmed.length > 1) {
|
|
1199
|
+
trimmed = trimmed.slice(0, Math.max(1, Math.floor(trimmed.length / 2)));
|
|
1200
|
+
payload = JSON.stringify({ ...parsed, transactions: trimmed, _truncated: true, _originalCount: original.length });
|
|
1201
|
+
}
|
|
1202
|
+
return payload;
|
|
1203
|
+
},
|
|
1154
1204
|
async call(input, context) {
|
|
1155
1205
|
const limit = input.limit ?? 10;
|
|
1156
1206
|
const action = input.action;
|
|
@@ -3724,15 +3774,23 @@ function extractConversationText(messages) {
|
|
|
3724
3774
|
}
|
|
3725
3775
|
|
|
3726
3776
|
// src/compact/microcompact.ts
|
|
3727
|
-
function microcompact(messages) {
|
|
3777
|
+
function microcompact(messages, tools) {
|
|
3728
3778
|
const seen = /* @__PURE__ */ new Map();
|
|
3729
3779
|
let toolUseIndex = 0;
|
|
3730
3780
|
const toolUseInputs = /* @__PURE__ */ new Map();
|
|
3781
|
+
const cacheableByName = /* @__PURE__ */ new Map();
|
|
3782
|
+
if (tools) {
|
|
3783
|
+
for (const t of tools) {
|
|
3784
|
+
cacheableByName.set(t.name, t.cacheable ?? true);
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3731
3787
|
const dedupedToolUseIds = /* @__PURE__ */ new Set();
|
|
3788
|
+
const toolNameById = /* @__PURE__ */ new Map();
|
|
3732
3789
|
for (const msg of messages) {
|
|
3733
3790
|
for (const block of msg.content) {
|
|
3734
3791
|
if (block.type === "tool_use") {
|
|
3735
3792
|
toolUseInputs.set(block.id, `${block.name}:${stableStringify(block.input)}`);
|
|
3793
|
+
toolNameById.set(block.id, block.name);
|
|
3736
3794
|
}
|
|
3737
3795
|
}
|
|
3738
3796
|
}
|
|
@@ -3744,6 +3802,11 @@ function microcompact(messages) {
|
|
|
3744
3802
|
if (block.type !== "tool_result") return block;
|
|
3745
3803
|
const key = toolUseInputs.get(block.toolUseId);
|
|
3746
3804
|
if (!key) return block;
|
|
3805
|
+
const toolName = toolNameById.get(block.toolUseId);
|
|
3806
|
+
if (toolName && cacheableByName.get(toolName) === false) {
|
|
3807
|
+
toolUseIndex++;
|
|
3808
|
+
return block;
|
|
3809
|
+
}
|
|
3747
3810
|
toolUseIndex++;
|
|
3748
3811
|
const prior = seen.get(key);
|
|
3749
3812
|
if (prior && !block.isError) {
|
|
@@ -4442,7 +4505,7 @@ var QueryEngine = class {
|
|
|
4442
4505
|
};
|
|
4443
4506
|
const dispatcher = new EarlyToolDispatcher(this.tools, context);
|
|
4444
4507
|
try {
|
|
4445
|
-
const microcompacted = microcompact(this.messages);
|
|
4508
|
+
const microcompacted = microcompact(this.messages, this.tools);
|
|
4446
4509
|
this.messages = microcompacted;
|
|
4447
4510
|
for (const dedupedId of microcompacted.dedupedToolUseIds) {
|
|
4448
4511
|
yield {
|