@epam/ai-dial-chat-hooks 1.2.0-dev.14 → 1.2.0-dev.141
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/api-error/api-error.js +5 -4
- package/attachment/useAttachmentValidation/useAttachmentValidation.js +26 -19
- package/attachments.d.ts +10 -4
- package/catalog/map-deployment-to-catalog-item.js +2 -2
- package/catalog/map-skill-to-catalog-item.js +30 -27
- package/catalog/publish.js +2 -1
- package/catalog/useApplicationCredentials/useApplicationCredentials.js +39 -0
- package/catalog/useSkillDetailsPanelData/useSkillDetailsPanelData.js +39 -39
- package/catalog/useSkillItemDetails.js +17 -13
- package/catalog.d.ts +42 -5
- package/catalog.js +6 -5
- package/conversation/conversation-transfer/queue.js +8 -5
- package/conversation/create-chat-stream-api.js +30 -21
- package/conversation/stage.js +23 -0
- package/conversation/useAttachmentUpload/useAttachmentUpload.js +12 -5
- package/conversation/useConversationImport/useConversationImport.js +1 -1
- package/conversation/useConversationScroll/useConversationScroll.js +68 -64
- package/conversation/useConversationStream/apply-chunk.js +1 -1
- package/conversation/useConversationStream/generation-resume.js +75 -63
- package/conversation/useConversationStream/useConversationStream.js +145 -102
- package/conversation-overlay.d.ts +7 -0
- package/conversation-overlay.js +2 -0
- package/conversation-sources/useConversationSources/useConversationSources.js +31 -24
- package/conversation-sources.d.ts +1 -1
- package/conversation.d.ts +140 -8
- package/conversation.js +31 -30
- package/file-manager-canvas.d.ts +398 -0
- package/file-manager-canvas.js +2 -0
- package/file-manager.d.ts +71 -330
- package/file-manager.js +15 -15
- package/files/attachment-canvas.js +51 -13
- package/files/attachment-types.js +14 -13
- package/files/useDialFileManagerTabConfig/useDialFileManagerTabConfig.js +1 -5
- package/files/useFileAttachmentPicker/useFileAttachmentPicker.js +43 -0
- package/index.d.ts +750 -35
- package/index.js +123 -111
- package/mcp-apps/useMcpAppHostAdapter/useMcpAppHostAdapter.js +7 -5
- package/mcp-apps/useMcpAppHostContext/useMcpAppHostContext.js +1 -1
- package/mcp-apps/useMcpAppTools/useMcpAppTools.js +1 -1
- package/mcp-apps/useOpenMcpAppCanvas/useOpenMcpAppCanvas.js +25 -23
- package/mcp-apps.d.ts +8 -6
- package/package.json +37 -18
- package/scheduled-task/scheduled-task-description.js +77 -0
- package/scheduled-task/scheduled-task-preparation.js +24 -0
- package/scheduled-task/scheduled-task-trigger.js +7 -2
- package/scheduled-task/scheduled-tasks-api-client.js +19 -0
- package/scheduled-task/use-scheduled-task-runs.js +82 -0
- package/scheduled-task/use-scheduled-tasks.js +93 -0
- package/scheduled-tasks.d.ts +180 -3
- package/scheduled-tasks.js +7 -2
- package/skill/skill.js +10 -7
- package/skill/useSkillArchiveImport/useSkillArchiveImport.js +75 -0
- package/skill/useSkillEditorLoad.js +29 -28
- package/skill/useSkillEditorSubmit.js +92 -75
- package/skill-editor.d.ts +107 -0
- package/skill-editor.js +9 -8
- package/usage/map-usage-data-to-dashboard.js +66 -0
- package/usage/map-user-usage-to-model-limits.js +160 -0
- package/usage.d.ts +120 -0
- package/usage.js +3 -0
- package/utils.d.ts +3 -1
package/skill/skill.js
CHANGED
|
@@ -13,7 +13,10 @@ var i = "SKILL.md", a = 1048576, o = 16777216, s = 100, c = new Set([".dial-reso
|
|
|
13
13
|
...e,
|
|
14
14
|
name: t,
|
|
15
15
|
description: n
|
|
16
|
-
}).trimEnd()}\n---\n\n${i}`, g = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/, _ = (e) => {
|
|
16
|
+
}).trimEnd()}\n---\n\n${i}`, g = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/, _ = /^---[ \t]*$/, v = (e) => {
|
|
17
|
+
let t = e.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n").split("\n"), n = t.findIndex((e) => e.trim() !== "");
|
|
18
|
+
return n === -1 || !_.test(t[n]) ? !1 : t.some((e, t) => t > n && _.test(e));
|
|
19
|
+
}, y = (e) => {
|
|
17
20
|
let t = g.exec(e);
|
|
18
21
|
if (!t) throw Error("SKILL.md is missing its YAML frontmatter block");
|
|
19
22
|
let [, r, i] = t;
|
|
@@ -21,7 +24,7 @@ var i = "SKILL.md", a = 1048576, o = 16777216, s = 100, c = new Set([".dial-reso
|
|
|
21
24
|
frontmatter: n(r) ?? {},
|
|
22
25
|
instructions: i.replace(/^\r?\n/, "")
|
|
23
26
|
};
|
|
24
|
-
},
|
|
27
|
+
}, b = (e) => {
|
|
25
28
|
let n = t(e), r = n[i];
|
|
26
29
|
if (r == null) throw Error(`Skill archive is missing a root ${i} file`);
|
|
27
30
|
let a = /* @__PURE__ */ new Map();
|
|
@@ -30,19 +33,19 @@ var i = "SKILL.md", a = 1048576, o = 16777216, s = 100, c = new Set([".dial-reso
|
|
|
30
33
|
manifestText: new TextDecoder().decode(r),
|
|
31
34
|
files: a
|
|
32
35
|
};
|
|
33
|
-
},
|
|
36
|
+
}, x = (e) => {
|
|
34
37
|
let t = e.lastIndexOf("/");
|
|
35
38
|
return t === -1 ? e : e.slice(t + 1);
|
|
36
|
-
},
|
|
39
|
+
}, S = (e) => new Blob([new Uint8Array(e)]), C = (e, t, n, r) => Object.keys(e).length > 0 ? h(e, t, n, r) : m({
|
|
37
40
|
name: t,
|
|
38
41
|
description: n,
|
|
39
42
|
instructions: r
|
|
40
|
-
}),
|
|
43
|
+
}), w = (t, n) => {
|
|
41
44
|
let r = t.filter((t) => t.kind === e.File);
|
|
42
45
|
return {
|
|
43
46
|
filePaths: r.map((e) => e.path),
|
|
44
|
-
files: r.map((e) =>
|
|
47
|
+
files: r.map((e) => S(n.get(e.path)?.bytes ?? new Uint8Array()))
|
|
45
48
|
};
|
|
46
49
|
};
|
|
47
50
|
//#endregion
|
|
48
|
-
export { a as SKILL_FILE_UPLOAD_MAX_BYTES, i as SKILL_MANIFEST_FILE, s as SKILL_UPLOAD_MAX_FILES, o as SKILL_UPLOAD_MAX_TOTAL_BYTES,
|
|
51
|
+
export { a as SKILL_FILE_UPLOAD_MAX_BYTES, i as SKILL_MANIFEST_FILE, s as SKILL_UPLOAD_MAX_FILES, o as SKILL_UPLOAD_MAX_TOTAL_BYTES, w as buildSkillFilesPayload, m as buildSkillManifest, C as buildSkillManifestForSubmit, h as buildSkillManifestFromFrontmatter, f as isValidSkillRelativePath, x as nameFromPath, p as normalizeSkillName, y as parseSkillManifest, S as skillFileBytesToBlob, v as startsWithFrontmatterBlock, b as unpackSkillArchive };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { getApiErrorStatus as e } from "../../api-error/api-error.js";
|
|
2
|
+
import { useCallback as t, useEffect as n, useRef as r, useState as i } from "react";
|
|
3
|
+
//#region src/skill/useSkillArchiveImport/useSkillArchiveImport.ts
|
|
4
|
+
var a = "SKILL.md", o = /* @__PURE__ */ function(e) {
|
|
5
|
+
return e.Idle = "idle", e.Uploading = "uploading", e.Success = "success", e.Error = "error", e;
|
|
6
|
+
}({}), s = /* @__PURE__ */ function(e) {
|
|
7
|
+
return e.Validation = "validation", e.Collision = "collision", e.RateLimited = "rateLimited", e.ServiceUnavailable = "serviceUnavailable", e.Generic = "generic", e;
|
|
8
|
+
}({}), c = /* @__PURE__ */ function(e) {
|
|
9
|
+
return e.UnsupportedFilename = "unsupportedFilename", e;
|
|
10
|
+
}({}), l = (e) => {
|
|
11
|
+
switch (e) {
|
|
12
|
+
case 400:
|
|
13
|
+
case 413:
|
|
14
|
+
case 422: return "validation";
|
|
15
|
+
case 409: return "collision";
|
|
16
|
+
case 429: return "rateLimited";
|
|
17
|
+
case 502:
|
|
18
|
+
case 503: return "serviceUnavailable";
|
|
19
|
+
default: return "generic";
|
|
20
|
+
}
|
|
21
|
+
}, u = (e, t) => e.toLowerCase().endsWith(".md") && e !== t, d = ({ importArchive: o, onImported: s, onError: c, manifestFileName: d = a }) => {
|
|
22
|
+
let [f, p] = i(!1), [m, h] = i("idle"), [g, _] = i(void 0), [v, y] = i(void 0), b = r(!1), x = r(!0);
|
|
23
|
+
n(() => (x.current = !0, () => {
|
|
24
|
+
x.current = !1;
|
|
25
|
+
}), []);
|
|
26
|
+
let S = t(async (t) => {
|
|
27
|
+
b.current = !0, h("uploading"), y(void 0);
|
|
28
|
+
try {
|
|
29
|
+
let e = await o(t);
|
|
30
|
+
if (!x.current || (await s(e), !x.current)) return;
|
|
31
|
+
h("success");
|
|
32
|
+
} catch (t) {
|
|
33
|
+
if (!x.current) return;
|
|
34
|
+
let n = l(e(t));
|
|
35
|
+
h("error"), y(n), c(t, n);
|
|
36
|
+
} finally {
|
|
37
|
+
b.current = !1;
|
|
38
|
+
}
|
|
39
|
+
}, [
|
|
40
|
+
o,
|
|
41
|
+
s,
|
|
42
|
+
c
|
|
43
|
+
]), C = t(() => {
|
|
44
|
+
b.current || (_(void 0), p(!0));
|
|
45
|
+
}, []), w = t(() => {
|
|
46
|
+
p(!1), _(void 0);
|
|
47
|
+
}, []), T = t(() => {
|
|
48
|
+
h("error"), _("unsupportedFilename");
|
|
49
|
+
}, []);
|
|
50
|
+
return {
|
|
51
|
+
isDialogOpen: f,
|
|
52
|
+
status: m,
|
|
53
|
+
selectionRejectionReason: g,
|
|
54
|
+
errorKind: v,
|
|
55
|
+
openDialog: C,
|
|
56
|
+
closeDialog: w,
|
|
57
|
+
handleFilesSelected: t((e) => {
|
|
58
|
+
let t = e[0];
|
|
59
|
+
if (!(!t || b.current)) {
|
|
60
|
+
if (u(t.name, d)) {
|
|
61
|
+
T();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
_(void 0), p(!1), S(t);
|
|
65
|
+
}
|
|
66
|
+
}, [
|
|
67
|
+
d,
|
|
68
|
+
T,
|
|
69
|
+
S
|
|
70
|
+
]),
|
|
71
|
+
handleFilesRejected: T
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { s as SkillArchiveImportErrorKind, o as SkillArchiveImportStatus, c as SkillArchiveSelectionRejectionReason, l as classifySkillArchiveImportError, d as useSkillArchiveImport };
|
|
@@ -6,12 +6,12 @@ import { SkillFileNodeKind as u } from "@epam/ai-dial-skill-editor";
|
|
|
6
6
|
//#region src/skill/useSkillEditorLoad.ts
|
|
7
7
|
var d = /* @__PURE__ */ function(e) {
|
|
8
8
|
return e.Loading = "loading", e.Loaded = "loaded", e.Error = "error", e.Forbidden = "forbidden", e.NotFound = "not-found", e;
|
|
9
|
-
}({}), f = class extends Error {}, p = (e, r) => {
|
|
9
|
+
}({}), f = class extends Error {}, p = class extends Error {}, m = (e, r) => {
|
|
10
10
|
let i = e.parentPath ? t(e.parentPath) : "", a = `${n(r)}/files`;
|
|
11
11
|
return i === a ? e.name : i.startsWith(`${a}/`) ? `${i.slice(a.length + 1)}/${e.name}` : i === "files" ? e.name : i.startsWith("files/") ? `${i.slice(6)}/${e.name}` : null;
|
|
12
|
-
},
|
|
12
|
+
}, h = async (e, t, n) => {
|
|
13
13
|
let r = await e.downloadSkill(t, n), i = r.headers.get("etag");
|
|
14
|
-
if (!i) throw new
|
|
14
|
+
if (!i) throw new p("Skill ETag is missing");
|
|
15
15
|
try {
|
|
16
16
|
let e = await r.arrayBuffer(), { manifestText: t, files: n } = o(new Uint8Array(e));
|
|
17
17
|
return {
|
|
@@ -22,17 +22,17 @@ var d = /* @__PURE__ */ function(e) {
|
|
|
22
22
|
} catch {
|
|
23
23
|
throw new f("Skill ZIP is invalid");
|
|
24
24
|
}
|
|
25
|
-
},
|
|
25
|
+
}, g = async (e, t, n) => {
|
|
26
26
|
let [i, a] = await Promise.all([e.downloadSkillFile(t, n, r), e.listSkillFiles({
|
|
27
27
|
bucket: t,
|
|
28
28
|
path: n,
|
|
29
29
|
filePath: "",
|
|
30
30
|
recursive: !0
|
|
31
|
-
})]), o = a.items.find((e) => e.nodeType === "item" &&
|
|
32
|
-
if (!s) throw
|
|
31
|
+
})]), o = a.items.find((e) => e.nodeType === "item" && m(e, n) === "SKILL.md"), s = i.headers.get("etag") ?? o?.etag;
|
|
32
|
+
if (!s) throw new p("Skill ETag is missing");
|
|
33
33
|
let c = a.items.filter((e) => e.nodeType === "item").map((e) => ({
|
|
34
34
|
item: e,
|
|
35
|
-
path:
|
|
35
|
+
path: m(e, n)
|
|
36
36
|
})).filter((e) => e.path != null && e.path !== "SKILL.md"), l = await Promise.all(c.map(async ({ path: r }) => {
|
|
37
37
|
let i = await e.downloadSkillFile(t, n, r);
|
|
38
38
|
return [r, new Uint8Array(await i.arrayBuffer())];
|
|
@@ -42,40 +42,41 @@ var d = /* @__PURE__ */ function(e) {
|
|
|
42
42
|
manifestText: await i.text(),
|
|
43
43
|
files: new Map(l)
|
|
44
44
|
};
|
|
45
|
-
},
|
|
46
|
-
let [d,
|
|
45
|
+
}, _ = ({ isEditMode: t, bucket: n, skillPath: r, client: o }) => {
|
|
46
|
+
let [d, m] = l(t ? "loading" : "loaded"), [_, v] = l(0), [y, b] = l(), x = c(void 0), S = c({}), C = c(void 0), [w, T] = l([]), E = c(/* @__PURE__ */ new Map());
|
|
47
47
|
return s(() => {
|
|
48
48
|
if (!t || !n) return;
|
|
49
49
|
if (r == null) {
|
|
50
|
-
|
|
50
|
+
m("error");
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
let s = !1;
|
|
54
|
-
return
|
|
54
|
+
return m("loading"), (async () => {
|
|
55
55
|
if (await Promise.resolve(), !s) try {
|
|
56
56
|
let t;
|
|
57
57
|
try {
|
|
58
|
-
t = await
|
|
58
|
+
t = await h(o, n, r);
|
|
59
59
|
} catch (i) {
|
|
60
|
+
if (i instanceof p) throw i;
|
|
60
61
|
let a = e(i);
|
|
61
62
|
if (!(i instanceof f) && a !== 400) throw i;
|
|
62
|
-
t = await
|
|
63
|
+
t = await g(o, n, r);
|
|
63
64
|
}
|
|
64
65
|
let { frontmatter: c, instructions: l } = a(t.manifestText);
|
|
65
66
|
if (s) return;
|
|
66
|
-
|
|
67
|
+
x.current = t.etag, S.current = c, C.current = r, E.current = new Map([...t.files].map(([e, t]) => [e, { bytes: t }])), T([...t.files.keys()].map((e) => ({
|
|
67
68
|
path: e,
|
|
68
69
|
name: i(e),
|
|
69
70
|
kind: u.File
|
|
70
|
-
}))),
|
|
71
|
+
}))), b({
|
|
71
72
|
name: typeof c.name == "string" ? c.name : "",
|
|
72
73
|
description: typeof c.description == "string" ? c.description : "",
|
|
73
74
|
instructions: l
|
|
74
|
-
}),
|
|
75
|
+
}), m("loaded");
|
|
75
76
|
} catch (t) {
|
|
76
77
|
if (s) return;
|
|
77
78
|
let n = e(t);
|
|
78
|
-
|
|
79
|
+
m(n === 403 ? "forbidden" : n === 404 ? "not-found" : "error");
|
|
79
80
|
}
|
|
80
81
|
})(), () => {
|
|
81
82
|
s = !0;
|
|
@@ -84,20 +85,20 @@ var d = /* @__PURE__ */ function(e) {
|
|
|
84
85
|
t,
|
|
85
86
|
n,
|
|
86
87
|
r,
|
|
87
|
-
|
|
88
|
+
_,
|
|
88
89
|
o
|
|
89
90
|
]), {
|
|
90
91
|
loadState: d,
|
|
91
|
-
loadedValues:
|
|
92
|
-
setLoadedValues:
|
|
93
|
-
files:
|
|
94
|
-
setFiles:
|
|
95
|
-
filesContentRef:
|
|
96
|
-
frontmatterRef:
|
|
97
|
-
etagRef:
|
|
98
|
-
loadedPathRef:
|
|
99
|
-
retryLoad: () =>
|
|
92
|
+
loadedValues: y,
|
|
93
|
+
setLoadedValues: b,
|
|
94
|
+
files: w,
|
|
95
|
+
setFiles: T,
|
|
96
|
+
filesContentRef: E,
|
|
97
|
+
frontmatterRef: S,
|
|
98
|
+
etagRef: x,
|
|
99
|
+
loadedPathRef: C,
|
|
100
|
+
retryLoad: () => v((e) => e + 1)
|
|
100
101
|
};
|
|
101
102
|
};
|
|
102
103
|
//#endregion
|
|
103
|
-
export { d as SkillEditorLoadState,
|
|
104
|
+
export { d as SkillEditorLoadState, _ as useSkillEditorLoad };
|
|
@@ -1,135 +1,152 @@
|
|
|
1
1
|
import { getApiErrorDetails as e, getApiErrorStatus as t } from "../api-error/api-error.js";
|
|
2
|
-
import { buildSkillFilesPayload as n, buildSkillManifestForSubmit as r, isValidSkillRelativePath as i, normalizeSkillName as a } from "./skill.js";
|
|
3
|
-
import { useCallback as
|
|
4
|
-
import { NotificationVariant as
|
|
2
|
+
import { buildSkillFilesPayload as n, buildSkillManifestForSubmit as r, isValidSkillRelativePath as i, normalizeSkillName as a, startsWithFrontmatterBlock as o } from "./skill.js";
|
|
3
|
+
import { useCallback as s, useRef as c, useState as l } from "react";
|
|
4
|
+
import { NotificationVariant as u } from "@epam/ai-dial-ui-kit";
|
|
5
5
|
//#region src/skill/useSkillEditorSubmit.ts
|
|
6
|
-
var
|
|
6
|
+
var d = (e, t) => JSON.stringify({
|
|
7
7
|
values: e,
|
|
8
8
|
files: [...t].sort((e, t) => e.path.localeCompare(t.path))
|
|
9
|
-
}),
|
|
10
|
-
let [
|
|
9
|
+
}), f = ({ bucket: f, isEditMode: p, files: m, filesContentRef: h, frontmatterRef: g, loadedPathRef: _, etagRef: v, returnUrl: y, refetchSkills: b, client: x, messages: S, onNavigate: C, onNotify: w }) => {
|
|
10
|
+
let [T, E] = l({}), [D, O] = l(), [k, A] = l(!1), [j, M] = l(), [N, P] = l("idle"), F = c(null), I = c(null), L = s(async (n) => {
|
|
11
11
|
switch (t(n)) {
|
|
12
12
|
case 409:
|
|
13
|
-
|
|
13
|
+
E({ name: S.nameConflict });
|
|
14
14
|
return;
|
|
15
15
|
case 412:
|
|
16
|
-
|
|
16
|
+
E({ name: S.nameConflict });
|
|
17
17
|
return;
|
|
18
18
|
case 413:
|
|
19
|
-
|
|
19
|
+
O(S.archiveTooLarge);
|
|
20
20
|
return;
|
|
21
21
|
case 503:
|
|
22
|
-
|
|
22
|
+
O(S.serviceUnavailable), A(!0);
|
|
23
23
|
return;
|
|
24
24
|
case 400: {
|
|
25
25
|
let { message: t } = await e(n);
|
|
26
|
-
|
|
26
|
+
O(t ?? S.pathInvalid);
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
default: {
|
|
30
30
|
let { traceId: t } = await e(n);
|
|
31
|
-
|
|
32
|
-
variant:
|
|
33
|
-
message:
|
|
31
|
+
O(S.saveError), w({
|
|
32
|
+
variant: u.Error,
|
|
33
|
+
message: S.saveError,
|
|
34
34
|
requestId: t
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
}, [
|
|
38
|
+
}, [S, w]), R = s(async (e) => {
|
|
39
39
|
let t = a(e.name);
|
|
40
40
|
if (!t || !i(t)) {
|
|
41
|
-
|
|
41
|
+
E({ name: S.nameInvalid });
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
let o =
|
|
45
|
-
c ? {skillManifest:
|
|
44
|
+
let o = d(e, m), s = F.current, c = s != null && s.fingerprint === o, l = t, p, _, v;
|
|
45
|
+
c ? {skillManifest: p, filePaths: _, files: v} = s : (p = r(g.current, t, e.description, e.instructions), {filePaths: _, files: v} = n(m, h.current)), P("submitting"), F.current = {
|
|
46
46
|
fingerprint: o,
|
|
47
|
-
bucket:
|
|
48
|
-
path:
|
|
49
|
-
skillManifest:
|
|
47
|
+
bucket: f,
|
|
48
|
+
path: l,
|
|
49
|
+
skillManifest: p,
|
|
50
50
|
filePaths: _,
|
|
51
|
-
files:
|
|
51
|
+
files: v
|
|
52
52
|
};
|
|
53
53
|
try {
|
|
54
|
-
await
|
|
55
|
-
variant:
|
|
56
|
-
title:
|
|
57
|
-
message:
|
|
58
|
-
}),
|
|
54
|
+
await x.createSkill(f, l, p, _, v), await b(), P("success"), w({
|
|
55
|
+
variant: u.Success,
|
|
56
|
+
title: S.saveSuccessTitle,
|
|
57
|
+
message: S.createSuccess(t)
|
|
58
|
+
}), C(y);
|
|
59
59
|
} catch (e) {
|
|
60
|
-
|
|
60
|
+
P("failure"), await L(e);
|
|
61
61
|
}
|
|
62
62
|
}, [
|
|
63
|
-
|
|
64
|
-
p,
|
|
63
|
+
f,
|
|
65
64
|
m,
|
|
66
65
|
h,
|
|
66
|
+
g,
|
|
67
|
+
S,
|
|
67
68
|
x,
|
|
68
|
-
|
|
69
|
+
w,
|
|
69
70
|
C,
|
|
70
|
-
S,
|
|
71
|
-
v,
|
|
72
71
|
y,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
b,
|
|
73
|
+
L
|
|
74
|
+
]), z = s(async (e) => {
|
|
75
|
+
let i = _.current, a = v.current;
|
|
76
76
|
if (!i || !a) {
|
|
77
|
-
|
|
77
|
+
O(S.saveError);
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
|
-
let o = r(
|
|
81
|
-
|
|
80
|
+
let o = r(g.current, e.name, e.description, e.instructions), { filePaths: s, files: c } = n(m, h.current);
|
|
81
|
+
P("submitting");
|
|
82
82
|
try {
|
|
83
|
-
|
|
84
|
-
variant:
|
|
85
|
-
title:
|
|
86
|
-
message:
|
|
87
|
-
}),
|
|
83
|
+
v.current = (await x.updateSkill(f, i, o, s, c, a)).etag ?? a, await b(), P("success"), w({
|
|
84
|
+
variant: u.Success,
|
|
85
|
+
title: S.updateSuccessTitle,
|
|
86
|
+
message: S.updateSuccess(e.name)
|
|
87
|
+
}), C(y);
|
|
88
88
|
} catch (e) {
|
|
89
|
-
if (
|
|
90
|
-
|
|
89
|
+
if (P("failure"), t(e) === 412) {
|
|
90
|
+
M({ message: S.conflictMessage });
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
-
await
|
|
93
|
+
await L(e);
|
|
94
94
|
}
|
|
95
95
|
}, [
|
|
96
|
-
|
|
97
|
-
p,
|
|
96
|
+
f,
|
|
98
97
|
m,
|
|
99
98
|
h,
|
|
100
99
|
g,
|
|
101
100
|
_,
|
|
101
|
+
v,
|
|
102
|
+
S,
|
|
102
103
|
x,
|
|
103
|
-
|
|
104
|
+
w,
|
|
104
105
|
C,
|
|
105
|
-
S,
|
|
106
|
-
v,
|
|
107
106
|
y,
|
|
108
|
-
|
|
107
|
+
b,
|
|
108
|
+
L
|
|
109
|
+
]), B = s((e) => {
|
|
110
|
+
let t = o(e.instructions);
|
|
111
|
+
E((e) => {
|
|
112
|
+
if (t === (e.instructions === S.instructionsFrontmatter)) return e;
|
|
113
|
+
if (t) return {
|
|
114
|
+
...e,
|
|
115
|
+
instructions: S.instructionsFrontmatter
|
|
116
|
+
};
|
|
117
|
+
let n = { ...e };
|
|
118
|
+
return delete n.instructions, n;
|
|
119
|
+
});
|
|
120
|
+
}, [S]), V = s(async (e) => {
|
|
121
|
+
if (N === "submitting" || !f) return;
|
|
122
|
+
let t = {};
|
|
123
|
+
if (e.name.trim() || (t.name = S.required), e.description.trim() || (t.description = S.required), e.instructions.trim() ? o(e.instructions) && (t.instructions = S.instructionsFrontmatter) : t.instructions = S.required, Object.keys(t).length > 0) {
|
|
124
|
+
E(t);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
E({}), O(void 0), A(!1), M(void 0), I.current = e, p ? await z(e) : await R(e);
|
|
128
|
+
}, [
|
|
129
|
+
N,
|
|
130
|
+
f,
|
|
131
|
+
S,
|
|
132
|
+
p,
|
|
133
|
+
z,
|
|
134
|
+
R
|
|
109
135
|
]);
|
|
110
136
|
return {
|
|
111
|
-
phase:
|
|
112
|
-
errors:
|
|
113
|
-
submitError:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
T({}), D(void 0), k(void 0), f ? await F(e) : await P(e);
|
|
124
|
-
}, [
|
|
125
|
-
A,
|
|
126
|
-
d,
|
|
127
|
-
x,
|
|
128
|
-
f,
|
|
129
|
-
F,
|
|
130
|
-
P
|
|
131
|
-
])
|
|
137
|
+
phase: N,
|
|
138
|
+
errors: T,
|
|
139
|
+
submitError: D,
|
|
140
|
+
isSubmitErrorRetryable: k,
|
|
141
|
+
retrySubmit: s(() => {
|
|
142
|
+
let e = I.current;
|
|
143
|
+
e != null && V(e);
|
|
144
|
+
}, [V]),
|
|
145
|
+
conflict: j,
|
|
146
|
+
clearConflict: () => M(void 0),
|
|
147
|
+
handleSubmit: V,
|
|
148
|
+
handleValuesChange: B
|
|
132
149
|
};
|
|
133
150
|
};
|
|
134
151
|
//#endregion
|
|
135
|
-
export {
|
|
152
|
+
export { f as useSkillEditorSubmit };
|
package/skill-editor.d.ts
CHANGED
|
@@ -43,6 +43,13 @@ export declare const buildSkillManifestForSubmit: (frontmatter: Record<string, u
|
|
|
43
43
|
*/
|
|
44
44
|
export declare const buildSkillManifestFromFrontmatter: (baseFrontmatter: Record<string, unknown>, name: string, description: string, instructions: string) => string;
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Classifies an import request's HTTP status into a semantic outcome: 400/413/422 are
|
|
48
|
+
* archive-content problems, 409 is a name collision, 429 is rate limiting, 502/503 mean the
|
|
49
|
+
* backend is unavailable, and anything else (including no status at all) is generic.
|
|
50
|
+
*/
|
|
51
|
+
export declare const classifySkillArchiveImportError: (status: number | undefined) => SkillArchiveImportErrorKind;
|
|
52
|
+
|
|
46
53
|
/**
|
|
47
54
|
* Client-side mirror of the backend's `isValidSkillRelativePath`
|
|
48
55
|
* (`apps/chat-api/src/skills/utils/skill-path.util.ts`), used only for
|
|
@@ -122,6 +129,28 @@ export declare interface SkillAboutDetails {
|
|
|
122
129
|
skillPrompt?: string;
|
|
123
130
|
}
|
|
124
131
|
|
|
132
|
+
/** Semantic classification of an import request failure. */
|
|
133
|
+
export declare enum SkillArchiveImportErrorKind {
|
|
134
|
+
Validation = "validation",
|
|
135
|
+
Collision = "collision",
|
|
136
|
+
RateLimited = "rateLimited",
|
|
137
|
+
ServiceUnavailable = "serviceUnavailable",
|
|
138
|
+
Generic = "generic"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Phase of a skill-archive import, driving the host's loading/success/error presentation. */
|
|
142
|
+
export declare enum SkillArchiveImportStatus {
|
|
143
|
+
Idle = "idle",
|
|
144
|
+
Uploading = "uploading",
|
|
145
|
+
Success = "success",
|
|
146
|
+
Error = "error"
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Reason a selected/dropped file was rejected before any request was made. */
|
|
150
|
+
export declare enum SkillArchiveSelectionRejectionReason {
|
|
151
|
+
UnsupportedFilename = "unsupportedFilename"
|
|
152
|
+
}
|
|
153
|
+
|
|
125
154
|
/** Already-configured DIAL Core download operations `useSkillEditorLoad` needs. */
|
|
126
155
|
export declare interface SkillEditorLoadClient {
|
|
127
156
|
/** Downloads the whole-skill ZIP archive. */
|
|
@@ -163,6 +192,12 @@ export declare interface SkillEditorSubmitClient {
|
|
|
163
192
|
export declare interface SkillEditorSubmitMessages {
|
|
164
193
|
/** Shown when a required field is empty. */
|
|
165
194
|
required: string;
|
|
195
|
+
/**
|
|
196
|
+
* Shown when the Instructions value opens with its own YAML frontmatter
|
|
197
|
+
* block — pasting a whole `SKILL.md` in there would otherwise produce a
|
|
198
|
+
* manifest with two frontmatter blocks.
|
|
199
|
+
*/
|
|
200
|
+
instructionsFrontmatter: string;
|
|
166
201
|
/** Shown when the normalized skill name fails DIAL's naming rules. */
|
|
167
202
|
nameInvalid: string;
|
|
168
203
|
/** Shown when the skill name already exists (409), or defensively on an unreachable create-mode 412. */
|
|
@@ -328,6 +363,28 @@ export declare interface SkillManifestValues {
|
|
|
328
363
|
instructions: string;
|
|
329
364
|
}
|
|
330
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Answers one question: would appending this text after the fence that
|
|
368
|
+
* `buildSkillManifest` writes produce a *second* frontmatter block?
|
|
369
|
+
*
|
|
370
|
+
* That happens when the text's first non-blank line is a bare `---` and some
|
|
371
|
+
* later line is a bare `---` too — the exact shape of a `SKILL.md` pasted
|
|
372
|
+
* wholesale into the editor's Instructions field.
|
|
373
|
+
*
|
|
374
|
+
* Detection is deliberately structural rather than YAML-based: a pasted block
|
|
375
|
+
* whose fenced content fails to parse corrupts the stored manifest
|
|
376
|
+
* identically (and renders as a setext `h2` in the Catalog's Details tab just
|
|
377
|
+
* the same), so requiring parseable YAML here would let the worst cases
|
|
378
|
+
* through. Keeping `parseYaml` out also makes this cheap enough to run on
|
|
379
|
+
* every keystroke.
|
|
380
|
+
*
|
|
381
|
+
* A single unclosed fence returns `false`: with no closing fence there is no
|
|
382
|
+
* second block, matching `FRONTMATTER_PATTERN`'s own requirement. A `---`
|
|
383
|
+
* appearing later in the body (a horizontal rule, a setext underline) is
|
|
384
|
+
* likewise not a frontmatter block.
|
|
385
|
+
*/
|
|
386
|
+
export declare const startsWithFrontmatterBlock: (text: string) => boolean;
|
|
387
|
+
|
|
331
388
|
declare type SubmitPhase = 'idle' | 'submitting' | 'success' | 'failure';
|
|
332
389
|
|
|
333
390
|
/** A skill archive unpacked into its manifest text and a relative-path → bytes map of every other entry. */
|
|
@@ -346,6 +403,46 @@ export declare interface UnpackedSkillArchive {
|
|
|
346
403
|
*/
|
|
347
404
|
export declare const unpackSkillArchive: (bytes: Uint8Array) => UnpackedSkillArchive;
|
|
348
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Headless controller for the skill-archive upload flow: dialog visibility, the exact-filename
|
|
408
|
+
* precheck, in-flight exclusion, and import completion. The host supplies the configured request
|
|
409
|
+
* and observes completion/failure through the injected callbacks; the hook never imports app
|
|
410
|
+
* contexts, i18n, or a configured API client.
|
|
411
|
+
*/
|
|
412
|
+
export declare const useSkillArchiveImport: <TResult>({ importArchive, onImported, onError, manifestFileName, }: UseSkillArchiveImportOptions<TResult>) => UseSkillArchiveImportResult;
|
|
413
|
+
|
|
414
|
+
/** Options accepted by {@link useSkillArchiveImport}. */
|
|
415
|
+
export declare interface UseSkillArchiveImportOptions<TResult> {
|
|
416
|
+
/** Submits the selected archive; the host owns request configuration and the client. */
|
|
417
|
+
importArchive: (file: File) => Promise<TResult>;
|
|
418
|
+
/** Called once after a successful import (and any awaited host follow-up) settles. */
|
|
419
|
+
onImported: (result: TResult) => void | Promise<void>;
|
|
420
|
+
/** Called once when the import request, or the host's follow-up in {@link onImported}, fails. */
|
|
421
|
+
onError: (error: unknown, kind: SkillArchiveImportErrorKind) => void;
|
|
422
|
+
/** Exact filename treated as the skill manifest. Defaults to `'SKILL.md'`. */
|
|
423
|
+
manifestFileName?: string;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** Result returned by {@link useSkillArchiveImport}. */
|
|
427
|
+
export declare interface UseSkillArchiveImportResult {
|
|
428
|
+
/** Whether the upload dialog is open. */
|
|
429
|
+
isDialogOpen: boolean;
|
|
430
|
+
/** Current phase of the import. */
|
|
431
|
+
status: SkillArchiveImportStatus;
|
|
432
|
+
/** Reason the current/last selection was rejected locally; `undefined` once cleared. */
|
|
433
|
+
selectionRejectionReason: SkillArchiveSelectionRejectionReason | undefined;
|
|
434
|
+
/** Classified failure of the last import request; `undefined` outside a request failure. */
|
|
435
|
+
errorKind: SkillArchiveImportErrorKind | undefined;
|
|
436
|
+
/** Opens the dialog, unless an import is already in flight. */
|
|
437
|
+
openDialog: () => void;
|
|
438
|
+
/** Closes the dialog and clears any rejection reason. */
|
|
439
|
+
closeDialog: () => void;
|
|
440
|
+
/** Wire to the dialog drop zone's `onChange`. */
|
|
441
|
+
handleFilesSelected: (files: File[]) => void;
|
|
442
|
+
/** Wire to the dialog drop zone's `onReject`. */
|
|
443
|
+
handleFilesRejected: () => void;
|
|
444
|
+
}
|
|
445
|
+
|
|
349
446
|
/**
|
|
350
447
|
* Owns the edit-mode skill download/unpack/parse flow: the in-memory
|
|
351
448
|
* supporting-file map, the loaded manifest values and frontmatter, the
|
|
@@ -437,6 +534,10 @@ export declare interface UseSkillEditorSubmitResult {
|
|
|
437
534
|
errors: SkillEditorErrors;
|
|
438
535
|
/** General submit-time error, distinct from a stale-edit `conflict`. */
|
|
439
536
|
submitError: string | undefined;
|
|
537
|
+
/** Whether `submitError` was caused by something a plain re-send can clear, rather than by the submission itself. */
|
|
538
|
+
isSubmitErrorRetryable: boolean;
|
|
539
|
+
/** Re-submits the values of the attempt that produced `submitError`. No-op before the first submit. */
|
|
540
|
+
retrySubmit: () => void;
|
|
440
541
|
/** Present when the last save hit a stale-ETag conflict. */
|
|
441
542
|
conflict: {
|
|
442
543
|
message: string;
|
|
@@ -445,6 +546,12 @@ export declare interface UseSkillEditorSubmitResult {
|
|
|
445
546
|
clearConflict: () => void;
|
|
446
547
|
/** Validates and submits the given form values. */
|
|
447
548
|
handleSubmit: (values: SkillEditorValues) => Promise<void>;
|
|
549
|
+
/**
|
|
550
|
+
* Re-runs the Instructions frontmatter check against the editor's current
|
|
551
|
+
* values, so a pasted `SKILL.md` is flagged as the text lands rather than
|
|
552
|
+
* only on submit. Pass as the editor's `onValuesChange`.
|
|
553
|
+
*/
|
|
554
|
+
handleValuesChange: (values: SkillEditorValues) => void;
|
|
448
555
|
}
|
|
449
556
|
|
|
450
557
|
/**
|
package/skill-editor.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { SKILL_FILE_UPLOAD_MAX_BYTES as e, SKILL_MANIFEST_FILE as t, SKILL_UPLOAD_MAX_FILES as n, SKILL_UPLOAD_MAX_TOTAL_BYTES as r, buildSkillFilesPayload as i, buildSkillManifest as a, buildSkillManifestForSubmit as o, buildSkillManifestFromFrontmatter as s, isValidSkillRelativePath as c, nameFromPath as l, normalizeSkillName as u, parseSkillManifest as d, skillFileBytesToBlob as f,
|
|
2
|
-
import { parseSkillManifestDocument as
|
|
3
|
-
import { validateSkillFileBatch as
|
|
4
|
-
import { skillFileToAttachment as
|
|
5
|
-
import { SkillEditorLoadState as
|
|
6
|
-
import { useSkillEditorSubmit as
|
|
7
|
-
import { useSkillFileActions as
|
|
8
|
-
|
|
1
|
+
import { SKILL_FILE_UPLOAD_MAX_BYTES as e, SKILL_MANIFEST_FILE as t, SKILL_UPLOAD_MAX_FILES as n, SKILL_UPLOAD_MAX_TOTAL_BYTES as r, buildSkillFilesPayload as i, buildSkillManifest as a, buildSkillManifestForSubmit as o, buildSkillManifestFromFrontmatter as s, isValidSkillRelativePath as c, nameFromPath as l, normalizeSkillName as u, parseSkillManifest as d, skillFileBytesToBlob as f, startsWithFrontmatterBlock as p, unpackSkillArchive as m } from "./skill/skill.js";
|
|
2
|
+
import { parseSkillManifestDocument as h } from "./skill/skill-manifest.js";
|
|
3
|
+
import { validateSkillFileBatch as g } from "./skill/skill-file-batch-validation.js";
|
|
4
|
+
import { skillFileToAttachment as _ } from "./skill/skill-file-preview.js";
|
|
5
|
+
import { SkillEditorLoadState as v, useSkillEditorLoad as y } from "./skill/useSkillEditorLoad.js";
|
|
6
|
+
import { useSkillEditorSubmit as b } from "./skill/useSkillEditorSubmit.js";
|
|
7
|
+
import { useSkillFileActions as x } from "./skill/useSkillFileActions.js";
|
|
8
|
+
import { SkillArchiveImportErrorKind as S, SkillArchiveImportStatus as C, SkillArchiveSelectionRejectionReason as w, classifySkillArchiveImportError as T, useSkillArchiveImport as E } from "./skill/useSkillArchiveImport/useSkillArchiveImport.js";
|
|
9
|
+
export { e as SKILL_FILE_UPLOAD_MAX_BYTES, t as SKILL_MANIFEST_FILE, n as SKILL_UPLOAD_MAX_FILES, r as SKILL_UPLOAD_MAX_TOTAL_BYTES, S as SkillArchiveImportErrorKind, C as SkillArchiveImportStatus, w as SkillArchiveSelectionRejectionReason, v as SkillEditorLoadState, i as buildSkillFilesPayload, a as buildSkillManifest, o as buildSkillManifestForSubmit, s as buildSkillManifestFromFrontmatter, T as classifySkillArchiveImportError, c as isValidSkillRelativePath, l as nameFromPath, u as normalizeSkillName, d as parseSkillManifest, h as parseSkillManifestDocument, f as skillFileBytesToBlob, _ as skillFileToAttachment, p as startsWithFrontmatterBlock, m as unpackSkillArchive, E as useSkillArchiveImport, y as useSkillEditorLoad, b as useSkillEditorSubmit, x as useSkillFileActions, g as validateSkillFileBatch };
|