@opengeni/react 0.44.1 → 0.44.2
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/{chunk-Q2NCKWTK.js → chunk-HFO4ERGQ.js} +51 -4
- package/dist/chunk-HFO4ERGQ.js.map +1 -0
- package/dist/{chunk-KC27K42G.js → chunk-QQRM3DO3.js} +2 -2
- package/dist/{chunk-KG5F2OKE.js → chunk-YNYIAYXQ.js} +168 -2
- package/dist/chunk-YNYIAYXQ.js.map +1 -0
- package/dist/composer.js +2 -2
- package/dist/index.js +3 -3
- package/dist/session-ui.js +1 -1
- package/dist/session.js +1 -1
- package/package.json +1 -1
- package/src/hooks/use-composer.ts +79 -9
- package/src/timeline/tool-renderers.tsx +206 -3
- package/dist/chunk-KG5F2OKE.js.map +0 -1
- package/dist/chunk-Q2NCKWTK.js.map +0 -1
- /package/dist/{chunk-KC27K42G.js.map → chunk-QQRM3DO3.js.map} +0 -0
package/dist/composer.js
CHANGED
|
@@ -37,8 +37,8 @@ import {
|
|
|
37
37
|
useChatComposer,
|
|
38
38
|
useChatComposerController,
|
|
39
39
|
useVoiceInput
|
|
40
|
-
} from "./chunk-
|
|
41
|
-
import "./chunk-
|
|
40
|
+
} from "./chunk-QQRM3DO3.js";
|
|
41
|
+
import "./chunk-HFO4ERGQ.js";
|
|
42
42
|
import "./chunk-EB67J347.js";
|
|
43
43
|
import {
|
|
44
44
|
BillingClassMark,
|
package/dist/index.js
CHANGED
|
@@ -109,7 +109,7 @@ import {
|
|
|
109
109
|
useLightboxOptional,
|
|
110
110
|
useThemeType,
|
|
111
111
|
v4aToGitFileDiff
|
|
112
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-YNYIAYXQ.js";
|
|
113
113
|
import "./chunk-YDNWMKXO.js";
|
|
114
114
|
import {
|
|
115
115
|
buildTimeline,
|
|
@@ -171,14 +171,14 @@ import {
|
|
|
171
171
|
useSlashCommands,
|
|
172
172
|
useTranscription,
|
|
173
173
|
useVoiceInput
|
|
174
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-QQRM3DO3.js";
|
|
175
175
|
import {
|
|
176
176
|
FILE_ONLY_MESSAGE_TEXT,
|
|
177
177
|
composeSendInput,
|
|
178
178
|
shouldSteerOnKey,
|
|
179
179
|
shouldSubmitOnKey,
|
|
180
180
|
useComposer
|
|
181
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-HFO4ERGQ.js";
|
|
182
182
|
import {
|
|
183
183
|
useMutationRunner,
|
|
184
184
|
usePolledValue,
|
package/dist/session-ui.js
CHANGED
package/dist/session.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/react",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.2",
|
|
4
4
|
"description": "React hooks and styled components for OpenGeni: live session streaming, chat composer, message timeline, session status, and fleet views — token-themed (CSS variables), dark-first, built on Tailwind v4 + Radix + Motion.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -585,6 +585,22 @@ export function useComposer(
|
|
|
585
585
|
}
|
|
586
586
|
void loadDraft(false);
|
|
587
587
|
}, [durableDrafts, loadDraft, sessionId]);
|
|
588
|
+
// After long background / sleep the in-memory revision is often stale while
|
|
589
|
+
// a prior autosave already advanced the server. Soft-reload on wake so the
|
|
590
|
+
// next keystroke does not OCC against a dead revision.
|
|
591
|
+
useEffect(() => {
|
|
592
|
+
if (!sessionId || !durableDrafts) return;
|
|
593
|
+
const onWake = () => {
|
|
594
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") return;
|
|
595
|
+
void loadDraft(false);
|
|
596
|
+
};
|
|
597
|
+
document.addEventListener("visibilitychange", onWake);
|
|
598
|
+
window.addEventListener("pageshow", onWake);
|
|
599
|
+
return () => {
|
|
600
|
+
document.removeEventListener("visibilitychange", onWake);
|
|
601
|
+
window.removeEventListener("pageshow", onWake);
|
|
602
|
+
};
|
|
603
|
+
}, [durableDrafts, loadDraft, sessionId]);
|
|
588
604
|
useEffect(() => {
|
|
589
605
|
if (!sessionId || !durableDrafts) return;
|
|
590
606
|
return registerSessionReconciler(sessionId, "composer", async () => await loadDraft(false));
|
|
@@ -692,7 +708,16 @@ export function useComposer(
|
|
|
692
708
|
}
|
|
693
709
|
setDraftSaving(true);
|
|
694
710
|
try {
|
|
695
|
-
const saved = await
|
|
711
|
+
const saved = await saveComposerDraftWithStaleRetry({
|
|
712
|
+
client,
|
|
713
|
+
workspaceId,
|
|
714
|
+
sessionId,
|
|
715
|
+
request,
|
|
716
|
+
onAdoptRemote: (remote) => {
|
|
717
|
+
draftRef.current = remote;
|
|
718
|
+
setDraft(remote);
|
|
719
|
+
},
|
|
720
|
+
});
|
|
696
721
|
if (
|
|
697
722
|
targetKeyRef.current !== ownedTargetKey ||
|
|
698
723
|
targetGeneration.current !== ownedGeneration
|
|
@@ -701,8 +726,12 @@ export function useComposer(
|
|
|
701
726
|
}
|
|
702
727
|
draftRef.current = saved;
|
|
703
728
|
setDraft(saved);
|
|
704
|
-
lastSavedSignature.current =
|
|
729
|
+
lastSavedSignature.current = draftSignature({
|
|
730
|
+
...request,
|
|
731
|
+
expectedRevision: saved.revision,
|
|
732
|
+
});
|
|
705
733
|
setDraftConflict(null);
|
|
734
|
+
setError(null);
|
|
706
735
|
success = true;
|
|
707
736
|
} catch (cause) {
|
|
708
737
|
if (
|
|
@@ -1260,11 +1289,13 @@ export function useComposer(
|
|
|
1260
1289
|
}
|
|
1261
1290
|
if (choice === "use_remote") {
|
|
1262
1291
|
applyDraft(remote);
|
|
1292
|
+
setError(null);
|
|
1263
1293
|
return;
|
|
1264
1294
|
}
|
|
1265
1295
|
draftRef.current = remote;
|
|
1266
1296
|
setDraft(remote);
|
|
1267
1297
|
setDraftConflict(null);
|
|
1298
|
+
setError(null);
|
|
1268
1299
|
const payload = currentDraftPayload();
|
|
1269
1300
|
if (payload) await persistPayload({ ...payload, expectedRevision: remote.revision });
|
|
1270
1301
|
},
|
|
@@ -1393,13 +1424,52 @@ function asError(cause: unknown): Error {
|
|
|
1393
1424
|
|
|
1394
1425
|
function isDraftConflictError(error: Error): boolean {
|
|
1395
1426
|
const apiError = error as Partial<OpenGeniApiError>;
|
|
1396
|
-
return
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1427
|
+
if (apiError.status !== 409 || apiError.outcomeUnknown === true) return false;
|
|
1428
|
+
// Production queue OCC returns `DRAFT_CHANGED`. Older/SDK-shaped 409s may
|
|
1429
|
+
// omit code or use the generic conflict labels — all are recoverable OCC.
|
|
1430
|
+
const code = apiError.code;
|
|
1431
|
+
if (
|
|
1432
|
+
code === undefined ||
|
|
1433
|
+
code === "DRAFT_CHANGED" ||
|
|
1434
|
+
code === "conflict" ||
|
|
1435
|
+
code === "idempotency_conflict"
|
|
1436
|
+
) {
|
|
1437
|
+
return true;
|
|
1438
|
+
}
|
|
1439
|
+
return /draft changed/i.test(error.message);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* One OCC retry: adopt the server revision and rewrite the same local content.
|
|
1444
|
+
* Covers the common "tab slept through a successful autosave" case without
|
|
1445
|
+
* stranding the operator on a raw 409 toast.
|
|
1446
|
+
*/
|
|
1447
|
+
async function saveComposerDraftWithStaleRetry(input: {
|
|
1448
|
+
client: {
|
|
1449
|
+
getComposerDraft: (workspaceId: string, sessionId: string) => Promise<ComposerDraft>;
|
|
1450
|
+
saveComposerDraft: (
|
|
1451
|
+
workspaceId: string,
|
|
1452
|
+
sessionId: string,
|
|
1453
|
+
request: SaveComposerDraftRequest,
|
|
1454
|
+
) => Promise<ComposerDraft>;
|
|
1455
|
+
};
|
|
1456
|
+
workspaceId: string;
|
|
1457
|
+
sessionId: string;
|
|
1458
|
+
request: SaveComposerDraftRequest;
|
|
1459
|
+
onAdoptRemote: (remote: ComposerDraft) => void;
|
|
1460
|
+
}): Promise<ComposerDraft> {
|
|
1461
|
+
try {
|
|
1462
|
+
return await input.client.saveComposerDraft(input.workspaceId, input.sessionId, input.request);
|
|
1463
|
+
} catch (cause) {
|
|
1464
|
+
const problem = asError(cause);
|
|
1465
|
+
if (!isDraftConflictError(problem)) throw problem;
|
|
1466
|
+
const remote = await input.client.getComposerDraft(input.workspaceId, input.sessionId);
|
|
1467
|
+
input.onAdoptRemote(remote);
|
|
1468
|
+
return await input.client.saveComposerDraft(input.workspaceId, input.sessionId, {
|
|
1469
|
+
...input.request,
|
|
1470
|
+
expectedRevision: remote.revision,
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1403
1473
|
}
|
|
1404
1474
|
|
|
1405
1475
|
function draftPayload(draft: ComposerDraft): SaveComposerDraftRequest {
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
MessagesSquareIcon,
|
|
18
18
|
MessageSquareIcon,
|
|
19
19
|
MousePointer2Icon,
|
|
20
|
+
PackageSearchIcon,
|
|
20
21
|
PanelsTopLeftIcon,
|
|
21
22
|
PlugIcon,
|
|
22
23
|
SearchIcon,
|
|
@@ -1033,6 +1034,204 @@ function SecretSetRenderer({ item }: ToolRendererProps) {
|
|
|
1033
1034
|
);
|
|
1034
1035
|
}
|
|
1035
1036
|
|
|
1037
|
+
/* ---- tool_search (progressive MCP disclosure) ------------------------------ */
|
|
1038
|
+
|
|
1039
|
+
type DisclosedTool = {
|
|
1040
|
+
/** Full wire name (`server__leaf` or bare). */
|
|
1041
|
+
name: string;
|
|
1042
|
+
/** Server / namespace prefix before `__`, when present. */
|
|
1043
|
+
source: string | null;
|
|
1044
|
+
/** Leaf tool name after `__`. */
|
|
1045
|
+
leaf: string;
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
function splitToolWireName(name: string): DisclosedTool {
|
|
1049
|
+
const boundary = name.indexOf("__");
|
|
1050
|
+
if (boundary <= 0) {
|
|
1051
|
+
return { name, source: null, leaf: name };
|
|
1052
|
+
}
|
|
1053
|
+
return {
|
|
1054
|
+
name,
|
|
1055
|
+
source: name.slice(0, boundary),
|
|
1056
|
+
leaf: name.slice(boundary + 2),
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/** Capability query from live tool_search args (object or JSON string). */
|
|
1061
|
+
function toolSearchQuery(item: ToolRendererProps["item"]): string {
|
|
1062
|
+
const fromArgs = parseToolArgs(item.arguments);
|
|
1063
|
+
if (typeof fromArgs.query === "string" && fromArgs.query.trim()) {
|
|
1064
|
+
return fromArgs.query.trim();
|
|
1065
|
+
}
|
|
1066
|
+
const raw = item.raw;
|
|
1067
|
+
if (raw && typeof raw === "object") {
|
|
1068
|
+
const rawArgs = (raw as { arguments?: unknown }).arguments;
|
|
1069
|
+
if (typeof rawArgs === "string" && rawArgs.trim()) {
|
|
1070
|
+
const parsed = tryParseJson(rawArgs);
|
|
1071
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1072
|
+
const query = (parsed as { query?: unknown }).query;
|
|
1073
|
+
if (typeof query === "string" && query.trim()) {
|
|
1074
|
+
return query.trim();
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
} else if (rawArgs && typeof rawArgs === "object" && !Array.isArray(rawArgs)) {
|
|
1078
|
+
const query = (rawArgs as { query?: unknown }).query;
|
|
1079
|
+
if (typeof query === "string" && query.trim()) {
|
|
1080
|
+
return query.trim();
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
return "";
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* Parse disclosed tools from the runtime event shape.
|
|
1089
|
+
* `normalizeSdkEvent` collapses `tool_search_output.tools[]` into text:
|
|
1090
|
+
* "Disclosed tools: a, b" | "No matching tools found."
|
|
1091
|
+
* Also accept a structured `tools` array when a host/enricher preserves it.
|
|
1092
|
+
*/
|
|
1093
|
+
function parseDisclosedTools(output: unknown): DisclosedTool[] | null {
|
|
1094
|
+
if (output && typeof output === "object" && !Array.isArray(output)) {
|
|
1095
|
+
const tools = (output as { tools?: unknown }).tools;
|
|
1096
|
+
if (Array.isArray(tools)) {
|
|
1097
|
+
return tools
|
|
1098
|
+
.map((tool) => {
|
|
1099
|
+
if (typeof tool === "string" && tool.trim()) {
|
|
1100
|
+
return splitToolWireName(tool.trim());
|
|
1101
|
+
}
|
|
1102
|
+
if (
|
|
1103
|
+
tool &&
|
|
1104
|
+
typeof tool === "object" &&
|
|
1105
|
+
typeof (tool as { name?: unknown }).name === "string"
|
|
1106
|
+
) {
|
|
1107
|
+
const name = (tool as { name: string }).name.trim();
|
|
1108
|
+
return name ? splitToolWireName(name) : null;
|
|
1109
|
+
}
|
|
1110
|
+
return null;
|
|
1111
|
+
})
|
|
1112
|
+
.filter((tool): tool is DisclosedTool => tool != null);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
const { text } = unwrapMcpOutput(output);
|
|
1117
|
+
const trimmed = text.trim();
|
|
1118
|
+
if (!trimmed) {
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
if (/^no matching tools found\.?$/i.test(trimmed)) {
|
|
1122
|
+
return [];
|
|
1123
|
+
}
|
|
1124
|
+
const disclosed = trimmed.match(/^disclosed tools:\s*(.+)$/i);
|
|
1125
|
+
if (disclosed?.[1]) {
|
|
1126
|
+
return disclosed[1]
|
|
1127
|
+
.split(",")
|
|
1128
|
+
.map((part) => part.trim())
|
|
1129
|
+
.filter(Boolean)
|
|
1130
|
+
.map(splitToolWireName);
|
|
1131
|
+
}
|
|
1132
|
+
const parsed = tryParseJson(trimmed);
|
|
1133
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1134
|
+
return parseDisclosedTools(parsed);
|
|
1135
|
+
}
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
function toolSearchPreview(tools: DisclosedTool[] | null, cancelled: boolean): string | undefined {
|
|
1140
|
+
if (cancelled) {
|
|
1141
|
+
return undefined;
|
|
1142
|
+
}
|
|
1143
|
+
if (!tools) {
|
|
1144
|
+
return "Done";
|
|
1145
|
+
}
|
|
1146
|
+
if (tools.length === 0) {
|
|
1147
|
+
return "No matches";
|
|
1148
|
+
}
|
|
1149
|
+
if (tools.length === 1) {
|
|
1150
|
+
return tools[0]!.leaf;
|
|
1151
|
+
}
|
|
1152
|
+
const head = tools[0]!.leaf;
|
|
1153
|
+
return `${tools.length} tools · ${truncatePreview(head, 28)}`;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
function ToolSearchRenderer({ item }: ToolRendererProps) {
|
|
1157
|
+
const query = toolSearchQuery(item);
|
|
1158
|
+
const icon = <PackageSearchIcon className={ICON_SIZE} />;
|
|
1159
|
+
const running = item.status === "running";
|
|
1160
|
+
const queryPreview = query ? truncatePreview(query, 64) : "";
|
|
1161
|
+
|
|
1162
|
+
if (running) {
|
|
1163
|
+
return (
|
|
1164
|
+
<ActivityDisclosure
|
|
1165
|
+
icon={icon}
|
|
1166
|
+
iconTone="running"
|
|
1167
|
+
title="Looking up tools"
|
|
1168
|
+
running
|
|
1169
|
+
preview={
|
|
1170
|
+
queryPreview ? (
|
|
1171
|
+
<RunningPreview>{queryPreview}</RunningPreview>
|
|
1172
|
+
) : (
|
|
1173
|
+
<RunningPreview>Matching capabilities…</RunningPreview>
|
|
1174
|
+
)
|
|
1175
|
+
}
|
|
1176
|
+
>
|
|
1177
|
+
{query ? <BodyNote>capability query: {query}</BodyNote> : null}
|
|
1178
|
+
<PayloadBlock label="Arguments" value={redactSecrets(parseToolArgs(item.arguments))} />
|
|
1179
|
+
</ActivityDisclosure>
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const { text: outText, isError } = unwrapMcpOutput(item.output);
|
|
1184
|
+
if ((isError || item.status === "failed") && item.status !== "cancelled") {
|
|
1185
|
+
return (
|
|
1186
|
+
<ActivityDisclosure
|
|
1187
|
+
icon={icon}
|
|
1188
|
+
iconTone="failed"
|
|
1189
|
+
title="Tool lookup failed"
|
|
1190
|
+
failed
|
|
1191
|
+
preview={truncatePreview(outText, 80) || queryPreview || "Lookup failed"}
|
|
1192
|
+
>
|
|
1193
|
+
{query ? <BodyNote>capability query: {query}</BodyNote> : null}
|
|
1194
|
+
<PayloadBlock label="Arguments" value={redactSecrets(parseToolArgs(item.arguments))} />
|
|
1195
|
+
<PayloadBlock label="Error" value={outText} failed />
|
|
1196
|
+
</ActivityDisclosure>
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
const tools = parseDisclosedTools(item.output);
|
|
1201
|
+
const preview = toolSearchPreview(tools, item.status === "cancelled");
|
|
1202
|
+
|
|
1203
|
+
return (
|
|
1204
|
+
<ActivityDisclosure
|
|
1205
|
+
icon={icon}
|
|
1206
|
+
iconTone="muted"
|
|
1207
|
+
title="Looked up tools"
|
|
1208
|
+
cancelled={item.status === "cancelled"}
|
|
1209
|
+
preview={preview}
|
|
1210
|
+
>
|
|
1211
|
+
{query ? <BodyNote>capability query: {query}</BodyNote> : null}
|
|
1212
|
+
{tools && tools.length > 0 ? (
|
|
1213
|
+
<ul className="grid gap-1.5">
|
|
1214
|
+
{tools.slice(0, 12).map((tool) => (
|
|
1215
|
+
<li key={tool.name} className="flex min-w-0 items-baseline gap-2">
|
|
1216
|
+
{tool.source ? (
|
|
1217
|
+
<span className="shrink-0 text-og-xs text-og-fg-subtle">{tool.source}</span>
|
|
1218
|
+
) : null}
|
|
1219
|
+
<span className="truncate font-mono text-og-sm text-og-fg">{tool.leaf}</span>
|
|
1220
|
+
</li>
|
|
1221
|
+
))}
|
|
1222
|
+
{tools.length > 12 ? (
|
|
1223
|
+
<li className="text-og-xs text-og-fg-muted">+{tools.length - 12} more</li>
|
|
1224
|
+
) : null}
|
|
1225
|
+
</ul>
|
|
1226
|
+
) : tools && tools.length === 0 ? (
|
|
1227
|
+
<BodyNote>no deferred tools matched this capability query.</BodyNote>
|
|
1228
|
+
) : null}
|
|
1229
|
+
<PayloadBlock label="Arguments" value={redactSecrets(parseToolArgs(item.arguments))} />
|
|
1230
|
+
{tools == null && outText ? <PayloadBlock label="Result" value={outText} /> : null}
|
|
1231
|
+
</ActivityDisclosure>
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1036
1235
|
/* ---- docs / knowledge search ----------------------------------------------- */
|
|
1037
1236
|
|
|
1038
1237
|
function DocsSearchRenderer({ item }: ToolRendererProps) {
|
|
@@ -1577,9 +1776,11 @@ function GenericToolIcon({ name }: { name: string }) {
|
|
|
1577
1776
|
leaf.includes("knowledge") ||
|
|
1578
1777
|
leaf === "list_document_bases"
|
|
1579
1778
|
? FileSearchIcon
|
|
1580
|
-
: leaf === "tool_search"
|
|
1581
|
-
?
|
|
1582
|
-
:
|
|
1779
|
+
: leaf === "tool_search"
|
|
1780
|
+
? PackageSearchIcon
|
|
1781
|
+
: leaf === "load_skill"
|
|
1782
|
+
? PlugIcon
|
|
1783
|
+
: WrenchIcon;
|
|
1583
1784
|
return <Icon className={ICON_SIZE} />;
|
|
1584
1785
|
}
|
|
1585
1786
|
|
|
@@ -1591,6 +1792,7 @@ const BASE_ENTRIES: ToolRegistryEntry[] = [
|
|
|
1591
1792
|
{ match: "rawType", type: "apply_patch_call", render: ApplyPatchRenderer },
|
|
1592
1793
|
{ match: "rawType", type: "computer_call", render: ComputerCallRenderer },
|
|
1593
1794
|
{ match: "rawType", type: "hosted_tool_call", render: WebSearchRenderer },
|
|
1795
|
+
{ match: "rawType", type: "tool_search_call", render: ToolSearchRenderer },
|
|
1594
1796
|
// First-party sandbox + MCP tools resolve by name (exact or MCP leaf).
|
|
1595
1797
|
{ match: "name", name: "exec_command", render: ExecRenderer },
|
|
1596
1798
|
{ match: "name", name: "request_human_input", render: AskRenderer },
|
|
@@ -1609,6 +1811,7 @@ const BASE_ENTRIES: ToolRegistryEntry[] = [
|
|
|
1609
1811
|
{ match: "name", name: "computer_keypress", render: ComputerCallRenderer },
|
|
1610
1812
|
{ match: "name", name: "computer_drag", render: ComputerCallRenderer },
|
|
1611
1813
|
{ match: "name", name: "web_search_call", render: WebSearchRenderer },
|
|
1814
|
+
{ match: "name", name: "tool_search", render: ToolSearchRenderer },
|
|
1612
1815
|
{ match: "name", name: "view_image", render: ViewImageRenderer },
|
|
1613
1816
|
{ match: "name", name: "environment_set_variable", render: SecretSetRenderer },
|
|
1614
1817
|
{ match: "name", name: "variable_set_set_variable", render: SecretSetRenderer },
|