@burdenoff/fe-libs 2026.1027.8 → 2026.1027.10
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/chrome/ShortcutHelpDialog.js +16 -10
- package/dist/shared/agent-tools/adapters/assistant.d.ts +15 -2
- package/dist/shared/agent-tools/adapters/assistant.js +18 -15
- package/dist/shared/agent-tools/shell/shellTools.js +2 -0
- package/dist/shared/agent-tools/types.d.ts +7 -0
- package/dist/shared/assistant/ui/AssistantChatArea.js +1 -1
- package/dist/shared/keyboard/globalShortcuts.js +12 -0
- package/dist/shared/keyboard/types.d.ts +4 -0
- package/dist/shared-agent-tools.js +10 -10
- package/package.json +1 -1
|
@@ -27,16 +27,22 @@ var d = ({ isOpen: d, onClose: f, shortcuts: p }) => {
|
|
|
27
27
|
document.body.style.overflow = "";
|
|
28
28
|
};
|
|
29
29
|
}, [d]), !d) return null;
|
|
30
|
-
let _ =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
let _ = /* @__PURE__ */ new Map();
|
|
31
|
+
for (let e of p) {
|
|
32
|
+
let t = e.category || m("appShell.otherShortcuts", "Other"), n = e.categoryKey ? m(e.categoryKey, t) : t, r = _.get(n);
|
|
33
|
+
r ? r.shortcuts.push(e) : _.set(n, {
|
|
34
|
+
category: t,
|
|
35
|
+
label: n,
|
|
36
|
+
shortcuts: [e]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
let v = [..._.entries()].sort(([, e], [, t]) => {
|
|
34
40
|
let n = {
|
|
35
41
|
Navigation: 0,
|
|
36
42
|
Actions: 1,
|
|
37
43
|
UI: 2
|
|
38
|
-
}, r = n[e] ?? 99, i = n[t] ?? 99;
|
|
39
|
-
return r === i ? e.localeCompare(t) : r - i;
|
|
44
|
+
}, r = n[e.category] ?? 99, i = n[t.category] ?? 99;
|
|
45
|
+
return r === i ? e.category.localeCompare(t.category) : r - i;
|
|
40
46
|
}), y = n(), b = y === "mac" ? "macOS" : y === "windows" ? "Windows" : "Linux";
|
|
41
47
|
return /* @__PURE__ */ l(i, {
|
|
42
48
|
modal: !0,
|
|
@@ -74,17 +80,17 @@ var d = ({ isOpen: d, onClose: f, shortcuts: p }) => {
|
|
|
74
80
|
className: "flex-1 overflow-y-auto p-6",
|
|
75
81
|
children: /* @__PURE__ */ l("div", {
|
|
76
82
|
className: "grid grid-cols-1 md:grid-cols-2 gap-8",
|
|
77
|
-
children: v.map((e) => /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h3", {
|
|
83
|
+
children: v.map(([e, t]) => /* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h3", {
|
|
78
84
|
className: "text-sm font-semibold text-text-primary mb-3",
|
|
79
|
-
children:
|
|
85
|
+
children: t.label
|
|
80
86
|
}), /* @__PURE__ */ l("div", {
|
|
81
87
|
className: "space-y-1",
|
|
82
|
-
children:
|
|
88
|
+
children: t.shortcuts.map((e, t) => /* @__PURE__ */ u("div", {
|
|
83
89
|
className: "flex items-center justify-between py-2 px-3 rounded-button hover:bg-bg-sunken transition-all duration-200 hover:translate-x-0.5",
|
|
84
90
|
style: { animationDelay: `${t * 30}ms` },
|
|
85
91
|
children: [/* @__PURE__ */ l("span", {
|
|
86
92
|
className: "text-text-primary text-sm",
|
|
87
|
-
children: e.description
|
|
93
|
+
children: e.descriptionKey ? m(e.descriptionKey, e.description) : e.description
|
|
88
94
|
}), /* @__PURE__ */ l("kbd", {
|
|
89
95
|
className: "ml-4 px-2.5 py-1 bg-bg-sunken border border-border-subtle rounded text-text-secondary text-xs font-mono whitespace-nowrap transition-all duration-200 hover:scale-105",
|
|
90
96
|
children: r(e.keys)
|
|
@@ -38,7 +38,20 @@ export interface ClientToolOffer {
|
|
|
38
38
|
tools: readonly AnyDefinedAgentTool[];
|
|
39
39
|
manifest: ClientToolManifestEntry[];
|
|
40
40
|
}
|
|
41
|
-
export declare function offerClientTools(
|
|
41
|
+
export declare function offerClientTools(options: {
|
|
42
|
+
writeCapable: boolean;
|
|
43
|
+
}, tools?: readonly AnyDefinedAgentTool[]): ClientToolOffer;
|
|
44
|
+
/**
|
|
45
|
+
* Whether a mode that must not change data may still offer `tool`: it reads
|
|
46
|
+
* (`readOnly`) or only moves the person around the app (`navigation`).
|
|
47
|
+
*
|
|
48
|
+
* ★ BOFF-9908: Ask is promised read-only, so it is offered nothing else — not
|
|
49
|
+
* the confirmation-gated actions, not the canvas edits, and not the generic
|
|
50
|
+
* `ui_click` / `ui_fill` / `ui_select` / `ui_press_key`, which can press any
|
|
51
|
+
* ordinary button. The runner executes only offered tools, so leaving a tool
|
|
52
|
+
* out of the offer is what keeps the mode read-only.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isReadOnlyModeTool(tool: AnyDefinedAgentTool): boolean;
|
|
42
55
|
/**
|
|
43
56
|
* The tools registered right now, as the prompt's `clientTools`. Product tools
|
|
44
57
|
* come first, then the shared ones (`app_`, `ui_`), so if the cap is reached
|
|
@@ -60,7 +73,7 @@ export declare const CLIENT_TOOL_ORPHAN_MS = 20000;
|
|
|
60
73
|
/** The well-formed entries of an untrusted `clientToolRequests` value. */
|
|
61
74
|
export declare function parseClientToolRequests(raw: unknown): ClientToolRequest[];
|
|
62
75
|
export interface ClientToolRunnerOptions {
|
|
63
|
-
/** The definitions this turn advertised (`offerClientTools().tools`). */
|
|
76
|
+
/** The definitions this turn advertised (`offerClientTools(...).tools`). */
|
|
64
77
|
tools: readonly AnyDefinedAgentTool[];
|
|
65
78
|
/** Post one result to the sandbox. Rejects when the post did not land. */
|
|
66
79
|
post: (callId: string, result: AgentToolResult) => Promise<void>;
|
|
@@ -18,14 +18,17 @@ function c(e) {
|
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
function l(e = r()) {
|
|
22
|
-
let
|
|
21
|
+
function l(e, t = r()) {
|
|
22
|
+
let n = e.writeCapable ? t : t.filter(u), i = d(n), a = new Set(i.map((e) => e.name));
|
|
23
23
|
return {
|
|
24
|
-
tools:
|
|
25
|
-
manifest:
|
|
24
|
+
tools: n.filter((e) => a.has(e.name)),
|
|
25
|
+
manifest: i
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
function u(e
|
|
28
|
+
function u(e) {
|
|
29
|
+
return e.annotations?.readOnly === !0 || e.annotations?.navigation === !0;
|
|
30
|
+
}
|
|
31
|
+
function d(e = r()) {
|
|
29
32
|
let n = (e) => e.startsWith("app_") || e.startsWith("ui_"), i = [...e.filter((e) => !n(e.name)), ...e.filter((e) => n(e.name))], a = [], o = 2;
|
|
30
33
|
for (let e of i) {
|
|
31
34
|
let n = c(e), r = s.encode(JSON.stringify(n)).length + 1;
|
|
@@ -37,14 +40,14 @@ function u(e = r()) {
|
|
|
37
40
|
}
|
|
38
41
|
return a;
|
|
39
42
|
}
|
|
40
|
-
var
|
|
41
|
-
function
|
|
43
|
+
var f = /^ct_[0-9a-f]{32}$/, p = 4, m = 2e4;
|
|
44
|
+
function h(e) {
|
|
42
45
|
if (!Array.isArray(e)) return [];
|
|
43
46
|
let t = [];
|
|
44
|
-
for (let n of e.slice(0,
|
|
47
|
+
for (let n of e.slice(0, p)) {
|
|
45
48
|
if (typeof n != "object" || !n || Array.isArray(n)) continue;
|
|
46
49
|
let { callId: e, tool: r, input: i } = n;
|
|
47
|
-
typeof e != "string" || !
|
|
50
|
+
typeof e != "string" || !f.test(e) || typeof r != "string" || r.length === 0 || r.length > 64 || typeof i != "object" || !i || Array.isArray(i) || t.push({
|
|
48
51
|
callId: e,
|
|
49
52
|
tool: r,
|
|
50
53
|
input: i
|
|
@@ -52,7 +55,7 @@ function m(e) {
|
|
|
52
55
|
}
|
|
53
56
|
return t;
|
|
54
57
|
}
|
|
55
|
-
function
|
|
58
|
+
function g(r) {
|
|
56
59
|
let a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set(), s = !1, c = r.now ?? Date.now, l = r.orphanMs ?? 2e4, u = c(), d, f = () => {
|
|
57
60
|
d !== void 0 && clearInterval(d), d = void 0;
|
|
58
61
|
}, p = () => {
|
|
@@ -63,7 +66,7 @@ function h(r) {
|
|
|
63
66
|
f();
|
|
64
67
|
}
|
|
65
68
|
}, Math.max(1e3, Math.floor(l / 4))));
|
|
66
|
-
},
|
|
69
|
+
}, m = () => {
|
|
67
70
|
if (!r.onActivity) return;
|
|
68
71
|
let e = [...a.keys()].map((e) => g.get(e)).filter((e) => typeof e == "string");
|
|
69
72
|
r.onActivity(e.length > 0 ? e.join(", ") : null);
|
|
@@ -81,20 +84,20 @@ function h(r) {
|
|
|
81
84
|
return;
|
|
82
85
|
}
|
|
83
86
|
let l = new AbortController();
|
|
84
|
-
a.set(t.callId, l), g.set(t.callId, c.title),
|
|
87
|
+
a.set(t.callId, l), g.set(t.callId, c.title), m(), p(), i(c, t.input, {
|
|
85
88
|
initiator: "assistant",
|
|
86
89
|
signal: l.signal
|
|
87
90
|
}).then((e) => {
|
|
88
91
|
if (!l.signal.aborted) return _(t.callId, e);
|
|
89
92
|
}).finally(() => {
|
|
90
|
-
a.delete(t.callId), g.delete(t.callId),
|
|
93
|
+
a.delete(t.callId), g.delete(t.callId), m();
|
|
91
94
|
});
|
|
92
95
|
};
|
|
93
96
|
return {
|
|
94
97
|
receive(e) {
|
|
95
98
|
if (s) return;
|
|
96
99
|
u = c();
|
|
97
|
-
let t =
|
|
100
|
+
let t = h(e), n = new Set(t.map((e) => e.callId));
|
|
98
101
|
for (let [e, t] of a) n.has(e) || t.abort();
|
|
99
102
|
for (let e of t) o.has(e.callId) || v(e);
|
|
100
103
|
},
|
|
@@ -107,4 +110,4 @@ function h(r) {
|
|
|
107
110
|
};
|
|
108
111
|
}
|
|
109
112
|
//#endregion
|
|
110
|
-
export { a as CLIENT_TOOL_MANIFEST_MAX_BYTES, o as CLIENT_TOOL_MANIFEST_MAX_TOOLS,
|
|
113
|
+
export { a as CLIENT_TOOL_MANIFEST_MAX_BYTES, o as CLIENT_TOOL_MANIFEST_MAX_TOOLS, m as CLIENT_TOOL_ORPHAN_MS, d as buildClientToolManifest, g as createClientToolRunner, u as isReadOnlyModeTool, l as offerClientTools, h as parseClientToolRequests };
|
|
@@ -110,6 +110,7 @@ function p(e) {
|
|
|
110
110
|
title: "Open a page",
|
|
111
111
|
description: "Opens a page of the app in the person's tab. Pass a page label from app_list_pages (e.g. \"Runs\") or an in-app path starting with \"/\". Refused while the current page has unsaved changes.",
|
|
112
112
|
input: i.strictObject({ destination: i.string().trim().min(1).max(200).describe("A page label from app_list_pages, or an in-app path starting with \"/\".") }),
|
|
113
|
+
annotations: { navigation: !0 },
|
|
113
114
|
execute: ({ destination: t }) => {
|
|
114
115
|
let r = e();
|
|
115
116
|
d(r);
|
|
@@ -133,6 +134,7 @@ function p(e) {
|
|
|
133
134
|
"dark",
|
|
134
135
|
"system"
|
|
135
136
|
]).describe("The appearance to switch to.") }),
|
|
137
|
+
annotations: { navigation: !0 },
|
|
136
138
|
execute: ({ mode: t }) => {
|
|
137
139
|
let { setThemeMode: r } = e();
|
|
138
140
|
if (!r) throw new n("NEEDS_USER", "This app does not let the theme be changed here.");
|
|
@@ -26,6 +26,13 @@ export interface AgentToolAnnotations {
|
|
|
26
26
|
untrustedContent?: boolean;
|
|
27
27
|
/** The tool changes something that matters: it is confirmed before it runs. */
|
|
28
28
|
consequential?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The tool changes only where the person is in the app (the page, the
|
|
31
|
+
* appearance), never their data. A read-only assistant mode offers it along
|
|
32
|
+
* with the `readOnly` tools (`offerClientTools`). Not a WebMCP hint: it is
|
|
33
|
+
* never sent to the browser or to the assistant.
|
|
34
|
+
*/
|
|
35
|
+
navigation?: boolean;
|
|
29
36
|
}
|
|
30
37
|
/** What the confirmation dialog says. Plain text — never markup. */
|
|
31
38
|
export interface AgentToolConfirmation {
|
|
@@ -1598,7 +1598,7 @@ var ki = () => () => {}, Ai = () => "off", ji = ({ visible: ji = !0, writeAccess
|
|
|
1598
1598
|
permissionsSettled: m.navPermissionsSettled,
|
|
1599
1599
|
simulating: m.navSimulating,
|
|
1600
1600
|
sentBefore: ri(h)
|
|
1601
|
-
}) : null, pe = _.getState().sandboxWriteCapabilities[i]?.clientTools === !0 ? _i() : null, me = pe?.manifest ?? [], he = {
|
|
1601
|
+
}) : null, pe = _.getState().sandboxWriteCapabilities[i]?.clientTools === !0 ? _i({ writeCapable: le?.writeCapable === !0 || g === "api-calls" }) : null, me = pe?.manifest ?? [], he = {
|
|
1602
1602
|
conversationId: v,
|
|
1603
1603
|
writeReply: ce === "proposal-v1" ? n.writeReplyBound?.writeReply ?? null : null,
|
|
1604
1604
|
...ue ? { uiCatalogue: ue } : {},
|
|
@@ -13,7 +13,9 @@ function t(t) {
|
|
|
13
13
|
id: "global-nav-home",
|
|
14
14
|
keys: ["g h"],
|
|
15
15
|
description: "Go to Home",
|
|
16
|
+
descriptionKey: "nav.goHome",
|
|
16
17
|
category: "Navigation",
|
|
18
|
+
categoryKey: "chrome.commandPalette.section.navigation",
|
|
17
19
|
action: t.goHome,
|
|
18
20
|
global: !0
|
|
19
21
|
},
|
|
@@ -21,7 +23,9 @@ function t(t) {
|
|
|
21
23
|
id: "global-search",
|
|
22
24
|
keys: e("cmd+k"),
|
|
23
25
|
description: "Open Search",
|
|
26
|
+
descriptionKey: "appShell.shortcuts.openSearch",
|
|
24
27
|
category: "Search",
|
|
28
|
+
categoryKey: "common.search",
|
|
25
29
|
action: t.openSearch,
|
|
26
30
|
global: !0
|
|
27
31
|
},
|
|
@@ -29,7 +33,9 @@ function t(t) {
|
|
|
29
33
|
id: "global-toggle-sidebar",
|
|
30
34
|
keys: e("cmd+\\", "ctrl+\\"),
|
|
31
35
|
description: "Toggle Sidebar",
|
|
36
|
+
descriptionKey: "appShell.toggleSidebar",
|
|
32
37
|
category: "UI",
|
|
38
|
+
categoryKey: "appShell.shortcuts.category.ui",
|
|
33
39
|
action: t.toggleSidebar,
|
|
34
40
|
global: !0
|
|
35
41
|
},
|
|
@@ -37,7 +43,9 @@ function t(t) {
|
|
|
37
43
|
id: "global-toggle-theme",
|
|
38
44
|
keys: e("cmd+shift+d", "ctrl+shift+d"),
|
|
39
45
|
description: "Toggle Dark Mode",
|
|
46
|
+
descriptionKey: "appShell.shortcuts.toggleDarkMode",
|
|
40
47
|
category: "UI",
|
|
48
|
+
categoryKey: "appShell.shortcuts.category.ui",
|
|
41
49
|
action: t.toggleTheme,
|
|
42
50
|
global: !0
|
|
43
51
|
},
|
|
@@ -45,7 +53,9 @@ function t(t) {
|
|
|
45
53
|
id: "global-help",
|
|
46
54
|
keys: e("cmd+/", "ctrl+/"),
|
|
47
55
|
description: "Show Keyboard Shortcuts",
|
|
56
|
+
descriptionKey: "appShell.keyboardShortcuts",
|
|
48
57
|
category: "Help",
|
|
58
|
+
categoryKey: "appShell.shortcuts.category.help",
|
|
49
59
|
action: t.showHelp,
|
|
50
60
|
global: !0
|
|
51
61
|
}
|
|
@@ -54,7 +64,9 @@ function t(t) {
|
|
|
54
64
|
id: "global-nav-settings",
|
|
55
65
|
keys: ["g ,"],
|
|
56
66
|
description: "Go to Settings",
|
|
67
|
+
descriptionKey: "appShell.shortcuts.goToSettings",
|
|
57
68
|
category: "Navigation",
|
|
69
|
+
categoryKey: "chrome.commandPalette.section.navigation",
|
|
58
70
|
action: t.openSettings,
|
|
59
71
|
global: !0
|
|
60
72
|
}), n;
|
|
@@ -29,8 +29,12 @@ export interface KeyboardShortcut {
|
|
|
29
29
|
keys: string[] | PlatformKeys;
|
|
30
30
|
/** Human-readable description */
|
|
31
31
|
description: string;
|
|
32
|
+
/** Optional shell translation key; description remains the English fallback. */
|
|
33
|
+
descriptionKey?: string;
|
|
32
34
|
/** Category for grouping shortcuts (e.g., 'navigation', 'editing') */
|
|
33
35
|
category?: string;
|
|
36
|
+
/** Optional shell translation key; omit to preserve host-supplied category text. */
|
|
37
|
+
categoryKey?: string;
|
|
34
38
|
/** Action to execute when shortcut is triggered */
|
|
35
39
|
action: () => void;
|
|
36
40
|
/** Whether this shortcut is enabled */
|
|
@@ -4,13 +4,13 @@ import { currentConfirmation as l, registerConfirmHost as u, requestAgentConfirm
|
|
|
4
4
|
import { AGENT_TOOL_DESCRIPTION_MAX as h, AGENT_TOOL_NAME_MAX as g, AGENT_TOOL_NAME_PATTERN as _, AGENT_TOOL_OUTPUT_MAX_BYTES as v, AGENT_TOOL_OUTPUT_STRING_MAX as y, AGENT_TOOL_PARAM_DESCRIPTION_MAX as b } from "./shared/agent-tools/limits.js";
|
|
5
5
|
import { capResult as x, jsonByteLength as S } from "./shared/agent-tools/outputBudget.js";
|
|
6
6
|
import { runAgentTool as C } from "./shared/agent-tools/runAgentTool.js";
|
|
7
|
-
import { CLIENT_TOOL_MANIFEST_MAX_BYTES as w, CLIENT_TOOL_MANIFEST_MAX_TOOLS as T, CLIENT_TOOL_ORPHAN_MS as E, buildClientToolManifest as D, createClientToolRunner as O,
|
|
8
|
-
import { defineAgentTool as
|
|
9
|
-
import { useAgentTools as
|
|
10
|
-
import { AGENT_CONFIRM_TEST_ID_PREFIX as
|
|
11
|
-
import { getWebMcpModelContext as
|
|
12
|
-
import { assertNoUnsavedChanges as
|
|
13
|
-
import { DENY_SELECTOR as
|
|
14
|
-
import { createUiTools as
|
|
15
|
-
import { AgentToolsProvider as
|
|
16
|
-
export {
|
|
7
|
+
import { CLIENT_TOOL_MANIFEST_MAX_BYTES as w, CLIENT_TOOL_MANIFEST_MAX_TOOLS as T, CLIENT_TOOL_ORPHAN_MS as E, buildClientToolManifest as D, createClientToolRunner as O, isReadOnlyModeTool as k, offerClientTools as A, parseClientToolRequests as j } from "./shared/agent-tools/adapters/assistant.js";
|
|
8
|
+
import { defineAgentTool as M } from "./shared/agent-tools/defineAgentTool.js";
|
|
9
|
+
import { useAgentTools as N } from "./shared/agent-tools/useAgentTools.js";
|
|
10
|
+
import { AGENT_CONFIRM_TEST_ID_PREFIX as P, AgentConfirmHost as F } from "./shared/agent-tools/confirm/AgentConfirmHost.js";
|
|
11
|
+
import { getWebMcpModelContext as I, startWebMcpBridge as L, toWebMcpDescriptor as R } from "./shared/agent-tools/adapters/webmcp.js";
|
|
12
|
+
import { assertNoUnsavedChanges as z, createShellTools as B, resolveDestination as V } from "./shared/agent-tools/shell/shellTools.js";
|
|
13
|
+
import { DENY_SELECTOR as H, INTERACTIVE_SELECTOR as U, accessibleName as W, isDenied as G, isSensitiveField as K, roleOf as q } from "./shared/agent-tools/ui/dom.js";
|
|
14
|
+
import { createUiTools as J, isConsequentialControl as Y } from "./shared/agent-tools/ui/uiTools.js";
|
|
15
|
+
import { AgentToolsProvider as X } from "./shared/agent-tools/AgentToolsProvider.js";
|
|
16
|
+
export { P as AGENT_CONFIRM_TEST_ID_PREFIX, h as AGENT_TOOL_DESCRIPTION_MAX, g as AGENT_TOOL_NAME_MAX, _ as AGENT_TOOL_NAME_PATTERN, v as AGENT_TOOL_OUTPUT_MAX_BYTES, y as AGENT_TOOL_OUTPUT_STRING_MAX, b as AGENT_TOOL_PARAM_DESCRIPTION_MAX, F as AgentConfirmHost, e as AgentToolError, X as AgentToolsProvider, w as CLIENT_TOOL_MANIFEST_MAX_BYTES, T as CLIENT_TOOL_MANIFEST_MAX_TOOLS, E as CLIENT_TOOL_ORPHAN_MS, H as DENY_SELECTOR, U as INTERACTIVE_SELECTOR, W as accessibleName, t as agentToolFailure, z as assertNoUnsavedChanges, D as buildClientToolManifest, x as capResult, i as clearAgentTools, O as createClientToolRunner, B as createShellTools, J as createUiTools, l as currentConfirmation, M as defineAgentTool, a as getAgentTool, I as getWebMcpModelContext, n as isAgentToolError, Y as isConsequentialControl, G as isDenied, k as isReadOnlyModeTool, K as isSensitiveField, S as jsonByteLength, o as listAgentTools, A as offerClientTools, j as parseClientToolRequests, s as registerAgentTool, u as registerConfirmHost, d as requestAgentConfirmation, f as resetConfirmations, V as resolveDestination, q as roleOf, C as runAgentTool, p as settle, L as startWebMcpBridge, c as subscribeAgentTools, m as subscribeConfirmations, r as toAgentToolFailure, R as toWebMcpDescriptor, N as useAgentTools };
|