@t2000/engine 0.46.6 → 0.46.7
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 +26 -0
- package/dist/index.js +81 -33
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -922,6 +922,32 @@ declare class QueryEngine {
|
|
|
922
922
|
reset(): void;
|
|
923
923
|
getGuardEvents(): readonly GuardEvent[];
|
|
924
924
|
loadMessages(messages: Message[]): void;
|
|
925
|
+
/**
|
|
926
|
+
* [v0.46.7] Run a read-only tool out-of-band, using the engine's tool
|
|
927
|
+
* registry and ToolContext. Used by hosts to deterministically pre-dispatch
|
|
928
|
+
* tools based on user-message intent (e.g. always call `balance_check` when
|
|
929
|
+
* the user says "what's my net worth?", regardless of whether the LLM would
|
|
930
|
+
* have otherwise re-called it).
|
|
931
|
+
*
|
|
932
|
+
* The host is responsible for:
|
|
933
|
+
* - Streaming the synthetic `tool_start` + `tool_result` events to the UI
|
|
934
|
+
* (so cards render as if the LLM had called the tool).
|
|
935
|
+
* - Appending matching `tool_use` + `tool_result` ContentBlocks to the
|
|
936
|
+
* engine's message history via `loadMessages([...getMessages(), ...synth])`
|
|
937
|
+
* BEFORE calling `submitMessage`, so the LLM sees the fresh data and
|
|
938
|
+
* doesn't re-call.
|
|
939
|
+
*
|
|
940
|
+
* Throws if the tool isn't registered, isn't read-only, or fails input
|
|
941
|
+
* validation. Tool execution errors are returned as `{ data, isError: true }`
|
|
942
|
+
* for the caller to handle (typically: skip the injection so the LLM falls
|
|
943
|
+
* back to its normal flow).
|
|
944
|
+
*/
|
|
945
|
+
invokeReadTool(toolName: string, input: unknown, options?: {
|
|
946
|
+
signal?: AbortSignal;
|
|
947
|
+
}): Promise<{
|
|
948
|
+
data: unknown;
|
|
949
|
+
isError: boolean;
|
|
950
|
+
}>;
|
|
925
951
|
setServerPositions(data: EngineConfig['serverPositions']): void;
|
|
926
952
|
getUsage(): CostSnapshot;
|
|
927
953
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1710,17 +1710,31 @@ async function fetchCatalog() {
|
|
|
1710
1710
|
catalogCache = { data, ts: Date.now() };
|
|
1711
1711
|
return data;
|
|
1712
1712
|
}
|
|
1713
|
+
function renderServices(catalog) {
|
|
1714
|
+
return catalog.map((s) => ({
|
|
1715
|
+
id: s.id,
|
|
1716
|
+
name: s.name,
|
|
1717
|
+
description: s.description,
|
|
1718
|
+
categories: s.categories,
|
|
1719
|
+
endpoints: s.endpoints.map((e) => ({
|
|
1720
|
+
url: `${MPP_GATEWAY2}/${s.id}${e.path}`,
|
|
1721
|
+
method: e.method,
|
|
1722
|
+
description: e.description,
|
|
1723
|
+
price: `$${e.price}`
|
|
1724
|
+
}))
|
|
1725
|
+
}));
|
|
1726
|
+
}
|
|
1713
1727
|
function matchesQuery(service, q) {
|
|
1714
1728
|
const lower = q.toLowerCase();
|
|
1715
1729
|
return service.id.toLowerCase().includes(lower) || service.name.toLowerCase().includes(lower) || service.description.toLowerCase().includes(lower) || service.categories.some((c) => c.toLowerCase().includes(lower)) || service.endpoints.some((e) => e.description.toLowerCase().includes(lower));
|
|
1716
1730
|
}
|
|
1717
1731
|
var mppServicesTool = buildTool({
|
|
1718
1732
|
name: "mpp_services",
|
|
1719
|
-
description: 'Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Use BEFORE calling pay_api.
|
|
1733
|
+
description: 'Discover available MPP gateway services. Returns service names, descriptions, endpoints with required parameters, and pricing. Use BEFORE calling pay_api. With no args, returns the FULL catalog as a single card (default behavior \u2014 covers "show me available MPP services", "what services exist", "show me all MPP services"). Use `query` to keyword-search a specific need ("translate", "weather", "postcard"). Use `category` to filter to one category. Use `mode: "summary"` only if you explicitly want a category-counts overview without the full list.',
|
|
1720
1734
|
inputSchema: z.object({
|
|
1721
|
-
query: z.string().optional().describe('Filter by keyword (e.g. "postcard", "translate", "weather").'),
|
|
1722
|
-
category: z.string().optional().describe('Filter by category exactly (e.g. "weather", "image").
|
|
1723
|
-
mode: z.enum(["summary", "full"]).optional().describe('"full" returns the entire catalog in
|
|
1735
|
+
query: z.string().optional().describe('Filter by keyword (e.g. "postcard", "translate", "weather"). Returns matching services in one card.'),
|
|
1736
|
+
category: z.string().optional().describe('Filter by category exactly (e.g. "weather", "image"). Use mode:"summary" first if you need to see the category list.'),
|
|
1737
|
+
mode: z.enum(["summary", "full"]).optional().describe('"full" (default) returns the entire catalog in one card. "summary" returns category counts only \u2014 use this only when the user explicitly asks for a category overview.')
|
|
1724
1738
|
}),
|
|
1725
1739
|
jsonSchema: {
|
|
1726
1740
|
type: "object",
|
|
@@ -1736,7 +1750,7 @@ var mppServicesTool = buildTool({
|
|
|
1736
1750
|
mode: {
|
|
1737
1751
|
type: "string",
|
|
1738
1752
|
enum: ["summary", "full"],
|
|
1739
|
-
description: '"full" returns the entire catalog in one card.
|
|
1753
|
+
description: '"full" (default) returns the entire catalog in one card. "summary" returns category counts only.'
|
|
1740
1754
|
}
|
|
1741
1755
|
},
|
|
1742
1756
|
required: []
|
|
@@ -1748,25 +1762,14 @@ var mppServicesTool = buildTool({
|
|
|
1748
1762
|
maxResultSizeChars: 12e3,
|
|
1749
1763
|
async call(input) {
|
|
1750
1764
|
const catalog = await fetchCatalog();
|
|
1751
|
-
if (input.mode
|
|
1752
|
-
const services2 = catalog
|
|
1753
|
-
id: s.id,
|
|
1754
|
-
name: s.name,
|
|
1755
|
-
description: s.description,
|
|
1756
|
-
categories: s.categories,
|
|
1757
|
-
endpoints: s.endpoints.map((e) => ({
|
|
1758
|
-
url: `${MPP_GATEWAY2}/${s.id}${e.path}`,
|
|
1759
|
-
method: e.method,
|
|
1760
|
-
description: e.description,
|
|
1761
|
-
price: `$${e.price}`
|
|
1762
|
-
}))
|
|
1763
|
-
}));
|
|
1765
|
+
if (input.mode !== "summary" && !input.query && !input.category) {
|
|
1766
|
+
const services2 = renderServices(catalog);
|
|
1764
1767
|
return {
|
|
1765
1768
|
data: { services: services2, total: services2.length, mode: "full" },
|
|
1766
1769
|
displayText: `Full MPP catalog: ${services2.length} services.`
|
|
1767
1770
|
};
|
|
1768
1771
|
}
|
|
1769
|
-
if (!input.query && !input.category) {
|
|
1772
|
+
if (input.mode === "summary" && !input.query && !input.category) {
|
|
1770
1773
|
const counts = /* @__PURE__ */ new Map();
|
|
1771
1774
|
for (const svc of catalog) {
|
|
1772
1775
|
for (const cat of svc.categories) {
|
|
@@ -1777,14 +1780,14 @@ var mppServicesTool = buildTool({
|
|
|
1777
1780
|
return {
|
|
1778
1781
|
data: {
|
|
1779
1782
|
_refine: {
|
|
1780
|
-
reason: '
|
|
1783
|
+
reason: 'Category summary (mode:"summary"). Re-call with a category or omit mode for the full catalog.',
|
|
1781
1784
|
suggestedParams: { category: categories[0]?.category ?? "weather" },
|
|
1782
1785
|
allModes: ["summary", "full"]
|
|
1783
1786
|
},
|
|
1784
1787
|
categories,
|
|
1785
1788
|
totalServices: catalog.length
|
|
1786
1789
|
},
|
|
1787
|
-
displayText: `${catalog.length} services across ${categories.length} categories
|
|
1790
|
+
displayText: `${catalog.length} services across ${categories.length} categories.`
|
|
1788
1791
|
};
|
|
1789
1792
|
}
|
|
1790
1793
|
let filtered = catalog;
|
|
@@ -1795,18 +1798,7 @@ var mppServicesTool = buildTool({
|
|
|
1795
1798
|
if (input.query) {
|
|
1796
1799
|
filtered = filtered.filter((s) => matchesQuery(s, input.query));
|
|
1797
1800
|
}
|
|
1798
|
-
const services = filtered
|
|
1799
|
-
id: s.id,
|
|
1800
|
-
name: s.name,
|
|
1801
|
-
description: s.description,
|
|
1802
|
-
categories: s.categories,
|
|
1803
|
-
endpoints: s.endpoints.map((e) => ({
|
|
1804
|
-
url: `${MPP_GATEWAY2}/${s.id}${e.path}`,
|
|
1805
|
-
method: e.method,
|
|
1806
|
-
description: e.description,
|
|
1807
|
-
price: `$${e.price}`
|
|
1808
|
-
}))
|
|
1809
|
-
}));
|
|
1801
|
+
const services = renderServices(filtered);
|
|
1810
1802
|
const filterDesc = [
|
|
1811
1803
|
input.query ? `query "${input.query}"` : null,
|
|
1812
1804
|
input.category ? `category "${input.category}"` : null
|
|
@@ -4595,6 +4587,62 @@ var QueryEngine = class {
|
|
|
4595
4587
|
loadMessages(messages) {
|
|
4596
4588
|
this.messages = [...messages];
|
|
4597
4589
|
}
|
|
4590
|
+
/**
|
|
4591
|
+
* [v0.46.7] Run a read-only tool out-of-band, using the engine's tool
|
|
4592
|
+
* registry and ToolContext. Used by hosts to deterministically pre-dispatch
|
|
4593
|
+
* tools based on user-message intent (e.g. always call `balance_check` when
|
|
4594
|
+
* the user says "what's my net worth?", regardless of whether the LLM would
|
|
4595
|
+
* have otherwise re-called it).
|
|
4596
|
+
*
|
|
4597
|
+
* The host is responsible for:
|
|
4598
|
+
* - Streaming the synthetic `tool_start` + `tool_result` events to the UI
|
|
4599
|
+
* (so cards render as if the LLM had called the tool).
|
|
4600
|
+
* - Appending matching `tool_use` + `tool_result` ContentBlocks to the
|
|
4601
|
+
* engine's message history via `loadMessages([...getMessages(), ...synth])`
|
|
4602
|
+
* BEFORE calling `submitMessage`, so the LLM sees the fresh data and
|
|
4603
|
+
* doesn't re-call.
|
|
4604
|
+
*
|
|
4605
|
+
* Throws if the tool isn't registered, isn't read-only, or fails input
|
|
4606
|
+
* validation. Tool execution errors are returned as `{ data, isError: true }`
|
|
4607
|
+
* for the caller to handle (typically: skip the injection so the LLM falls
|
|
4608
|
+
* back to its normal flow).
|
|
4609
|
+
*/
|
|
4610
|
+
async invokeReadTool(toolName, input, options = {}) {
|
|
4611
|
+
const tool = findTool(this.tools, toolName);
|
|
4612
|
+
if (!tool) throw new Error(`invokeReadTool: tool not found: ${toolName}`);
|
|
4613
|
+
if (!tool.isReadOnly) {
|
|
4614
|
+
throw new Error(`invokeReadTool: tool is not read-only: ${toolName} (write tools must go through the permission gate)`);
|
|
4615
|
+
}
|
|
4616
|
+
const parsed = tool.inputSchema.safeParse(input);
|
|
4617
|
+
if (!parsed.success) {
|
|
4618
|
+
throw new Error(
|
|
4619
|
+
`invokeReadTool: invalid input for ${toolName}: ${parsed.error.issues.map((i) => i.message).join(", ")}`
|
|
4620
|
+
);
|
|
4621
|
+
}
|
|
4622
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
4623
|
+
const context = {
|
|
4624
|
+
agent: this.agent,
|
|
4625
|
+
mcpManager: this.mcpManager,
|
|
4626
|
+
walletAddress: this.walletAddress,
|
|
4627
|
+
suiRpcUrl: this.suiRpcUrl,
|
|
4628
|
+
serverPositions: this.serverPositions,
|
|
4629
|
+
positionFetcher: this.positionFetcher,
|
|
4630
|
+
env: this.env,
|
|
4631
|
+
signal,
|
|
4632
|
+
priceCache: this.priceCache,
|
|
4633
|
+
permissionConfig: this.permissionConfig,
|
|
4634
|
+
sessionSpendUsd: this.sessionSpendUsd
|
|
4635
|
+
};
|
|
4636
|
+
try {
|
|
4637
|
+
const result = await tool.call(parsed.data, context);
|
|
4638
|
+
return { data: result.data, isError: false };
|
|
4639
|
+
} catch (err) {
|
|
4640
|
+
return {
|
|
4641
|
+
data: { error: err instanceof Error ? err.message : "Tool execution failed" },
|
|
4642
|
+
isError: true
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4598
4646
|
setServerPositions(data) {
|
|
4599
4647
|
this.serverPositions = data;
|
|
4600
4648
|
}
|