@solidxai/core-ui 0.1.19 → 0.1.20-beta.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.
Files changed (43) hide show
  1. package/dist/components/core/extension/solid-core/agentRegistry/card/AgentResourceCardWidget.d.ts.map +1 -1
  2. package/dist/components/core/extension/solid-core/agentRegistry/card/AgentResourceCardWidget.js +3 -10
  3. package/dist/components/core/extension/solid-core/agentRegistry/card/AgentResourceCardWidget.js.map +1 -1
  4. package/dist/components/core/extension/solid-core/agentRegistry/card/AgentResourceCardWidget.tsx +3 -8
  5. package/dist/components/layout/AdminHeaderActions.d.ts.map +1 -1
  6. package/dist/components/layout/AdminHeaderActions.js +1 -29
  7. package/dist/components/layout/AdminHeaderActions.js.map +1 -1
  8. package/dist/components/layout/AdminHeaderActions.tsx +0 -42
  9. package/dist/components/layout/SolidAiStudioLayout.d.ts +0 -1
  10. package/dist/components/layout/SolidAiStudioLayout.d.ts.map +1 -1
  11. package/dist/components/layout/SolidAiStudioLayout.js +9 -161
  12. package/dist/components/layout/SolidAiStudioLayout.js.map +1 -1
  13. package/dist/components/layout/SolidAiStudioLayout.tsx +7 -136
  14. package/dist/routes/AppEventListener.d.ts.map +1 -1
  15. package/dist/routes/AppEventListener.js +3 -3
  16. package/dist/routes/AppEventListener.js.map +1 -1
  17. package/dist/routes/AppEventListener.tsx +1 -2
  18. package/dist/routes/pages/admin/core/AgentHubTagsField.css +21 -0
  19. package/dist/routes/pages/admin/core/AgentHubTagsField.d.ts +17 -0
  20. package/dist/routes/pages/admin/core/AgentHubTagsField.d.ts.map +1 -0
  21. package/dist/routes/pages/admin/core/AgentHubTagsField.js +171 -0
  22. package/dist/routes/pages/admin/core/AgentHubTagsField.js.map +1 -0
  23. package/dist/routes/pages/admin/core/AgentHubTagsField.tsx +125 -0
  24. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.css +7 -0
  25. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.d.ts.map +1 -1
  26. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.js +65 -52
  27. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.js.map +1 -1
  28. package/dist/routes/pages/admin/core/AgentRegistryEditorPage.tsx +53 -11
  29. package/dist/routes/pages/admin/core/AgentSkillRegistryEditorPage.d.ts.map +1 -1
  30. package/dist/routes/pages/admin/core/AgentSkillRegistryEditorPage.js +14 -69
  31. package/dist/routes/pages/admin/core/AgentSkillRegistryEditorPage.js.map +1 -1
  32. package/dist/routes/pages/admin/core/AgentSkillRegistryEditorPage.tsx +15 -83
  33. package/dist/routes/pages/admin/core/AgentToolActivationDialog.d.ts +11 -0
  34. package/dist/routes/pages/admin/core/AgentToolActivationDialog.d.ts.map +1 -0
  35. package/dist/routes/pages/admin/core/AgentToolActivationDialog.js +166 -0
  36. package/dist/routes/pages/admin/core/AgentToolActivationDialog.js.map +1 -0
  37. package/dist/routes/pages/admin/core/AgentToolActivationDialog.tsx +140 -0
  38. package/dist/routes/pages/admin/core/AgentToolRegistryEditorPage.css +26 -0
  39. package/dist/routes/pages/admin/core/AgentToolRegistryEditorPage.d.ts.map +1 -1
  40. package/dist/routes/pages/admin/core/AgentToolRegistryEditorPage.js +94 -71
  41. package/dist/routes/pages/admin/core/AgentToolRegistryEditorPage.js.map +1 -1
  42. package/dist/routes/pages/admin/core/AgentToolRegistryEditorPage.tsx +60 -52
  43. package/package.json +1 -1
@@ -1,10 +1,11 @@
1
1
  import React from "react";
2
- import { ArrowLeft, Plus, RefreshCw, X } from "lucide-react";
2
+ import { ArrowLeft, RefreshCw } from "lucide-react";
3
3
  import { useDispatch } from "react-redux";
4
4
  import { useNavigate, useParams } from "react-router-dom";
5
5
  import { createSolidEntityApi } from "../../../../redux/api/solidEntityApi";
6
6
  import { showToast } from "../../../../redux/features/toastSlice";
7
7
  import { AgentRegistryAuditPanel } from "./AgentRegistryAuditPanel";
8
+ import { AgentHubTagsField, agentHubTagsFrom, agentHubTagsPayload, type AgentHubTag } from "./AgentHubTagsField";
8
9
  import {
9
10
  SolidButton,
10
11
  SolidCodeEditor,
@@ -30,7 +31,7 @@ type SkillRecord = {
30
31
  iconName?: string | null;
31
32
  description?: string;
32
33
  body?: string;
33
- tags?: unknown;
34
+ tags?: AgentHubTag[];
34
35
  agentSkills?: AgentReference[] | AgentReference | null;
35
36
  };
36
37
 
@@ -45,25 +46,6 @@ function extractEntityRecord(response: unknown): Record<string, any> | undefined
45
46
  return candidate && typeof candidate === "object" ? candidate as Record<string, any> : undefined;
46
47
  }
47
48
 
