@t2000/engine 0.32.0 → 0.33.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 +148 -28
- package/dist/index.js +366 -116
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { resolveSymbol, getDecimalsForCoinType, assertAllowedAsset, getSwapQuote, SUI_TYPE } from '@t2000/sdk';
|
|
3
|
+
import { readdirSync, readFileSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
3
6
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
4
7
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
5
8
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
@@ -3941,6 +3944,187 @@ function extractConversationText(messages) {
|
|
|
3941
3944
|
};
|
|
3942
3945
|
}
|
|
3943
3946
|
|
|
3947
|
+
// src/context.ts
|
|
3948
|
+
var CHARS_PER_TOKEN = 4;
|
|
3949
|
+
var DEFAULT_CONTEXT_LIMIT = 2e5;
|
|
3950
|
+
function estimateTokens(messages) {
|
|
3951
|
+
let chars = 0;
|
|
3952
|
+
for (const msg of messages) {
|
|
3953
|
+
for (const block of msg.content) {
|
|
3954
|
+
chars += blockCharCount(block);
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
return Math.ceil(chars / CHARS_PER_TOKEN);
|
|
3958
|
+
}
|
|
3959
|
+
function blockCharCount(block) {
|
|
3960
|
+
switch (block.type) {
|
|
3961
|
+
case "text":
|
|
3962
|
+
return block.text.length;
|
|
3963
|
+
case "thinking":
|
|
3964
|
+
return block.thinking.length;
|
|
3965
|
+
case "redacted_thinking":
|
|
3966
|
+
return block.data.length;
|
|
3967
|
+
case "tool_use":
|
|
3968
|
+
return block.name.length + JSON.stringify(block.input).length;
|
|
3969
|
+
case "tool_result":
|
|
3970
|
+
return block.content.length;
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
var ContextBudget = class {
|
|
3974
|
+
estimatedTokens = 0;
|
|
3975
|
+
contextLimit;
|
|
3976
|
+
compactThreshold;
|
|
3977
|
+
warnThreshold;
|
|
3978
|
+
constructor(config = {}) {
|
|
3979
|
+
this.contextLimit = config.contextLimit ?? DEFAULT_CONTEXT_LIMIT;
|
|
3980
|
+
this.compactThreshold = config.compactThreshold ?? 0.85;
|
|
3981
|
+
this.warnThreshold = config.warnThreshold ?? 0.7;
|
|
3982
|
+
}
|
|
3983
|
+
/** Update with actual input_tokens from the API usage event. */
|
|
3984
|
+
update(inputTokens) {
|
|
3985
|
+
this.estimatedTokens = inputTokens;
|
|
3986
|
+
}
|
|
3987
|
+
/** True when the session should be compacted (at 85% of context limit). */
|
|
3988
|
+
shouldCompact() {
|
|
3989
|
+
return this.estimatedTokens >= this.contextLimit * this.compactThreshold;
|
|
3990
|
+
}
|
|
3991
|
+
/** True when nearing the limit (at 70% of context limit). */
|
|
3992
|
+
shouldWarn() {
|
|
3993
|
+
return this.estimatedTokens >= this.contextLimit * this.warnThreshold;
|
|
3994
|
+
}
|
|
3995
|
+
/** Current token count. */
|
|
3996
|
+
get tokens() {
|
|
3997
|
+
return this.estimatedTokens;
|
|
3998
|
+
}
|
|
3999
|
+
/** Remaining tokens before compaction triggers. */
|
|
4000
|
+
get remaining() {
|
|
4001
|
+
return Math.max(0, Math.floor(this.contextLimit * this.compactThreshold) - this.estimatedTokens);
|
|
4002
|
+
}
|
|
4003
|
+
/** Usage ratio (0..1). */
|
|
4004
|
+
get usage() {
|
|
4005
|
+
return this.estimatedTokens / this.contextLimit;
|
|
4006
|
+
}
|
|
4007
|
+
reset() {
|
|
4008
|
+
this.estimatedTokens = 0;
|
|
4009
|
+
}
|
|
4010
|
+
};
|
|
4011
|
+
async function compactMessages(messages, opts = {}) {
|
|
4012
|
+
const maxTokens = opts.maxTokens ?? 1e5;
|
|
4013
|
+
const keepRecent = opts.keepRecentCount ?? 8;
|
|
4014
|
+
const systemTokens = opts.systemPromptTokens ?? 500;
|
|
4015
|
+
const budget = maxTokens - systemTokens;
|
|
4016
|
+
if (messages.length === 0) return [];
|
|
4017
|
+
const mutable = messages.map((m) => ({
|
|
4018
|
+
role: m.role,
|
|
4019
|
+
content: m.content.map((b) => ({ ...b }))
|
|
4020
|
+
}));
|
|
4021
|
+
if (estimateTokens(mutable) <= budget) return mutable;
|
|
4022
|
+
const splitIdx = Math.max(0, mutable.length - keepRecent);
|
|
4023
|
+
const oldMessages = mutable.slice(0, splitIdx);
|
|
4024
|
+
const recent = mutable.slice(splitIdx);
|
|
4025
|
+
if (opts.summarizer && oldMessages.length > 0) {
|
|
4026
|
+
const strippedOld = stripThinkingBlocks(oldMessages);
|
|
4027
|
+
try {
|
|
4028
|
+
const summary = await opts.summarizer(strippedOld);
|
|
4029
|
+
const summaryMessages = [
|
|
4030
|
+
{ role: "user", content: [{ type: "text", text: `[Session summary: ${summary}]` }] },
|
|
4031
|
+
{ role: "assistant", content: [{ type: "text", text: "Understood. I have the context from our earlier conversation." }] }
|
|
4032
|
+
];
|
|
4033
|
+
const withSummary = [...summaryMessages, ...recent];
|
|
4034
|
+
if (estimateTokens(withSummary) <= budget) return sanitizeMessages(withSummary);
|
|
4035
|
+
} catch {
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
for (let i = 0; i < splitIdx; i++) {
|
|
4039
|
+
mutable[i].content = mutable[i].content.map((block) => {
|
|
4040
|
+
if (block.type === "tool_result" && block.content.length > 200) {
|
|
4041
|
+
return {
|
|
4042
|
+
...block,
|
|
4043
|
+
content: truncateToolResult(block.content)
|
|
4044
|
+
};
|
|
4045
|
+
}
|
|
4046
|
+
return block;
|
|
4047
|
+
});
|
|
4048
|
+
}
|
|
4049
|
+
for (let i = 0; i < splitIdx; i++) {
|
|
4050
|
+
mutable[i].content = mutable[i].content.filter(
|
|
4051
|
+
(b) => b.type !== "thinking" && b.type !== "redacted_thinking"
|
|
4052
|
+
);
|
|
4053
|
+
}
|
|
4054
|
+
if (estimateTokens(mutable) <= budget) return mutable;
|
|
4055
|
+
const first = mutable[0];
|
|
4056
|
+
const recentFromMutable = mutable.slice(splitIdx);
|
|
4057
|
+
const oldSection = mutable.slice(1, splitIdx);
|
|
4058
|
+
while (oldSection.length > 0 && estimateTokens([first, ...oldSection, ...recentFromMutable]) > budget) {
|
|
4059
|
+
oldSection.shift();
|
|
4060
|
+
}
|
|
4061
|
+
const compacted = [first, ...oldSection, ...recentFromMutable];
|
|
4062
|
+
if (estimateTokens(compacted) > budget) {
|
|
4063
|
+
for (const msg of compacted) {
|
|
4064
|
+
msg.content = msg.content.map((block) => {
|
|
4065
|
+
if (block.type === "tool_result" && block.content.length > 100) {
|
|
4066
|
+
return { ...block, content: truncateToolResult(block.content) };
|
|
4067
|
+
}
|
|
4068
|
+
return block;
|
|
4069
|
+
});
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
return sanitizeMessages(compacted);
|
|
4073
|
+
}
|
|
4074
|
+
function stripThinkingBlocks(messages) {
|
|
4075
|
+
return messages.map((m) => ({
|
|
4076
|
+
...m,
|
|
4077
|
+
content: m.content.filter(
|
|
4078
|
+
(b) => b.type !== "thinking" && b.type !== "redacted_thinking"
|
|
4079
|
+
)
|
|
4080
|
+
})).filter((m) => m.content.length > 0);
|
|
4081
|
+
}
|
|
4082
|
+
function sanitizeMessages(messages) {
|
|
4083
|
+
const toolUseIds = /* @__PURE__ */ new Set();
|
|
4084
|
+
const toolResultIds = /* @__PURE__ */ new Set();
|
|
4085
|
+
for (const msg of messages) {
|
|
4086
|
+
for (const block of msg.content) {
|
|
4087
|
+
if (block.type === "tool_use") toolUseIds.add(block.id);
|
|
4088
|
+
if (block.type === "tool_result") toolResultIds.add(block.toolUseId);
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
return messages.map((msg) => {
|
|
4092
|
+
const filtered = msg.content.filter((block) => {
|
|
4093
|
+
if (block.type === "tool_result") return toolUseIds.has(block.toolUseId);
|
|
4094
|
+
if (block.type === "tool_use") return toolResultIds.has(block.id);
|
|
4095
|
+
return true;
|
|
4096
|
+
});
|
|
4097
|
+
if (filtered.length === 0) return null;
|
|
4098
|
+
return { ...msg, content: filtered };
|
|
4099
|
+
}).filter((m) => m !== null);
|
|
4100
|
+
}
|
|
4101
|
+
function truncateToolResult(content) {
|
|
4102
|
+
try {
|
|
4103
|
+
const parsed = JSON.parse(content);
|
|
4104
|
+
if (parsed.error) {
|
|
4105
|
+
return JSON.stringify({ error: parsed.error });
|
|
4106
|
+
}
|
|
4107
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
4108
|
+
const summary = {};
|
|
4109
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
4110
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
4111
|
+
summary[key] = value;
|
|
4112
|
+
} else if (typeof value === "string") {
|
|
4113
|
+
summary[key] = value.length > 50 ? value.slice(0, 50) + "\u2026" : value;
|
|
4114
|
+
} else if (Array.isArray(value)) {
|
|
4115
|
+
summary[key] = `[${value.length} items]`;
|
|
4116
|
+
} else {
|
|
4117
|
+
summary[key] = "{\u2026}";
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
return JSON.stringify(summary);
|
|
4121
|
+
}
|
|
4122
|
+
return content.slice(0, 100);
|
|
4123
|
+
} catch {
|
|
4124
|
+
return content.slice(0, 100);
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
|
|
3944
4128
|
// src/engine.ts
|
|
3945
4129
|
var DEFAULT_MAX_TURNS = 10;
|
|
3946
4130
|
var DEFAULT_MAX_TOKENS = 4096;
|
|
@@ -3966,6 +4150,10 @@ var QueryEngine = class {
|
|
|
3966
4150
|
costTracker;
|
|
3967
4151
|
guardConfig;
|
|
3968
4152
|
guardState;
|
|
4153
|
+
recipes;
|
|
4154
|
+
contextBudget;
|
|
4155
|
+
contextSummarizer;
|
|
4156
|
+
matchedRecipe = null;
|
|
3969
4157
|
messages = [];
|
|
3970
4158
|
abortController = null;
|
|
3971
4159
|
guardEvents = [];
|
|
@@ -3989,6 +4177,9 @@ var QueryEngine = class {
|
|
|
3989
4177
|
this.costTracker = new CostTracker(config.costTracker);
|
|
3990
4178
|
this.guardConfig = config.guards;
|
|
3991
4179
|
this.guardState = createGuardRunnerState();
|
|
4180
|
+
this.recipes = config.recipes;
|
|
4181
|
+
this.contextBudget = new ContextBudget(config.contextBudget);
|
|
4182
|
+
this.contextSummarizer = config.contextSummarizer;
|
|
3992
4183
|
this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
|
|
3993
4184
|
}
|
|
3994
4185
|
/**
|
|
@@ -4006,6 +4197,7 @@ var QueryEngine = class {
|
|
|
4006
4197
|
}
|
|
4007
4198
|
this.abortController = new AbortController();
|
|
4008
4199
|
const signal = this.abortController.signal;
|
|
4200
|
+
this.matchedRecipe = this.recipes?.match(prompt) ?? null;
|
|
4009
4201
|
this.messages.push({
|
|
4010
4202
|
role: "user",
|
|
4011
4203
|
content: [{ type: "text", text: prompt }]
|
|
@@ -4064,10 +4256,18 @@ var QueryEngine = class {
|
|
|
4064
4256
|
getMessages() {
|
|
4065
4257
|
return this.messages;
|
|
4066
4258
|
}
|
|
4259
|
+
getMatchedRecipe() {
|
|
4260
|
+
return this.matchedRecipe;
|
|
4261
|
+
}
|
|
4262
|
+
getContextBudget() {
|
|
4263
|
+
return this.contextBudget;
|
|
4264
|
+
}
|
|
4067
4265
|
reset() {
|
|
4068
4266
|
this.messages = [];
|
|
4069
4267
|
this.costTracker.reset();
|
|
4268
|
+
this.contextBudget.reset();
|
|
4070
4269
|
this.guardEvents = [];
|
|
4270
|
+
this.matchedRecipe = null;
|
|
4071
4271
|
}
|
|
4072
4272
|
getGuardEvents() {
|
|
4073
4273
|
return this.guardEvents;
|
|
@@ -4117,6 +4317,13 @@ var QueryEngine = class {
|
|
|
4117
4317
|
pendingToolCalls: []
|
|
4118
4318
|
};
|
|
4119
4319
|
try {
|
|
4320
|
+
if (this.contextBudget.shouldCompact()) {
|
|
4321
|
+
this.messages = await compactMessages(this.messages, {
|
|
4322
|
+
maxTokens: 1e5,
|
|
4323
|
+
keepRecentCount: 8,
|
|
4324
|
+
summarizer: this.contextSummarizer
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4120
4327
|
this.messages = validateHistory(this.messages);
|
|
4121
4328
|
if (process.env.NODE_ENV !== "test") {
|
|
4122
4329
|
const summary = this.messages.map((m, idx) => {
|
|
@@ -4134,9 +4341,23 @@ ${summary.join("\n")}`);
|
|
|
4134
4341
|
}
|
|
4135
4342
|
const thinkingEnabled = this.thinking && this.thinking.type !== "disabled";
|
|
4136
4343
|
const effectiveToolChoice = thinkingEnabled ? applyToolChoice && turns === 1 ? "auto" : void 0 : applyToolChoice && turns === 1 ? this.toolChoice : void 0;
|
|
4344
|
+
let effectivePrompt = this.systemPrompt;
|
|
4345
|
+
if (this.matchedRecipe && this.recipes) {
|
|
4346
|
+
const recipeCtx = this.recipes.toPromptContext(this.matchedRecipe);
|
|
4347
|
+
if (typeof effectivePrompt === "string") {
|
|
4348
|
+
effectivePrompt = `${effectivePrompt}
|
|
4349
|
+
|
|
4350
|
+
${recipeCtx}`;
|
|
4351
|
+
} else if (Array.isArray(effectivePrompt)) {
|
|
4352
|
+
effectivePrompt = [
|
|
4353
|
+
...effectivePrompt,
|
|
4354
|
+
{ type: "text", text: recipeCtx }
|
|
4355
|
+
];
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4137
4358
|
const stream = this.provider.chat({
|
|
4138
4359
|
messages: this.messages,
|
|
4139
|
-
systemPrompt:
|
|
4360
|
+
systemPrompt: effectivePrompt,
|
|
4140
4361
|
tools: toolDefs,
|
|
4141
4362
|
model: this.model,
|
|
4142
4363
|
maxTokens: this.maxTokens,
|
|
@@ -4418,6 +4639,7 @@ ${summary.join("\n")}`);
|
|
|
4418
4639
|
event.cacheReadTokens,
|
|
4419
4640
|
event.cacheWriteTokens
|
|
4420
4641
|
);
|
|
4642
|
+
this.contextBudget.update(event.inputTokens);
|
|
4421
4643
|
yield {
|
|
4422
4644
|
type: "usage",
|
|
4423
4645
|
inputTokens: event.inputTokens,
|
|
@@ -4634,6 +4856,148 @@ var MemorySessionStore = class {
|
|
|
4634
4856
|
}
|
|
4635
4857
|
}
|
|
4636
4858
|
};
|
|
4859
|
+
var StepRequirementSchema = z.object({
|
|
4860
|
+
step: z.string().optional(),
|
|
4861
|
+
field: z.string().optional(),
|
|
4862
|
+
confirmation: z.boolean().optional()
|
|
4863
|
+
});
|
|
4864
|
+
var OnErrorSchema = z.object({
|
|
4865
|
+
action: z.enum(["abort", "refuse", "report", "retry"]),
|
|
4866
|
+
message: z.string(),
|
|
4867
|
+
suggest: z.string().optional()
|
|
4868
|
+
});
|
|
4869
|
+
var StepSchema = z.object({
|
|
4870
|
+
name: z.string().min(1),
|
|
4871
|
+
tool: z.string().optional(),
|
|
4872
|
+
service: z.string().optional(),
|
|
4873
|
+
purpose: z.string().min(1),
|
|
4874
|
+
cost: z.string().optional(),
|
|
4875
|
+
output: z.object({ type: z.string(), key: z.string() }).optional(),
|
|
4876
|
+
gate: z.enum(["none", "preview", "review", "estimate"]).optional(),
|
|
4877
|
+
gate_prompt: z.string().optional(),
|
|
4878
|
+
requires: z.array(StepRequirementSchema).optional(),
|
|
4879
|
+
rules: z.array(z.string()).optional(),
|
|
4880
|
+
condition: z.string().optional(),
|
|
4881
|
+
notes: z.string().optional(),
|
|
4882
|
+
flags: z.record(z.unknown()).optional(),
|
|
4883
|
+
on_error: OnErrorSchema.optional(),
|
|
4884
|
+
input_template: z.record(z.string()).optional(),
|
|
4885
|
+
cost_per_unit: z.string().optional()
|
|
4886
|
+
});
|
|
4887
|
+
var RecipeSchema = z.object({
|
|
4888
|
+
name: z.string().min(1),
|
|
4889
|
+
description: z.string().min(1),
|
|
4890
|
+
triggers: z.array(z.string().min(1)).min(1),
|
|
4891
|
+
services: z.array(z.string()).optional(),
|
|
4892
|
+
prerequisites: z.array(z.object({ field: z.string(), prompt: z.string() })).optional(),
|
|
4893
|
+
steps: z.array(StepSchema).min(1)
|
|
4894
|
+
}).refine(
|
|
4895
|
+
(r) => {
|
|
4896
|
+
const names = r.steps.map((s) => s.name);
|
|
4897
|
+
return new Set(names).size === names.length;
|
|
4898
|
+
},
|
|
4899
|
+
{ message: "Step names must be unique within a recipe" }
|
|
4900
|
+
);
|
|
4901
|
+
function loadRecipes(yamlDir) {
|
|
4902
|
+
const files = readdirSync(yamlDir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
4903
|
+
const recipes = [];
|
|
4904
|
+
for (const file of files) {
|
|
4905
|
+
const content = readFileSync(join(yamlDir, file), "utf-8");
|
|
4906
|
+
const raw = yaml.load(content);
|
|
4907
|
+
const parsed = RecipeSchema.parse(raw);
|
|
4908
|
+
recipes.push(parsed);
|
|
4909
|
+
}
|
|
4910
|
+
return recipes;
|
|
4911
|
+
}
|
|
4912
|
+
function parseRecipe(yamlContent) {
|
|
4913
|
+
const raw = yaml.load(yamlContent);
|
|
4914
|
+
return RecipeSchema.parse(raw);
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
// src/recipes/registry.ts
|
|
4918
|
+
var RecipeRegistry = class {
|
|
4919
|
+
recipes = [];
|
|
4920
|
+
/** Load all recipes from a directory of YAML files. */
|
|
4921
|
+
loadDir(yamlDir) {
|
|
4922
|
+
this.recipes.push(...loadRecipes(yamlDir));
|
|
4923
|
+
}
|
|
4924
|
+
/** Register a single recipe from a YAML string. */
|
|
4925
|
+
loadYaml(yamlContent) {
|
|
4926
|
+
this.recipes.push(parseRecipe(yamlContent));
|
|
4927
|
+
}
|
|
4928
|
+
/** Register a pre-parsed Recipe object. */
|
|
4929
|
+
register(recipe) {
|
|
4930
|
+
this.recipes.push(recipe);
|
|
4931
|
+
}
|
|
4932
|
+
/** All loaded recipes. */
|
|
4933
|
+
all() {
|
|
4934
|
+
return this.recipes;
|
|
4935
|
+
}
|
|
4936
|
+
/**
|
|
4937
|
+
* Match a user message to the most specific recipe.
|
|
4938
|
+
* Longest trigger phrase match wins. Returns null if no match.
|
|
4939
|
+
*/
|
|
4940
|
+
match(userMessage) {
|
|
4941
|
+
const normalized = userMessage.toLowerCase().trim();
|
|
4942
|
+
let best = null;
|
|
4943
|
+
let bestLength = 0;
|
|
4944
|
+
for (const recipe of this.recipes) {
|
|
4945
|
+
for (const trigger of recipe.triggers) {
|
|
4946
|
+
const triggerLower = trigger.toLowerCase();
|
|
4947
|
+
if (normalized.includes(triggerLower) && triggerLower.length > bestLength) {
|
|
4948
|
+
best = recipe;
|
|
4949
|
+
bestLength = triggerLower.length;
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4953
|
+
return best;
|
|
4954
|
+
}
|
|
4955
|
+
/**
|
|
4956
|
+
* Format a matched recipe as a compact context block for the system prompt.
|
|
4957
|
+
* Injected dynamically — only when the recipe matches.
|
|
4958
|
+
*/
|
|
4959
|
+
toPromptContext(recipe) {
|
|
4960
|
+
const lines = [
|
|
4961
|
+
`## Active Recipe: ${recipe.name}`,
|
|
4962
|
+
recipe.description,
|
|
4963
|
+
"Follow these steps:"
|
|
4964
|
+
];
|
|
4965
|
+
for (let i = 0; i < recipe.steps.length; i++) {
|
|
4966
|
+
const step = recipe.steps[i];
|
|
4967
|
+
const num = i + 1;
|
|
4968
|
+
const toolNote = step.tool ? ` \u2192 ${step.tool}` : "";
|
|
4969
|
+
const serviceNote = step.service ? ` (${step.service})` : "";
|
|
4970
|
+
const costNote = step.cost ? ` \u2014 ${step.cost}` : "";
|
|
4971
|
+
const gateNote = step.gate && step.gate !== "none" ? ` [GATE: ${step.gate}]` : "";
|
|
4972
|
+
let line = `${num}. ${step.name}${toolNote}${serviceNote}${costNote}${gateNote}`;
|
|
4973
|
+
if (step.gate_prompt) {
|
|
4974
|
+
line += ` \u2014 "${step.gate_prompt}"`;
|
|
4975
|
+
}
|
|
4976
|
+
lines.push(line);
|
|
4977
|
+
if (step.rules?.length) {
|
|
4978
|
+
for (const rule of step.rules) {
|
|
4979
|
+
lines.push(` - ${rule}`);
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
if (step.notes) {
|
|
4983
|
+
lines.push(` Note: ${step.notes}`);
|
|
4984
|
+
}
|
|
4985
|
+
if (step.on_error) {
|
|
4986
|
+
lines.push(` On error: ${step.on_error.action} \u2014 ${step.on_error.message}`);
|
|
4987
|
+
}
|
|
4988
|
+
if (step.condition) {
|
|
4989
|
+
lines.push(` Condition: ${step.condition}`);
|
|
4990
|
+
}
|
|
4991
|
+
}
|
|
4992
|
+
if (recipe.prerequisites?.length) {
|
|
4993
|
+
lines.push("Prerequisites (ask before starting):");
|
|
4994
|
+
for (const pre of recipe.prerequisites) {
|
|
4995
|
+
lines.push(`- ${pre.field}: "${pre.prompt}"`);
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
return lines.join("\n");
|
|
4999
|
+
}
|
|
5000
|
+
};
|
|
4637
5001
|
|
|
4638
5002
|
// src/classify-effort.ts
|
|
4639
5003
|
function classifyEffort(model, userMessage, matchedRecipe, sessionWriteCount) {
|
|
@@ -4794,120 +5158,6 @@ function buildStateContext(state) {
|
|
|
4794
5158
|
}
|
|
4795
5159
|
}
|
|
4796
5160
|
|
|
4797
|
-
// src/context.ts
|
|
4798
|
-
var CHARS_PER_TOKEN = 4;
|
|
4799
|
-
function estimateTokens(messages) {
|
|
4800
|
-
let chars = 0;
|
|
4801
|
-
for (const msg of messages) {
|
|
4802
|
-
for (const block of msg.content) {
|
|
4803
|
-
chars += blockCharCount(block);
|
|
4804
|
-
}
|
|
4805
|
-
}
|
|
4806
|
-
return Math.ceil(chars / CHARS_PER_TOKEN);
|
|
4807
|
-
}
|
|
4808
|
-
function blockCharCount(block) {
|
|
4809
|
-
switch (block.type) {
|
|
4810
|
-
case "text":
|
|
4811
|
-
return block.text.length;
|
|
4812
|
-
case "thinking":
|
|
4813
|
-
return block.thinking.length;
|
|
4814
|
-
case "redacted_thinking":
|
|
4815
|
-
return block.data.length;
|
|
4816
|
-
case "tool_use":
|
|
4817
|
-
return block.name.length + JSON.stringify(block.input).length;
|
|
4818
|
-
case "tool_result":
|
|
4819
|
-
return block.content.length;
|
|
4820
|
-
}
|
|
4821
|
-
}
|
|
4822
|
-
function compactMessages(messages, opts = {}) {
|
|
4823
|
-
const maxTokens = opts.maxTokens ?? 1e5;
|
|
4824
|
-
const keepRecent = opts.keepRecentCount ?? 6;
|
|
4825
|
-
const systemTokens = opts.systemPromptTokens ?? 500;
|
|
4826
|
-
const budget = maxTokens - systemTokens;
|
|
4827
|
-
if (messages.length === 0) return [];
|
|
4828
|
-
const mutable = messages.map((m) => ({
|
|
4829
|
-
role: m.role,
|
|
4830
|
-
content: m.content.map((b) => ({ ...b }))
|
|
4831
|
-
}));
|
|
4832
|
-
if (estimateTokens(mutable) <= budget) return mutable;
|
|
4833
|
-
const splitIdx = Math.max(0, mutable.length - keepRecent);
|
|
4834
|
-
for (let i = 0; i < splitIdx; i++) {
|
|
4835
|
-
mutable[i].content = mutable[i].content.map((block) => {
|
|
4836
|
-
if (block.type === "tool_result" && block.content.length > 200) {
|
|
4837
|
-
return {
|
|
4838
|
-
...block,
|
|
4839
|
-
content: truncateToolResult(block.content)
|
|
4840
|
-
};
|
|
4841
|
-
}
|
|
4842
|
-
return block;
|
|
4843
|
-
});
|
|
4844
|
-
}
|
|
4845
|
-
if (estimateTokens(mutable) <= budget) return mutable;
|
|
4846
|
-
const first = mutable[0];
|
|
4847
|
-
const recent = mutable.slice(splitIdx);
|
|
4848
|
-
const oldSection = mutable.slice(1, splitIdx);
|
|
4849
|
-
while (oldSection.length > 0 && estimateTokens([first, ...oldSection, ...recent]) > budget) {
|
|
4850
|
-
oldSection.shift();
|
|
4851
|
-
}
|
|
4852
|
-
const compacted = [first, ...oldSection, ...recent];
|
|
4853
|
-
if (estimateTokens(compacted) > budget) {
|
|
4854
|
-
for (const msg of compacted) {
|
|
4855
|
-
msg.content = msg.content.map((block) => {
|
|
4856
|
-
if (block.type === "tool_result" && block.content.length > 100) {
|
|
4857
|
-
return { ...block, content: truncateToolResult(block.content) };
|
|
4858
|
-
}
|
|
4859
|
-
return block;
|
|
4860
|
-
});
|
|
4861
|
-
}
|
|
4862
|
-
}
|
|
4863
|
-
return sanitizeMessages(compacted);
|
|
4864
|
-
}
|
|
4865
|
-
function sanitizeMessages(messages) {
|
|
4866
|
-
const toolUseIds = /* @__PURE__ */ new Set();
|
|
4867
|
-
const toolResultIds = /* @__PURE__ */ new Set();
|
|
4868
|
-
for (const msg of messages) {
|
|
4869
|
-
for (const block of msg.content) {
|
|
4870
|
-
if (block.type === "tool_use") toolUseIds.add(block.id);
|
|
4871
|
-
if (block.type === "tool_result") toolResultIds.add(block.toolUseId);
|
|
4872
|
-
}
|
|
4873
|
-
}
|
|
4874
|
-
return messages.map((msg) => {
|
|
4875
|
-
const filtered = msg.content.filter((block) => {
|
|
4876
|
-
if (block.type === "tool_result") return toolUseIds.has(block.toolUseId);
|
|
4877
|
-
if (block.type === "tool_use") return toolResultIds.has(block.id);
|
|
4878
|
-
return true;
|
|
4879
|
-
});
|
|
4880
|
-
if (filtered.length === 0) return null;
|
|
4881
|
-
return { ...msg, content: filtered };
|
|
4882
|
-
}).filter((m) => m !== null);
|
|
4883
|
-
}
|
|
4884
|
-
function truncateToolResult(content) {
|
|
4885
|
-
try {
|
|
4886
|
-
const parsed = JSON.parse(content);
|
|
4887
|
-
if (parsed.error) {
|
|
4888
|
-
return JSON.stringify({ error: parsed.error });
|
|
4889
|
-
}
|
|
4890
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
4891
|
-
const summary = {};
|
|
4892
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
4893
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
4894
|
-
summary[key] = value;
|
|
4895
|
-
} else if (typeof value === "string") {
|
|
4896
|
-
summary[key] = value.length > 50 ? value.slice(0, 50) + "\u2026" : value;
|
|
4897
|
-
} else if (Array.isArray(value)) {
|
|
4898
|
-
summary[key] = `[${value.length} items]`;
|
|
4899
|
-
} else {
|
|
4900
|
-
summary[key] = "{\u2026}";
|
|
4901
|
-
}
|
|
4902
|
-
}
|
|
4903
|
-
return JSON.stringify(summary);
|
|
4904
|
-
}
|
|
4905
|
-
return content.slice(0, 100);
|
|
4906
|
-
} catch {
|
|
4907
|
-
return content.slice(0, 100);
|
|
4908
|
-
}
|
|
4909
|
-
}
|
|
4910
|
-
|
|
4911
5161
|
// src/mcp.ts
|
|
4912
5162
|
function buildMcpTools(context, tools) {
|
|
4913
5163
|
const engineTools = tools ?? getDefaultTools();
|
|
@@ -5475,6 +5725,6 @@ function sanitizeAnthropicMessages(messages) {
|
|
|
5475
5725
|
return merged;
|
|
5476
5726
|
}
|
|
5477
5727
|
|
|
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 };
|
|
5728
|
+
export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_SYSTEM_PROMPT, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, balanceCheckTool, borrowTool, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, classifyEffort, clearPriceCache, compactMessages, createGuardRunnerState, defillamaChainTvlTool, defillamaPriceChangeTool, defillamaProtocolFeesTool, defillamaProtocolInfoTool, defillamaSuiProtocolsTool, defillamaTokenPricesTool, defillamaYieldPoolsTool, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getToolFlags, getWalletAddress, guardArtifactPreview, guardStaleData, hasNaviMcp, healthCheckTool, loadRecipes, mppServicesTool, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
|
|
5479
5729
|
//# sourceMappingURL=index.js.map
|
|
5480
5730
|
//# sourceMappingURL=index.js.map
|