48
- function parseTags(value: unknown): string[] {
49
- if (Array.isArray(value)) {
50
- return value.map((tag) => String(tag).trim()).filter(Boolean);
51
- }
52
-
53
- if (typeof value !== "string" || !value.trim()) return [];
54
-
55
- try {
56
- const parsed = JSON.parse(value);
57
- if (Array.isArray(parsed)) {
58
- return parsed.map((tag) => String(tag).trim()).filter(Boolean);
59
- }
60
- } catch {
61
- return value === "{}" ? [] : value.split(",").map((tag) => tag.trim()).filter(Boolean);
62
- }
63
-
64
- return [];
65
- }
66
-
67
49
  function formatErrorMessage(value: unknown): string | undefined {
68
50
  if (typeof value === "string") return value.trim() || undefined;
69
51
  if (Array.isArray(value)) {
@@ -125,7 +107,7 @@ export function AgentSkillRegistryEditorPage() {
125
107
  const { data: response, isLoading, isFetching, refetch } = useGetSolidEntityByIdQuery(
126
108
  {
127
109
  id,
128
- qs: "populate[0]=agentSkills&populate[1]=agentSkills.agentRegistry",
110
+ qs: "populate[0]=agentSkills&populate[1]=agentSkills.agentRegistry&populate[2]=tags",
129
111
  },
130
112
  { skip: !id || id === "new" },
131
113
  );
@@ -139,47 +121,36 @@ export function AgentSkillRegistryEditorPage() {
139
121
  const [iconName, setIconName] = React.useState("");
140
122
  const [description, setDescription] = React.useState("");
141
123
  const [body, setBody] = React.useState("");
142
- const [tags, setTags] = React.useState<string[]>([]);
143
- const [tagDraft, setTagDraft] = React.useState("");
124
+ const [tags, setTags] = React.useState<AgentHubTag[]>([]);
125
+ const [creatingTag, setCreatingTag] = React.useState(false);
144
126
  const [fieldErrors, setFieldErrors] = React.useState<Record<string, string>>({});
145
127
  const [auditRefreshVersion, setAuditRefreshVersion] = React.useState(0);
146
128
  const [confirmRefresh, setConfirmRefresh] = React.useState(false);
147
129
  const baseline = React.useRef("");
148
- const currentForm = () => JSON.stringify({ name, type, iconName, description, body, tags, tagDraft });
130
+ const currentForm = () => JSON.stringify({ name, type, iconName, description, body, tags });
149
131
 
150
132
  React.useEffect(() => {
151
- const nextTags = parseTags(record?.tags);
133
+ const nextTags = agentHubTagsFrom(record?.tags);
152
134
  setName(record?.name ?? "");
153
135
  setType(record?.type ?? "custom");
154
136
  setIconName(record?.iconName ?? "");
155
137
  setDescription(record?.description ?? "");
156
138
  setBody(record?.body ?? "");
157
139
  setTags(nextTags);
158
- setTagDraft("");
159
- baseline.current = JSON.stringify({ name: record?.name ?? "", type: record?.type ?? "custom", iconName: record?.iconName ?? "", description: record?.description ?? "", body: record?.body ?? "", tags: nextTags, tagDraft: "" });
140
+ baseline.current = JSON.stringify({ name: record?.name ?? "", type: record?.type ?? "custom", iconName: record?.iconName ?? "", description: record?.description ?? "", body: record?.body ?? "", tags: nextTags });
160
141
  }, [record]);
161
142
 
162
143
  const isReadOnly = record?.type === "solidx";
163
144
  const isDirty = Boolean(record?.id) && currentForm() !== baseline.current;
164
145
  const requestRefresh = () => isDirty ? setConfirmRefresh(true) : void refetch();
165
146
 
166
- const addTag = () => {
167
- const nextTag = tagDraft.trim();
168
- if (!nextTag) return;
169
- if (!tags.some((tag) => tag.toLowerCase() === nextTag.toLowerCase())) {
170
- setTags((current) => [...current, nextTag]);
171
- }
172
- setTagDraft("");
173
- setFieldErrors((current) => ({ ...current, tags: "" }));
174
- };
175
-
176
147
  const handleSave = async () => {
148
+ if (creatingTag) return;
177
149
  const nextErrors: Record<string, string> = {};
178
150
  if (!name.trim()) nextErrors.name = "Name is required.";
179
151
  if (!type.trim()) nextErrors.type = "Skill type is required.";
180
152
  if (!description.trim()) nextErrors.description = "Description is required.";
181
153
  if (!body.trim()) nextErrors.body = "Skill instructions are required.";
182
- if (tags.length === 0) nextErrors.tags = "At least one tag is required.";
183
154
 
184
155
  setFieldErrors(nextErrors);
185
156
  if (Object.keys(nextErrors).length > 0) {
@@ -198,7 +169,7 @@ export function AgentSkillRegistryEditorPage() {
198
169
  iconName: iconName || null,
199
170
  description: description.trim(),
200
171
  body,
201
- tags: JSON.stringify(tags),
172
+ ...agentHubTagsPayload(tags),
202
173
  };
203
174
 
204
175
  try {
@@ -229,14 +200,14 @@ export function AgentSkillRegistryEditorPage() {
229
200
  const errorDetail = getSaveErrorMessage(error);
230
201
  const serverFieldErrors: Record<string, string> = {};
231
202
  if (/required|not be empty|cannot be empty|should not be empty/i.test(errorDetail)) {
232
- for (const field of ["name", "type", "description", "body", "tags"]) {
203
+ for (const field of ["name", "type", "description", "body"]) {
233
204
  if (!new RegExp(`\\b${field}\\b`, "i").test(errorDetail)) continue;
234
205
  serverFieldErrors[field] = `${field === "body" ? "Skill instructions" : field[0].toUpperCase() + field.slice(1)} is required.`;
235
206
  }
236
207
  }
237
208
  if (Object.keys(serverFieldErrors).length > 0) {
238
209
  setFieldErrors(serverFieldErrors);
239
- setActiveTab(serverFieldErrors.body || serverFieldErrors.tags ? "skill" : "general");
210
+ setActiveTab(serverFieldErrors.body ? "skill" : "general");
240
211
  }
241
212
  dispatch(showToast({
242
213
  severity: "error",
@@ -306,46 +277,7 @@ export function AgentSkillRegistryEditorPage() {
306
277
  </select>
307
278
  {fieldErrors.type && <small id="agent-skill-type-error" className="agent-skill-editor__field-error">{fieldErrors.type}</small>}
308
279
  </label>
309
- <div className="agent-skill-editor__field">
310
- <span>Tags <b>*</b></span>
311
- <div className={`agent-skill-editor__tag-input${fieldErrors.tags ? " agent-skill-editor__tag-input--invalid" : ""}`}>
312
- {tags.map((tag, index) => (
313
- <span className="agent-skill-editor__tag" key={`${tag}-${index}`}>
314
- {tag}
315
- <button
316
- type="button"
317
- aria-label={`Remove ${tag}`}
318
- onClick={() => {
319
- setTags((current) => {
320
- const nextTags = current.filter((_, tagIndex) => tagIndex !== index);
321
- if (nextTags.length > 0) setFieldErrors((errors) => ({ ...errors, tags: "" }));
322
- return nextTags;
323
- });
324
- }}
325
- >
326
- <X size={13} />
327
- </button>
328
- </span>
329
- ))}
330
- <input
331
- value={tagDraft}
332
- aria-label="Add a tag"
333
- placeholder="Type a tag and press Enter"
334
- onChange={(event) => setTagDraft(event.target.value)}
335
- onKeyDown={(event) => {
336
- if (event.key === "Enter") {
337
- event.preventDefault();
338
- addTag();
339
- }
340
- }}
341
- />
342
- <SolidButton type="button" variant="secondary" size="small" onClick={addTag}>
343
- <Plus size={14} /> Add
344
- </SolidButton>
345
- </div>
346
- {fieldErrors.tags && <small className="agent-skill-editor__field-error">{fieldErrors.tags}</small>}
347
- <small>Tags are saved as a JSON array.</small>
348
- </div>
280
+ <AgentHubTagsField value={tags} onChange={setTags} disabled={isReadOnly || isCreating || isSaving} onBusyChange={setCreatingTag} />
349
281
  </fieldset>
350
282
  ),
351
283
  },
@@ -415,7 +347,7 @@ export function AgentSkillRegistryEditorPage() {
415
347
  Back
416
348
  </SolidButton>
417
349
  {!isReadOnly && (
418
- <SolidButton loading={isCreating || isSaving} onClick={handleSave}>
350
+ <SolidButton loading={isCreating || isSaving} disabled={creatingTag} onClick={handleSave}>
419
351
  Save Skill
420
352
  </SolidButton>
421
353
  )}
@@ -0,0 +1,11 @@
1
+ type Props = {
2
+ open: boolean;
3
+ toolId: number;
4
+ checksum: string;
5
+ toolName: string;
6
+ onOpenChange: (open: boolean) => void;
7
+ onActivated: () => Promise<void>;
8
+ };
9
+ export declare function AgentToolActivationDialog({ open, toolId, checksum, toolName, onOpenChange, onActivated }: Props): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=AgentToolActivationDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentToolActivationDialog.d.ts","sourceRoot":"","sources":["../../../../../src/routes/pages/admin/core/AgentToolActivationDialog.tsx"],"names":[],"mappings":"AAYA,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC,CAAC;AAuCF,wBAAgB,yBAAyB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,2CAiF/G"}
@@ -0,0 +1,166 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
12
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
38
+ import React from "react";
39
+ import { CheckCircle2, Circle, Loader2, ShieldCheck, XCircle } from "lucide-react";
40
+ import { solidPost } from "../../../../http/solidHttp";
41
+ import { SolidButton, SolidDialog, SolidDialogBody } from "../../../../components/shad-cn-ui";
42
+ function unwrapReport(response) {
43
+ var value = response === null || response === void 0 ? void 0 : response.data;
44
+ for (var depth = 0; depth < 5 && value; depth += 1) {
45
+ if (value.config && value.init)
46
+ return value;
47
+ value = value.data;
48
+ }
49
+ throw new Error("The server returned an invalid tool check result.");
50
+ }
51
+ function errorMessage(error) {
52
+ var _a, _b, _c, _d, _e;
53
+ var body = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data;
54
+ var message = (_e = (_d = (_c = (_b = body === null || body === void 0 ? void 0 : body.data) === null || _b === void 0 ? void 0 : _b.message) !== null && _c !== void 0 ? _c : body === null || body === void 0 ? void 0 : body.message) !== null && _d !== void 0 ? _d : body === null || body === void 0 ? void 0 : body.detail) !== null && _e !== void 0 ? _e : error === null || error === void 0 ? void 0 : error.message;
55
+ return Array.isArray(message) ? message.join(" ") : typeof message === "string" ? message : "Checks failed. Please retry.";
56
+ }
57
+ function CheckStep(_a) {
58
+ var _b;
59
+ var title = _a.title, step = _a.step, number = _a.number;
60
+ var Icon = step.status === "running" ? Loader2 : step.status === "passed" ? CheckCircle2
61
+ : step.status === "failed" ? XCircle : Circle;
62
+ var label = step.status === "running" ? "Checking" : step.status === "waiting" ? "Waiting" : step.status;
63
+ return _jsxs("section", { className: "agent-tool-check is-".concat(step.status), "aria-label": "".concat(title, ": ").concat(label), children: [_jsx("div", { className: "agent-tool-check__icon", children: _jsx(Icon, { size: 23, className: step.status === "running" ? "is-spinning" : undefined }) }), _jsxs("div", { className: "agent-tool-check__content", children: [_jsxs("div", { className: "agent-tool-check__heading", children: [_jsxs("h3", { children: [number, ". ", title] }), _jsx("span", { children: label })] }), _jsx("p", { children: step.message }), !!((_b = step.requiredSecrets) === null || _b === void 0 ? void 0 : _b.length) && _jsx("ul", { className: "agent-tool-check__secrets", "aria-label": "Required secrets", children: step.requiredSecrets.map(function (name) {
64
+ var _a, _b;
65
+ var missing = (_a = step.missingSecrets) === null || _a === void 0 ? void 0 : _a.includes(name);
66
+ var verified = step.status === "passed" || Boolean((_b = step.missingSecrets) === null || _b === void 0 ? void 0 : _b.length);
67
+ return _jsxs("li", { className: missing ? "is-missing" : verified ? "is-available" : "", children: [_jsx("code", { children: name }), _jsx("span", { children: missing ? "Missing, empty, or inactive" : verified ? "Available" : "Not verified" })] }, name);
68
+ }) })] })] });
69
+ }
70
+ export function AgentToolActivationDialog(_a) {
71
+ var _this = this;
72
+ var open = _a.open, toolId = _a.toolId, checksum = _a.checksum, toolName = _a.toolName, onOpenChange = _a.onOpenChange, onActivated = _a.onActivated;
73
+ var _b = React.useState({ status: "running", message: "Checking configuration and required secrets…" }), config = _b[0], setConfig = _b[1];
74
+ var _c = React.useState({ status: "waiting", message: "Waiting for configuration to pass." }), init = _c[0], setInit = _c[1];
75
+ var _d = React.useState(true), busy = _d[0], setBusy = _d[1];
76
+ var _e = React.useState(false), activated = _e[0], setActivated = _e[1];
77
+ var _f = React.useState(""), activationError = _f[0], setActivationError = _f[1];
78
+ var _g = React.useState(0), attempt = _g[0], setAttempt = _g[1];
79
+ var callbacks = React.useRef({ onActivated: onActivated });
80
+ callbacks.current = { onActivated: onActivated };
81
+ React.useEffect(function () {
82
+ if (!open)
83
+ return;
84
+ var controller = new AbortController();
85
+ var cancelled = false;
86
+ var run = function () { return __awaiter(_this, void 0, void 0, function () {
87
+ var phase, requestOptions, checkUrl, configuration, _a, initialization, _b, error_1, failed;
88
+ return __generator(this, function (_c) {
89
+ switch (_c.label) {
90
+ case 0:
91
+ phase = "config";
92
+ setBusy(true);
93
+ setActivated(false);
94
+ setActivationError("");
95
+ setConfig({ status: "running", message: "Checking configuration and required secrets…" });
96
+ setInit({ status: "waiting", message: "Waiting for configuration to pass." });
97
+ _c.label = 1;
98
+ case 1:
99
+ _c.trys.push([1, 5, 6, 7]);
100
+ requestOptions = { signal: controller.signal, timeout: 60000 };
101
+ checkUrl = "/agent-tool-registry/".concat(toolId, "/check");
102
+ _a = unwrapReport;
103
+ return [4 /*yield*/, solidPost(checkUrl, { checksum: checksum, phase: "config" }, requestOptions)];
104
+ case 2:
105
+ configuration = _a.apply(void 0, [_c.sent()]);
106
+ if (configuration.toolId !== toolId || configuration.checksum !== checksum)
107
+ throw new Error("The server checked a different tool version.");
108
+ if (cancelled)
109
+ return [2 /*return*/];
110
+ setConfig(configuration.config);
111
+ if (configuration.config.status !== "passed") {
112
+ setInit({ status: "skipped", message: "Configuration must pass before initialization can run." });
113
+ return [2 /*return*/];
114
+ }
115
+ phase = "init";
116
+ setInit({ status: "running", message: "Running the tool’s initialization check…" });
117
+ _b = unwrapReport;
118
+ return [4 /*yield*/, solidPost(checkUrl, { checksum: checksum, phase: "init" }, requestOptions)];
119
+ case 3:
120
+ initialization = _b.apply(void 0, [_c.sent()]);
121
+ if (initialization.toolId !== toolId || initialization.checksum !== checksum)
122
+ throw new Error("The server checked a different tool version.");
123
+ if (cancelled)
124
+ return [2 /*return*/];
125
+ setConfig(initialization.config);
126
+ setInit(initialization.init);
127
+ if (initialization.config.status !== "passed" || initialization.init.status !== "passed")
128
+ return [2 /*return*/];
129
+ phase = "activate";
130
+ return [4 /*yield*/, callbacks.current.onActivated()];
131
+ case 4:
132
+ _c.sent();
133
+ if (cancelled)
134
+ return [2 /*return*/];
135
+ setActivated(true);
136
+ return [3 /*break*/, 7];
137
+ case 5:
138
+ error_1 = _c.sent();
139
+ if (cancelled)
140
+ return [2 /*return*/];
141
+ failed = { status: "failed", message: errorMessage(error_1) };
142
+ if (phase === "config") {
143
+ setConfig(failed);
144
+ setInit({ status: "skipped", message: "Configuration must pass before initialization can run." });
145
+ }
146
+ else if (phase === "init")
147
+ setInit(failed);
148
+ else
149
+ setActivationError(errorMessage(error_1));
150
+ return [3 /*break*/, 7];
151
+ case 6:
152
+ if (!cancelled)
153
+ setBusy(false);
154
+ return [7 /*endfinally*/];
155
+ case 7: return [2 /*return*/];
156
+ }
157
+ });
158
+ }); };
159
+ // Avoid duplicate requests during React StrictMode effect replay.
160
+ var timer = setTimeout(function () { return void run(); }, 0);
161
+ return function () { cancelled = true; clearTimeout(timer); controller.abort(); };
162
+ }, [open, toolId, checksum, attempt]);
163
+ return _jsx(SolidDialog, { open: open, onOpenChange: function (next) { if (!busy)
164
+ onOpenChange(next); }, className: busy ? "agent-tool-activation-dialog is-checking" : "agent-tool-activation-dialog", header: "Activate tool", dismissible: !busy, style: { width: "min(36rem, 94vw)" }, footer: _jsxs(_Fragment, { children: [_jsx(SolidButton, { variant: "secondary", disabled: busy, onClick: function () { return onOpenChange(false); }, children: activated ? "Done" : "Close" }), !activated && _jsx(SolidButton, { loading: busy, onClick: function () { setBusy(true); setAttempt(function (value) { return value + 1; }); }, children: busy ? "Checking…" : "Retry checks" })] }), children: _jsx(SolidDialogBody, { children: _jsxs("div", { className: "agent-tool-activation", "aria-live": "polite", "aria-busy": busy, children: [_jsxs("p", { className: "agent-tool-activation__intro", children: [_jsx("strong", { children: toolName }), " will activate after configuration and initialization both pass."] }), _jsx(CheckStep, { title: "Configuration", step: config, number: 1 }), _jsx(CheckStep, { title: "Initialization", step: init, number: 2 }), activated ? _jsxs("div", { className: "agent-tool-activation__success", role: "status", children: [_jsx(ShieldCheck, { size: 20 }), _jsxs("div", { children: [_jsx("strong", { children: "Tool activated" }), _jsx("p", { children: "Both checks passed. Restart linked agent processes to apply the change." })] })] }) : !busy && _jsx("p", { className: "agent-tool-activation__failure", role: "alert", children: activationError ? "Checks passed, but activation failed: ".concat(activationError) : "The tool remains inactive. Resolve the reported issue and retry the checks." })] }) }) });
165
+ }
166
+ //# sourceMappingURL=AgentToolActivationDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentToolActivationDialog.js","sourceRoot":"","sources":["../../../../../src/routes/pages/admin/core/AgentToolActivationDialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from \"react\";\nimport { CheckCircle2, Circle, Loader2, ShieldCheck, XCircle } from \"lucide-react\";\nimport { solidPost } from \"../../../../http/solidHttp\";\nimport { SolidButton, SolidDialog, SolidDialogBody } from \"../../../../components/shad-cn-ui\";\n\ntype Step = {\n status: \"waiting\" | \"running\" | \"passed\" | \"failed\" | \"skipped\";\n message: string;\n requiredSecrets?: string[];\n missingSecrets?: string[];\n};\ntype Report = { toolId?: number; checksum?: string; config: Step; init: Step };\ntype Props = {\n open: boolean;\n toolId: number;\n checksum: string;\n toolName: string;\n onOpenChange: (open: boolean) => void;\n onActivated: () => Promise<void>;\n};\n\nfunction unwrapReport(response: any): Report {\n let value = response?.data;\n for (let depth = 0; depth < 5 && value; depth += 1) {\n if (value.config && value.init) return value as Report;\n value = value.data;\n }\n throw new Error(\"The server returned an invalid tool check result.\");\n}\n\nfunction errorMessage(error: any): string {\n const body = error?.response?.data;\n const message = body?.data?.message ?? body?.message ?? body?.detail ?? error?.message;\n return Array.isArray(message) ? message.join(\" \") : typeof message === \"string\" ? message : \"Checks failed. Please retry.\";\n}\n\nfunction CheckStep({ title, step, number }: { title: string; step: Step; number: number }) {\n const Icon = step.status === \"running\" ? Loader2 : step.status === \"passed\" ? CheckCircle2\n : step.status === \"failed\" ? XCircle : Circle;\n const label = step.status === \"running\" ? \"Checking\" : step.status === \"waiting\" ? \"Waiting\" : step.status;\n return <section className={`agent-tool-check is-${step.status}`} aria-label={`${title}: ${label}`}>\n <div className=\"agent-tool-check__icon\"><Icon size={23} className={step.status === \"running\" ? \"is-spinning\" : undefined} /></div>\n <div className=\"agent-tool-check__content\">\n <div className=\"agent-tool-check__heading\"><h3>{number}. {title}</h3><span>{label}</span></div>\n <p>{step.message}</p>\n {!!step.requiredSecrets?.length && <ul className=\"agent-tool-check__secrets\" aria-label=\"Required secrets\">\n {step.requiredSecrets.map((name) => {\n const missing = step.missingSecrets?.includes(name);\n const verified = step.status === \"passed\" || Boolean(step.missingSecrets?.length);\n return <li key={name} className={missing ? \"is-missing\" : verified ? \"is-available\" : \"\"}>\n <code>{name}</code><span>{missing ? \"Missing, empty, or inactive\" : verified ? \"Available\" : \"Not verified\"}</span>\n </li>;\n })}\n </ul>}\n </div>\n </section>;\n}\n\nexport function AgentToolActivationDialog({ open, toolId, checksum, toolName, onOpenChange, onActivated }: Props) {\n const [config, setConfig] = React.useState<Step>({ status: \"running\", message: \"Checking configuration and required secrets…\" });\n const [init, setInit] = React.useState<Step>({ status: \"waiting\", message: \"Waiting for configuration to pass.\" });\n const [busy, setBusy] = React.useState(true);\n const [activated, setActivated] = React.useState(false);\n const [activationError, setActivationError] = React.useState(\"\");\n const [attempt, setAttempt] = React.useState(0);\n const callbacks = React.useRef({ onActivated });\n callbacks.current = { onActivated };\n\n React.useEffect(() => {\n if (!open) return;\n const controller = new AbortController();\n let cancelled = false;\n const run = async () => {\n let phase: \"config\" | \"init\" | \"activate\" = \"config\";\n setBusy(true);\n setActivated(false);\n setActivationError(\"\");\n setConfig({ status: \"running\", message: \"Checking configuration and required secrets…\" });\n setInit({ status: \"waiting\", message: \"Waiting for configuration to pass.\" });\n try {\n const requestOptions = { signal: controller.signal, timeout: 60000 };\n const checkUrl = `/agent-tool-registry/${toolId}/check`;\n const configuration = unwrapReport(await solidPost(checkUrl, { checksum, phase: \"config\" }, requestOptions));\n if (configuration.toolId !== toolId || configuration.checksum !== checksum) throw new Error(\"The server checked a different tool version.\");\n if (cancelled) return;\n setConfig(configuration.config);\n if (configuration.config.status !== \"passed\") {\n setInit({ status: \"skipped\", message: \"Configuration must pass before initialization can run.\" });\n return;\n }\n phase = \"init\";\n setInit({ status: \"running\", message: \"Running the tool’s initialization check…\" });\n const initialization = unwrapReport(await solidPost(checkUrl, { checksum, phase: \"init\" }, requestOptions));\n if (initialization.toolId !== toolId || initialization.checksum !== checksum) throw new Error(\"The server checked a different tool version.\");\n if (cancelled) return;\n setConfig(initialization.config);\n setInit(initialization.init);\n if (initialization.config.status !== \"passed\" || initialization.init.status !== \"passed\") return;\n phase = \"activate\";\n await callbacks.current.onActivated();\n if (cancelled) return;\n setActivated(true);\n } catch (error) {\n if (cancelled) return;\n const failed: Step = { status: \"failed\", message: errorMessage(error) };\n if (phase === \"config\") {\n setConfig(failed);\n setInit({ status: \"skipped\", message: \"Configuration must pass before initialization can run.\" });\n } else if (phase === \"init\") setInit(failed);\n else setActivationError(errorMessage(error));\n } finally {\n if (!cancelled) setBusy(false);\n }\n };\n // Avoid duplicate requests during React StrictMode effect replay.\n const timer = setTimeout(() => void run(), 0);\n return () => { cancelled = true; clearTimeout(timer); controller.abort(); };\n }, [open, toolId, checksum, attempt]);\n\n return <SolidDialog open={open} onOpenChange={(next) => { if (!busy) onOpenChange(next); }}\n className={busy ? \"agent-tool-activation-dialog is-checking\" : \"agent-tool-activation-dialog\"}\n header=\"Activate tool\" dismissible={!busy} style={{ width: \"min(36rem, 94vw)\" }}\n footer={<>\n <SolidButton variant=\"secondary\" disabled={busy} onClick={() => onOpenChange(false)}>{activated ? \"Done\" : \"Close\"}</SolidButton>\n {!activated && <SolidButton loading={busy} onClick={() => { setBusy(true); setAttempt((value) => value + 1); }}>\n {busy ? \"Checking…\" : \"Retry checks\"}\n </SolidButton>}\n </>}>\n <SolidDialogBody>\n <div className=\"agent-tool-activation\" aria-live=\"polite\" aria-busy={busy}>\n <p className=\"agent-tool-activation__intro\"><strong>{toolName}</strong> will activate after configuration and initialization both pass.</p>\n <CheckStep title=\"Configuration\" step={config} number={1} />\n <CheckStep title=\"Initialization\" step={init} number={2} />\n {activated ? <div className=\"agent-tool-activation__success\" role=\"status\"><ShieldCheck size={20} />\n <div><strong>Tool activated</strong><p>Both checks passed. Restart linked agent processes to apply the change.</p></div>\n </div> : !busy && <p className=\"agent-tool-activation__failure\" role=\"alert\">{activationError ? `Checks passed, but activation failed: ${activationError}` : \"The tool remains inactive. Resolve the reported issue and retry the checks.\"}</p>}\n </div>\n </SolidDialogBody>\n </SolidDialog>;\n}\n"]}
@@ -0,0 +1,140 @@
1
+ import React from "react";
2
+ import { CheckCircle2, Circle, Loader2, ShieldCheck, XCircle } from "lucide-react";
3
+ import { solidPost } from "../../../../http/solidHttp";
4
+ import { SolidButton, SolidDialog, SolidDialogBody } from "../../../../components/shad-cn-ui";
5
+
6
+ type Step = {
7
+ status: "waiting" | "running" | "passed" | "failed" | "skipped";
8
+ message: string;
9
+ requiredSecrets?: string[];
10
+ missingSecrets?: string[];
11
+ };
12
+ type Report = { toolId?: number; checksum?: string; config: Step; init: Step };
13
+ type Props = {
14
+ open: boolean;
15
+ toolId: number;
16
+ checksum: string;
17
+ toolName: string;
18
+ onOpenChange: (open: boolean) => void;
19
+ onActivated: () => Promise<void>;
20
+ };
21
+
22
+ function unwrapReport(response: any): Report {
23
+ let value = response?.data;
24
+ for (let depth = 0; depth < 5 && value; depth += 1) {
25
+ if (value.config && value.init) return value as Report;
26
+ value = value.data;
27
+ }
28
+ throw new Error("The server returned an invalid tool check result.");
29
+ }
30
+
31
+ function errorMessage(error: any): string {
32
+ const body = error?.response?.data;
33
+ const message = body?.data?.message ?? body?.message ?? body?.detail ?? error?.message;
34
+ return Array.isArray(message) ? message.join(" ") : typeof message === "string" ? message : "Checks failed. Please retry.";
35
+ }
36
+
37
+ function CheckStep({ title, step, number }: { title: string; step: Step; number: number }) {
38
+ const Icon = step.status === "running" ? Loader2 : step.status === "passed" ? CheckCircle2
39
+ : step.status === "failed" ? XCircle : Circle;
40
+ const label = step.status === "running" ? "Checking" : step.status === "waiting" ? "Waiting" : step.status;
41
+ return <section className={`agent-tool-check is-${step.status}`} aria-label={`${title}: ${label}`}>
42
+ <div className="agent-tool-check__icon"><Icon size={23} className={step.status === "running" ? "is-spinning" : undefined} /></div>
43
+ <div className="agent-tool-check__content">
44
+ <div className="agent-tool-check__heading"><h3>{number}. {title}</h3><span>{label}</span></div>
45
+ <p>{step.message}</p>
46
+ {!!step.requiredSecrets?.length && <ul className="agent-tool-check__secrets" aria-label="Required secrets">
47
+ {step.requiredSecrets.map((name) => {
48
+ const missing = step.missingSecrets?.includes(name);
49
+ const verified = step.status === "passed" || Boolean(step.missingSecrets?.length);
50
+ return <li key={name} className={missing ? "is-missing" : verified ? "is-available" : ""}>
51
+ <code>{name}</code><span>{missing ? "Missing, empty, or inactive" : verified ? "Available" : "Not verified"}</span>
52
+ </li>;
53
+ })}
54
+ </ul>}
55
+ </div>
56
+ </section>;
57
+ }
58
+
59
+ export function AgentToolActivationDialog({ open, toolId, checksum, toolName, onOpenChange, onActivated }: Props) {
60
+ const [config, setConfig] = React.useState<Step>({ status: "running", message: "Checking configuration and required secrets…" });
61
+ const [init, setInit] = React.useState<Step>({ status: "waiting", message: "Waiting for configuration to pass." });
62
+ const [busy, setBusy] = React.useState(true);
63
+ const [activated, setActivated] = React.useState(false);
64
+ const [activationError, setActivationError] = React.useState("");
65
+ const [attempt, setAttempt] = React.useState(0);
66
+ const callbacks = React.useRef({ onActivated });
67
+ callbacks.current = { onActivated };
68
+
69
+ React.useEffect(() => {
70
+ if (!open) return;
71
+ const controller = new AbortController();
72
+ let cancelled = false;
73
+ const run = async () => {
74
+ let phase: "config" | "init" | "activate" = "config";
75
+ setBusy(true);
76
+ setActivated(false);
77
+ setActivationError("");
78
+ setConfig({ status: "running", message: "Checking configuration and required secrets…" });
79
+ setInit({ status: "waiting", message: "Waiting for configuration to pass." });
80
+ try {
81
+ const requestOptions = { signal: controller.signal, timeout: 60000 };
82
+ const checkUrl = `/agent-tool-registry/${toolId}/check`;
83
+ const configuration = unwrapReport(await solidPost(checkUrl, { checksum, phase: "config" }, requestOptions));
84
+ if (configuration.toolId !== toolId || configuration.checksum !== checksum) throw new Error("The server checked a different tool version.");
85
+ if (cancelled) return;
86
+ setConfig(configuration.config);
87
+ if (configuration.config.status !== "passed") {
88
+ setInit({ status: "skipped", message: "Configuration must pass before initialization can run." });
89
+ return;
90
+ }
91
+ phase = "init";
92
+ setInit({ status: "running", message: "Running the tool’s initialization check…" });
93
+ const initialization = unwrapReport(await solidPost(checkUrl, { checksum, phase: "init" }, requestOptions));
94
+ if (initialization.toolId !== toolId || initialization.checksum !== checksum) throw new Error("The server checked a different tool version.");
95
+ if (cancelled) return;
96
+ setConfig(initialization.config);
97
+ setInit(initialization.init);
98
+ if (initialization.config.status !== "passed" || initialization.init.status !== "passed") return;
99
+ phase = "activate";
100
+ await callbacks.current.onActivated();
101
+ if (cancelled) return;
102
+ setActivated(true);
103
+ } catch (error) {
104
+ if (cancelled) return;
105
+ const failed: Step = { status: "failed", message: errorMessage(error) };
106
+ if (phase === "config") {
107
+ setConfig(failed);
108
+ setInit({ status: "skipped", message: "Configuration must pass before initialization can run." });
109
+ } else if (phase === "init") setInit(failed);
110
+ else setActivationError(errorMessage(error));
111
+ } finally {
112
+ if (!cancelled) setBusy(false);
113
+ }
114
+ };
115
+ // Avoid duplicate requests during React StrictMode effect replay.
116
+ const timer = setTimeout(() => void run(), 0);
117
+ return () => { cancelled = true; clearTimeout(timer); controller.abort(); };
118
+ }, [open, toolId, checksum, attempt]);
119
+
120
+ return <SolidDialog open={open} onOpenChange={(next) => { if (!busy) onOpenChange(next); }}
121
+ className={busy ? "agent-tool-activation-dialog is-checking" : "agent-tool-activation-dialog"}
122
+ header="Activate tool" dismissible={!busy} style={{ width: "min(36rem, 94vw)" }}
123
+ footer={<>
124
+ <SolidButton variant="secondary" disabled={busy} onClick={() => onOpenChange(false)}>{activated ? "Done" : "Close"}</SolidButton>
125
+ {!activated && <SolidButton loading={busy} onClick={() => { setBusy(true); setAttempt((value) => value + 1); }}>
126
+ {busy ? "Checking…" : "Retry checks"}
127
+ </SolidButton>}
128
+ </>}>
129
+ <SolidDialogBody>
130
+ <div className="agent-tool-activation" aria-live="polite" aria-busy={busy}>
131
+ <p className="agent-tool-activation__intro"><strong>{toolName}</strong> will activate after configuration and initialization both pass.</p>
132
+ <CheckStep title="Configuration" step={config} number={1} />
133
+ <CheckStep title="Initialization" step={init} number={2} />
134
+ {activated ? <div className="agent-tool-activation__success" role="status"><ShieldCheck size={20} />
135
+ <div><strong>Tool activated</strong><p>Both checks passed. Restart linked agent processes to apply the change.</p></div>
136
+ </div> : !busy && <p className="agent-tool-activation__failure" role="alert">{activationError ? `Checks passed, but activation failed: ${activationError}` : "The tool remains inactive. Resolve the reported issue and retry the checks."}</p>}
137
+ </div>
138
+ </SolidDialogBody>
139
+ </SolidDialog>;
140
+ }
@@ -122,4 +122,30 @@
122
122
  @media(max-width:900px) { .agent-tool-editor__sessions { height:auto; min-height:0; grid-template-columns:minmax(0,1fr); grid-template-rows:auto minmax(24rem,1fr); max-height:none; } .agent-tool-editor__sessions-sidebar { max-height:18rem; border-right:0; border-bottom:1px solid var(--surface-border,var(--border)); } .agent-tool-editor__event-filters>label { flex:1 1 8rem; } }
123
123
  @media(max-width:600px) { .agent-tool-editor { padding:1rem; } .agent-tool-editor__header { align-items:flex-start; flex-direction:column; } .agent-tool-editor__actions { width:100%; } }
124
124
  fieldset.agent-tool-editor__general { min-width:0; margin:0; padding:0; border:0; }
125
+ .agent-tool-activation { display:flex; flex-direction:column; gap:1rem; }
126
+ .agent-tool-activation-dialog.is-checking .solid-radix-dialog-close { visibility:hidden; }
127
+ .agent-tool-activation__intro { margin:0 0 .25rem; color:var(--text-color-secondary,var(--muted-foreground)); line-height:1.6; }
128
+ .agent-tool-activation__intro strong { color:var(--text-color,var(--foreground)); }
129
+ .agent-tool-check { display:flex; align-items:flex-start; gap:.85rem; padding:1rem; border:1px solid var(--surface-border,var(--border)); border-radius:.75rem; background:var(--surface-ground,var(--background)); }
130
+ .agent-tool-check__icon { display:flex; flex:0 0 2.4rem; align-items:center; justify-content:center; height:2.4rem; border-radius:50%; background:var(--surface-card,var(--card)); color:var(--text-color-secondary,var(--muted-foreground)); }
131
+ .agent-tool-check__content { flex:1; min-width:0; }
132
+ .agent-tool-check__heading { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:.5rem; }
133
+ .agent-tool-check__heading h3 { margin:0; font-size:.95rem; }
134
+ .agent-tool-check__heading>span { padding:.15rem .55rem; border:1px solid currentColor; border-radius:999px; font-size:.7rem; font-weight:650; text-transform:capitalize; }
135
+ .agent-tool-check p { margin:.45rem 0 0; font-size:.82rem; line-height:1.5; overflow-wrap:anywhere; color:var(--text-color-secondary,var(--muted-foreground)); }
136
+ .agent-tool-check.is-running .agent-tool-check__icon,.agent-tool-check.is-running .agent-tool-check__heading>span { color:var(--primary-color,var(--primary)); }
137
+ .agent-tool-check.is-passed .agent-tool-check__icon,.agent-tool-check.is-passed .agent-tool-check__heading>span { color:#16a34a; }
138
+ .agent-tool-check.is-failed .agent-tool-check__icon,.agent-tool-check.is-failed .agent-tool-check__heading>span { color:#dc2626; }
139
+ .agent-tool-check__secrets { display:flex; flex-direction:column; gap:.4rem; padding:0; margin:.8rem 0 0; list-style:none; }
140
+ .agent-tool-check__secrets li { display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:.35rem; font-size:.75rem; }
141
+ .agent-tool-check__secrets code { overflow-wrap:anywhere; }
142
+ .agent-tool-check__secrets .is-available>span { color:#16a34a; }
143
+ .agent-tool-check__secrets .is-missing>span { color:#dc2626; }
144
+ .agent-tool-activation__success { display:flex; gap:.65rem; padding:.85rem 1rem; border-radius:.65rem; background:color-mix(in srgb,#16a34a 9%,var(--surface-card,var(--card))); color:#16a34a; }
145
+ .agent-tool-activation__success svg { flex-shrink:0; }
146
+ .agent-tool-activation__success p { margin:.25rem 0 0; font-size:.8rem; color:var(--text-color-secondary,var(--muted-foreground)); }
147
+ .agent-tool-activation__failure { margin:0; font-size:.82rem; color:var(--text-color-secondary,var(--muted-foreground)); }
148
+ .agent-tool-check .is-spinning { animation:agent-tool-check-spin 1s linear infinite; }
149
+ @keyframes agent-tool-check-spin { to { transform:rotate(360deg); } }
150
+ @media(prefers-reduced-motion:reduce) { .agent-tool-check .is-spinning { animation:none; } }
125
151
  .agent-tool-editor__readonly-note { margin:0; padding:.75rem 1rem; border:1px solid var(--surface-border,var(--border)); border-radius:.5rem; color:var(--text-color-secondary,var(--muted-foreground)); background:var(--surface-ground,var(--background)); font-size:.875rem; }
@@ -1 +1 @@
1
- {"version":3,"file":"AgentToolRegistryEditorPage.d.ts","sourceRoot":"","sources":["../../../../../src/routes/pages/admin/core/AgentToolRegistryEditorPage.tsx"],"names":[],"mappings":"AAUA,OAAO,mCAAmC,CAAC;AAuE3C,wBAAgB,2BAA2B,4CAiM1C"}
1
+ {"version":3,"file":"AgentToolRegistryEditorPage.d.ts","sourceRoot":"","sources":["../../../../../src/routes/pages/admin/core/AgentToolRegistryEditorPage.tsx"],"names":[],"mappings":"AAaA,OAAO,mCAAmC,CAAC;AA6D3C,wBAAgB,2BAA2B,4CAgN1C"}