@epam/ai-dial-chat-hooks 1.2.0-dev.28 → 1.2.0-dev.284

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 (94) hide show
  1. package/api-error/api-error.js +7 -4
  2. package/attachment/useAttachmentValidation/useAttachmentValidation.js +26 -19
  3. package/attachments.d.ts +10 -4
  4. package/catalog/catalog-derivations.js +1 -1
  5. package/catalog/deployment-id.js +8 -2
  6. package/catalog/map-deployment-limits-to-catalog.js +16 -24
  7. package/catalog/map-deployment-limits-to-input.js +81 -9
  8. package/catalog/map-deployment-to-catalog-item.js +34 -34
  9. package/catalog/map-entity-details-to-catalog.js +7 -0
  10. package/catalog/map-skill-to-catalog-item.js +55 -48
  11. package/catalog/publish.js +6 -5
  12. package/catalog/useApplicationCredentials/useApplicationCredentials.js +39 -0
  13. package/catalog/useCatalogEditNavigation/useCatalogEditNavigation.js +122 -101
  14. package/catalog/usePublishFolders/usePublishFolders.js +1 -1
  15. package/catalog/useSkillDetailsPanelData/useSkillDetailsPanelData.js +39 -39
  16. package/catalog/useSkillItemDetails.js +17 -13
  17. package/catalog.d.ts +139 -34
  18. package/catalog.js +23 -22
  19. package/conversation/conversation-transfer/export-conversation.js +24 -16
  20. package/conversation/conversation-transfer/import-conversation.js +80 -31
  21. package/conversation/conversation-transfer/queue.js +8 -5
  22. package/conversation/create-chat-stream-api.js +85 -49
  23. package/conversation/message-utils.js +44 -2
  24. package/conversation/stage.js +27 -0
  25. package/conversation/useActiveConversationSync/useActiveConversationSync.js +7 -8
  26. package/conversation/useConversationExport/useConversationExport.js +9 -9
  27. package/conversation/useConversationHandlers/useConversationHandlers.js +73 -57
  28. package/conversation/useConversationImport/useConversationImport.js +123 -121
  29. package/conversation/useConversationPanelItems/useConversationPanelItems.js +50 -32
  30. package/conversation/useConversationScroll/useConversationScroll.js +68 -64
  31. package/conversation/useConversationStream/apply-chunk.js +1 -1
  32. package/conversation/useConversationStream/frame-scheduler.js +39 -0
  33. package/conversation/useConversationStream/generation-resume.js +122 -64
  34. package/conversation/useConversationStream/useConversationStream.js +265 -116
  35. package/conversation/useMessageSelectionReply/useMessageSelectionReply.js +189 -0
  36. package/conversation-sources/useConversationSources/useConversationSources.js +31 -24
  37. package/conversation-sources.d.ts +1 -1
  38. package/conversation-transfer.d.ts +2 -1
  39. package/conversation.d.ts +295 -17
  40. package/conversation.js +32 -29
  41. package/file-manager-canvas.d.ts +53 -5
  42. package/file-manager.d.ts +156 -26
  43. package/file-manager.js +25 -23
  44. package/files/attachment-canvas.js +74 -40
  45. package/files/attachment-types.js +14 -13
  46. package/files/dial-file-manager-mapping.util.js +2 -1
  47. package/files/dial-file-manager-path.util.js +23 -1
  48. package/files/dial-file-manager.model.js +23 -19
  49. package/files/dial-file-manager.types.js +3 -3
  50. package/files/useDialFileListing/useDialFileListing.js +139 -127
  51. package/files/useDialFileManager/useDialFileManager.js +132 -128
  52. package/files/useDialFileManagerSections/useDialFileManagerSections.js +155 -0
  53. package/files/useDialFileManagerTabConfig/useDialFileManagerTabConfig.js +20 -19
  54. package/files/useDialFileMutations/useDialFileMutations.js +33 -32
  55. package/files/useDialFileUploadBatch/useDialFileUploadBatch.js +117 -110
  56. package/files/useFileAttachmentPicker/useFileAttachmentPicker.js +49 -0
  57. package/index.d.ts +1178 -112
  58. package/index.js +136 -122
  59. package/mcp-apps/useMcpAppHostAdapter/useMcpAppHostAdapter.js +7 -5
  60. package/mcp-apps/useMcpAppHostContext/useMcpAppHostContext.js +1 -1
  61. package/mcp-apps/useMcpAppTools/useMcpAppTools.js +1 -1
  62. package/mcp-apps/useOpenMcpAppCanvas/useOpenMcpAppCanvas.js +25 -23
  63. package/mcp-apps.d.ts +8 -6
  64. package/oauth/toolset-id.js +5 -3
  65. package/oauth/useToolsetLogin/useToolsetLogin.js +8 -8
  66. package/oauth.d.ts +32 -0
  67. package/oauth.js +9 -9
  68. package/package.json +26 -21
  69. package/scheduled-task/scheduled-task-description.js +81 -0
  70. package/scheduled-task/scheduled-task-preparation.js +24 -0
  71. package/scheduled-task/scheduled-task-trigger.js +74 -71
  72. package/scheduled-task/scheduled-tasks-api-client.js +19 -0
  73. package/scheduled-task/use-scheduled-task-runs.js +194 -0
  74. package/scheduled-task/use-scheduled-tasks.js +93 -0
  75. package/scheduled-tasks.d.ts +197 -3
  76. package/scheduled-tasks.js +7 -2
  77. package/shared/application-schema.js +5 -2
  78. package/shared/cron-day-of-month.js +13 -0
  79. package/skill/skill-archive.js +19 -0
  80. package/skill/skill-types.js +8 -7
  81. package/skill/skill.js +53 -27
  82. package/skill/useSkillArchiveImport/useSkillArchiveImport.js +79 -0
  83. package/skill/useSkillEditorLoad.js +65 -59
  84. package/skill/useSkillEditorSubmit.js +108 -84
  85. package/skill/useSkillFileActions.js +70 -58
  86. package/skill-editor.d.ts +160 -8
  87. package/skill-editor.js +9 -8
  88. package/usage/map-usage-data-to-dashboard.js +66 -0
  89. package/usage/map-user-usage-to-model-limits.js +202 -0
  90. package/usage.d.ts +125 -0
  91. package/usage.js +3 -0
  92. package/usePageFileDrag/usePageFileDrag.js +3 -3
  93. package/utils.d.ts +26 -6
  94. package/utils.js +10 -10
@@ -1,99 +1,111 @@
1
- import { SKILL_MANIFEST_FILE as e, buildSkillManifest as t, buildSkillManifestFromFrontmatter as n, nameFromPath as r } from "./skill.js";
2
- import { validateSkillFileBatch as i } from "./skill-file-batch-validation.js";
3
- import { getUtf8ByteLength as a } from "@epam/ai-dial-chat-shared";
4
- import { useCallback as o, useMemo as s, useRef as c, useState as l } from "react";
5
- import { SkillFileNodeKind as u } from "@epam/ai-dial-skill-editor";
1
+ import { SKILL_MANIFEST_FILE as e, buildSkillManifest as t, buildSkillManifestFromFrontmatter as n, isValidSkillRelativePath as r, nameFromPath as i } from "./skill.js";
2
+ import { validateSkillFileBatch as a } from "./skill-file-batch-validation.js";
3
+ import { extractSkillArchive as o } from "./skill-archive.js";
4
+ import { getUtf8ByteLength as s } from "@epam/ai-dial-chat-shared";
5
+ import { useCallback as c, useMemo as l, useRef as u, useState as d } from "react";
6
+ import { SkillFileNodeKind as f } from "@epam/ai-dial-skill-editor";
6
7
  //#region src/skill/useSkillFileActions.ts
7
- var d = ({ files: d, setFiles: f, filesContentRef: p, frontmatterRef: m, loadedValues: h, setLoadedValues: g, isEditMode: _, isDirty: v, setSelectedPath: y, messages: b }) => {
8
- let [x, S] = l(!1), C = c(null), w = o(() => {
9
- let e = d.filter((e) => e.kind === u.File).map((e) => e.path), r = 0;
10
- for (let t of e) r += p.current.get(t)?.bytes.length ?? 0;
8
+ var p = "probe", m = ({ files: m, setFiles: h, filesContentRef: g, frontmatterRef: _, loadedValues: v, setLoadedValues: y, isEditMode: b, isDirty: x, setSelectedPath: S, messages: C, pickFromFileSystem: w }) => {
9
+ let [T, E] = d(!1), D = u(null), O = c(() => {
10
+ let e = m.filter((e) => e.kind === f.File).map((e) => e.path), r = 0;
11
+ for (let t of e) r += g.current.get(t)?.bytes.length ?? 0;
11
12
  let i = {
12
- name: h?.name ?? "",
13
- description: h?.description ?? "",
14
- instructions: h?.instructions ?? ""
15
- }, o = _ ? n(m.current, i.name, i.description, i.instructions) : t(i);
13
+ name: v?.name ?? "",
14
+ description: v?.description ?? "",
15
+ instructions: v?.instructions ?? ""
16
+ }, a = b ? n(_.current, i.name, i.description, i.instructions) : t(i);
16
17
  return {
17
18
  existingPaths: e,
18
19
  existingTotalBytes: r,
19
- manifestByteLength: a(o),
20
- messages: b
20
+ manifestByteLength: s(a),
21
+ messages: C
21
22
  };
22
23
  }, [
23
- d,
24
- p,
25
- _,
26
24
  m,
27
- h,
28
- b
29
- ]), T = o(() => new Promise((e) => {
30
- C.current = e, S(!0);
31
- }), []), E = o((e) => {
32
- S(!1), C.current?.(e), C.current = null;
25
+ g,
26
+ b,
27
+ _,
28
+ v,
29
+ C
30
+ ]), k = c(() => new Promise((e) => {
31
+ D.current = e, E(!0);
32
+ }), []), A = c((e) => {
33
+ E(!1), D.current?.(e), D.current = null;
33
34
  }, []);
34
35
  return {
35
- fileActions: s(() => ({
36
+ fileActions: l(() => ({
36
37
  validateBatch: async (e) => {
37
- let { results: t, batchErrors: n } = await i(e, w());
38
+ let { results: t, batchErrors: n } = await a(e, O());
38
39
  return {
39
40
  results: t,
40
41
  batchErrors: n
41
42
  };
42
43
  },
43
44
  commitBatch: async (e) => {
44
- let { results: t, batchErrors: n, manifestCandidate: a } = await i(e, w());
45
- if (t.some((e) => e.error !== void 0) || n.length > 0) return { error: n[0]?.message ?? b.saveError };
46
- if (a) {
47
- if (_ && a.name !== (h?.name ?? "")) return { error: b.manifestNameMismatch };
48
- if ((_ || v) && !await T()) return { error: b.manifestImportDeclined };
45
+ let { results: t, batchErrors: n, manifestCandidate: r } = await a(e, O());
46
+ if (t.some((e) => e.error !== void 0) || n.length > 0) return { error: n[0]?.message ?? C.saveError };
47
+ if (r) {
48
+ if (b && r.name !== (v?.name ?? "")) return { error: C.manifestNameMismatch };
49
+ if ((b || x) && !await k()) return { error: C.manifestImportDeclined };
49
50
  }
50
51
  try {
51
- let t = e.filter((e) => e.id !== a?.candidateId), n = await Promise.all(t.map(async (e) => ({
52
+ let t = e.filter((e) => e.id !== r?.candidateId), n = await Promise.all(t.map(async (e) => ({
52
53
  path: e.path,
53
54
  bytes: new Uint8Array(await e.file.arrayBuffer()),
54
55
  mimeType: e.file.type || void 0
55
56
  })));
56
- for (let e of n) p.current.set(e.path, {
57
+ for (let e of n) g.current.set(e.path, {
57
58
  bytes: e.bytes,
58
59
  mimeType: e.mimeType
59
60
  });
60
- return n.length > 0 && f((e) => [...e, ...n.map((e) => ({
61
+ return n.length > 0 && h((e) => [...e, ...n.map((e) => ({
61
62
  path: e.path,
62
- name: r(e.path),
63
- kind: u.File
64
- }))]), a && (m.current = _ ? {
65
- ...m.current,
66
- ...a.frontmatter
67
- } : a.frontmatter, g({
68
- name: _ ? h?.name ?? a.name : a.name,
69
- description: a.description,
70
- instructions: a.instructions
63
+ name: i(e.path),
64
+ kind: f.File
65
+ }))]), r && (_.current = b ? {
66
+ ..._.current,
67
+ ...r.frontmatter
68
+ } : r.frontmatter, y({
69
+ name: b ? v?.name ?? r.name : r.name,
70
+ description: r.description,
71
+ instructions: r.instructions
71
72
  })), {};
72
73
  } catch (e) {
73
74
  return { error: e instanceof Error ? e.message : String(e) };
74
75
  }
75
76
  },
76
77
  onRemoveNode: (t) => {
77
- f((e) => e.filter((e) => e.path !== t && !e.path.startsWith(`${t}/`)));
78
- for (let e of [...p.current.keys()]) (e === t || e.startsWith(`${t}/`)) && p.current.delete(e);
79
- y((n) => n === t || n.startsWith(`${t}/`) ? e : n);
80
- }
78
+ h((e) => e.filter((e) => e.path !== t && !e.path.startsWith(`${t}/`)));
79
+ for (let e of [...g.current.keys()]) (e === t || e.startsWith(`${t}/`)) && g.current.delete(e);
80
+ S((n) => n === t || n.startsWith(`${t}/`) ? e : n);
81
+ },
82
+ onCreateFolder: (e) => {
83
+ h((t) => t.some((t) => t.path === e) ? t : [...t, {
84
+ path: e,
85
+ name: i(e),
86
+ kind: f.Folder
87
+ }]);
88
+ },
89
+ validateFolderPath: (e) => r(`${e}/${p}`) ? void 0 : C.pathInvalid,
90
+ extractArchive: o,
91
+ pickFromFileSystem: w
81
92
  }), [
82
- w,
83
- _,
93
+ O,
94
+ b,
95
+ x,
84
96
  v,
85
- h,
86
- T,
87
- p,
88
- m,
89
- f,
97
+ k,
90
98
  g,
99
+ _,
100
+ h,
91
101
  y,
92
- b
102
+ S,
103
+ C,
104
+ w
93
105
  ]),
94
- pendingManifestImport: x,
95
- resolveManifestImport: E
106
+ pendingManifestImport: T,
107
+ resolveManifestImport: A
96
108
  };
97
109
  };
98
110
  //#endregion
99
- export { d as useSkillFileActions };
111
+ export { m as useSkillFileActions };
package/skill-editor.d.ts CHANGED
@@ -7,6 +7,7 @@ import { SkillEditorFileActions } from '@epam/ai-dial-skill-editor';
7
7
  import { SkillEditorValues } from '@epam/ai-dial-skill-editor';
8
8
  import { SkillFileBatchError } from '@epam/ai-dial-skill-editor';
9
9
  import { SkillFileListResponseDto } from '@epam/ai-dial-chat-api-client';
10
+ import { SkillFileSourceEntry } from '@epam/ai-dial-skill-editor';
10
11
  import { SkillFileTreeNode } from '@epam/ai-dial-skill-editor';
11
12
  import { SkillFileUploadCandidate } from '@epam/ai-dial-skill-editor';
12
13
  import { SkillFileValidationResult } from '@epam/ai-dial-skill-editor';
@@ -15,7 +16,10 @@ import { SkillUploadResponseDto } from '@epam/ai-dial-chat-api-client';
15
16
  /**
16
17
  * Builds the ordered supporting-file paths and `Blob` payload
17
18
  * `createSkill`/`updateSkill` expect from the editor's file tree and
18
- * in-memory content map.
19
+ * in-memory content map. Every folder node with no descendant node gets a
20
+ * zero-byte `<folder>/.dial_folder` marker after the real files, so the
21
+ * empty folder survives the whole-skill write; a folder with content needs
22
+ * none, and a marker it had before is dropped by that same write.
19
23
  */
20
24
  export declare const buildSkillFilesPayload: (files: SkillFileTreeNode[], filesContent: Map<string, SkillFileContent>) => SkillFilesPayload;
21
25
 
@@ -43,11 +47,27 @@ export declare const buildSkillManifestForSubmit: (frontmatter: Record<string, u
43
47
  */
44
48
  export declare const buildSkillManifestFromFrontmatter: (baseFrontmatter: Record<string, unknown>, name: string, description: string, instructions: string) => string;
45
49
 
50
+ /**
51
+ * Classifies an import request's HTTP status into a semantic outcome: 400/413/422 are
52
+ * archive-content problems, 409 is a name collision, 429 is rate limiting, 502/503 mean the
53
+ * backend is unavailable, and anything else (including no status at all) is generic.
54
+ */
55
+ export declare const classifySkillArchiveImportError: (status: number | undefined) => SkillArchiveImportErrorKind;
56
+
57
+ /** Returns the limit each over-long skill field exceeds, keyed by field; fields within their limit are omitted. */
58
+ export declare const getSkillFieldLengthViolations: (values: Record<SkillTextField, string>) => Partial<Record<SkillTextField, number>>;
59
+
60
+ /** Whether a skill-relative path is a folder marker (`<folder>/.dial_folder`, never a root-level `.dial_folder`). */
61
+ export declare const isSkillFolderMarkerPath: (path: string) => boolean;
62
+
46
63
  /**
47
64
  * Client-side mirror of the backend's `isValidSkillRelativePath`
48
65
  * (`apps/chat-api/src/skills/utils/skill-path.util.ts`), used only for
49
66
  * immediate inline feedback — the server remains authoritative and may still
50
- * reject a path this function accepts.
67
+ * reject a path this function accepts. It additionally reserves the
68
+ * `.dial_folder` marker name so a user can never upload or name a folder
69
+ * after it; the save payload's generated markers never pass through here
70
+ * (the server accepts them only as a zero-byte final segment).
51
71
  */
52
72
  export declare const isValidSkillRelativePath: (relativePath: string) => boolean;
53
73
 
@@ -95,9 +115,19 @@ export declare const parseSkillManifestDocument: (raw: string) => SkillManifestD
95
115
  */
96
116
  export declare const SKILL_FILE_UPLOAD_MAX_BYTES = 1048576;
97
117
 
118
+ /**
119
+ * Zero-byte object written at `<folder>/.dial_folder` so an otherwise empty
120
+ * skill folder survives a save — DIAL Core storage has no directory objects,
121
+ * so a folder only exists as a file's path prefix.
122
+ */
123
+ export declare const SKILL_FOLDER_MARKER = ".dial_folder";
124
+
98
125
  /** Root manifest filename required at the top of every skill archive (mirrors `SKILL_MANIFEST_FILE` in `apps/chat-api/src/skills/utils/skill-path.util.ts`). */
99
126
  export declare const SKILL_MANIFEST_FILE = "SKILL.md";
100
127
 
128
+ /** Length limit of each skill editor text field. */
129
+ export declare const SKILL_TEXT_FIELD_MAX_LENGTHS: Record<SkillTextField, number>;
130
+
101
131
  /**
102
132
  * Client-side mirror of the backend's default `SKILL_UPLOAD_MAX_FILES`
103
133
  * (`apps/chat-api/src/config/environment.config.ts`), used only for
@@ -122,6 +152,28 @@ export declare interface SkillAboutDetails {
122
152
  skillPrompt?: string;
123
153
  }
124
154
 
155
+ /** Semantic classification of an import request failure. */
156
+ export declare enum SkillArchiveImportErrorKind {
157
+ Validation = "validation",
158
+ Collision = "collision",
159
+ RateLimited = "rateLimited",
160
+ ServiceUnavailable = "serviceUnavailable",
161
+ Generic = "generic"
162
+ }
163
+
164
+ /** Phase of a skill-archive import, driving the host's loading/success/error presentation. */
165
+ export declare enum SkillArchiveImportStatus {
166
+ Idle = "idle",
167
+ Uploading = "uploading",
168
+ Success = "success",
169
+ Error = "error"
170
+ }
171
+
172
+ /** Reason a selected/dropped file was rejected before any request was made. */
173
+ export declare enum SkillArchiveSelectionRejectionReason {
174
+ UnsupportedFilename = "unsupportedFilename"
175
+ }
176
+
125
177
  /** Already-configured DIAL Core download operations `useSkillEditorLoad` needs. */
126
178
  export declare interface SkillEditorLoadClient {
127
179
  /** Downloads the whole-skill ZIP archive. */
@@ -163,6 +215,14 @@ export declare interface SkillEditorSubmitClient {
163
215
  export declare interface SkillEditorSubmitMessages {
164
216
  /** Shown when a required field is empty. */
165
217
  required: string;
218
+ /** Shown when a name, description or instructions value exceeds its length limit, given that limit. */
219
+ tooLong: (maxLength: number) => string;
220
+ /**
221
+ * Shown when the Instructions value opens with its own YAML frontmatter
222
+ * block — pasting a whole `SKILL.md` in there would otherwise produce a
223
+ * manifest with two frontmatter blocks.
224
+ */
225
+ instructionsFrontmatter: string;
166
226
  /** Shown when the normalized skill name fails DIAL's naming rules. */
167
227
  nameInvalid: string;
168
228
  /** Shown when the skill name already exists (409), or defensively on an unreachable create-mode 412. */
@@ -292,6 +352,9 @@ export declare interface SkillFilesPayload {
292
352
  */
293
353
  export declare const skillFileToAttachment: (node: SkillFileTreeNode, content: SkillFileContent) => Attachment;
294
354
 
355
+ /** Returns the folder path a marker path stands for (`docs/.dial_folder` → `docs`). */
356
+ export declare const skillFolderMarkerParent: (markerPath: string) => string;
357
+
295
358
  /** A `SKILL.md` split into its frontmatter fields and its prose body. */
296
359
  export declare interface SkillManifestDocument {
297
360
  /** `name` frontmatter field, when present and a string. */
@@ -328,24 +391,94 @@ export declare interface SkillManifestValues {
328
391
  instructions: string;
329
392
  }
330
393
 
394
+ /** Skill editor text fields with a length limit. */
395
+ export declare type SkillTextField = 'name' | 'description' | 'instructions';
396
+
397
+ /**
398
+ * Answers one question: would appending this text after the fence that
399
+ * `buildSkillManifest` writes produce a *second* frontmatter block?
400
+ *
401
+ * That happens when the text's first non-blank line is a bare `---` and some
402
+ * later line is a bare `---` too — the exact shape of a `SKILL.md` pasted
403
+ * wholesale into the editor's Instructions field.
404
+ *
405
+ * Detection is deliberately structural rather than YAML-based: a pasted block
406
+ * whose fenced content fails to parse corrupts the stored manifest
407
+ * identically (and renders as a setext `h2` in the Catalog's Details tab just
408
+ * the same), so requiring parseable YAML here would let the worst cases
409
+ * through. Keeping `parseYaml` out also makes this cheap enough to run on
410
+ * every keystroke.
411
+ *
412
+ * A single unclosed fence returns `false`: with no closing fence there is no
413
+ * second block, matching `FRONTMATTER_PATTERN`'s own requirement. A `---`
414
+ * appearing later in the body (a horizontal rule, a setext underline) is
415
+ * likewise not a frontmatter block.
416
+ */
417
+ export declare const startsWithFrontmatterBlock: (text: string) => boolean;
418
+
331
419
  declare type SubmitPhase = 'idle' | 'submitting' | 'success' | 'failure';
332
420
 
333
421
  /** A skill archive unpacked into its manifest text and a relative-path → bytes map of every other entry. */
334
422
  export declare interface UnpackedSkillArchive {
335
423
  /** The root `SKILL.md` entry's decoded text content. */
336
424
  manifestText: string;
337
- /** Every non-manifest entry, keyed by relative path. */
425
+ /** Every non-manifest, non-marker entry, keyed by relative path. */
338
426
  files: Map<string, Uint8Array>;
427
+ /** Folder paths restored from `<folder>/.dial_folder` marker entries. */
428
+ folders: string[];
339
429
  }
340
430
 
341
431
  /**
342
432
  * Unpacks a whole-skill ZIP (as downloaded from `GET /api/v1/skills/download`
343
433
  * — DIAL Core's whole-resource `GET` is the one place this contract still
344
- * uses a ZIP, per design.md) into its manifest text and every other entry's
345
- * bytes. Throws if the archive has no root `SKILL.md` entry.
434
+ * uses a ZIP, per design.md) into its manifest text, every other entry's
435
+ * bytes, and the folders its empty-folder markers stand for. Throws if the
436
+ * archive has no root `SKILL.md` entry.
346
437
  */
347
438
  export declare const unpackSkillArchive: (bytes: Uint8Array) => UnpackedSkillArchive;
348
439
 
440
+ /**
441
+ * Headless controller for the skill-archive upload flow: dialog visibility, the exact-filename
442
+ * precheck, in-flight exclusion, abort-on-close, and import completion. The host supplies the configured request
443
+ * and observes completion/failure through the injected callbacks; the hook never imports app
444
+ * contexts, i18n, or a configured API client.
445
+ */
446
+ export declare const useSkillArchiveImport: <TResult>({ importArchive, onImported, onError, manifestFileName, }: UseSkillArchiveImportOptions<TResult>) => UseSkillArchiveImportResult;
447
+
448
+ /** Options accepted by {@link useSkillArchiveImport}. */
449
+ export declare interface UseSkillArchiveImportOptions<TResult> {
450
+ /** Submits the selected archive; the host owns the client. `signal` aborts when the dialog closes or the hook unmounts mid-upload. */
451
+ importArchive: (file: File, signal: AbortSignal) => Promise<TResult>;
452
+ /** Called once after a successful import (and any awaited host follow-up) settles. */
453
+ onImported: (result: TResult) => void | Promise<void>;
454
+ /** Called once when the import request, or the host's follow-up in {@link onImported}, fails. */
455
+ onError: (error: unknown, kind: SkillArchiveImportErrorKind) => void;
456
+ /** Exact filename treated as the skill manifest. Defaults to `'SKILL.md'`. */
457
+ manifestFileName?: string;
458
+ }
459
+
460
+ /** Result returned by {@link useSkillArchiveImport}. */
461
+ export declare interface UseSkillArchiveImportResult {
462
+ /** Whether the upload dialog is open. */
463
+ isDialogOpen: boolean;
464
+ /** Current phase of the import. */
465
+ status: SkillArchiveImportStatus;
466
+ /** Whether an import request is in flight; the dialog stays open until it succeeds. */
467
+ isUploading: boolean;
468
+ /** Reason the current/last selection was rejected locally; `undefined` once cleared. */
469
+ selectionRejectionReason: SkillArchiveSelectionRejectionReason | undefined;
470
+ /** Classified failure of the last import request; `undefined` outside a request failure. */
471
+ errorKind: SkillArchiveImportErrorKind | undefined;
472
+ /** Opens the dialog and clears any previous rejection or request failure. */
473
+ openDialog: () => void;
474
+ /** Closes the dialog, aborting an in-flight import, and clears any rejection reason. */
475
+ closeDialog: () => void;
476
+ /** Wire to the dialog drop zone's `onChange`. */
477
+ handleFilesSelected: (files: File[]) => void;
478
+ /** Wire to the dialog drop zone's `onReject`. */
479
+ handleFilesRejected: () => void;
480
+ }
481
+
349
482
  /**
350
483
  * Owns the edit-mode skill download/unpack/parse flow: the in-memory
351
484
  * supporting-file map, the loaded manifest values and frontmatter, the
@@ -397,7 +530,7 @@ export declare interface UseSkillEditorLoadResult {
397
530
  * `client.createSkill`/`client.updateSkill`, and mapping the resulting
398
531
  * success/error/conflict outcomes to presentable state.
399
532
  */
400
- export declare const useSkillEditorSubmit: ({ bucket, isEditMode, files, filesContentRef, frontmatterRef, loadedPathRef, etagRef, returnUrl, refetchSkills, client, messages, onNavigate, onNotify, }: UseSkillEditorSubmitParams) => UseSkillEditorSubmitResult;
533
+ export declare const useSkillEditorSubmit: ({ bucket, isEditMode, files, filesContentRef, frontmatterRef, loadedPathRef, etagRef, returnUrl, getCreateReturnUrl, refetchSkills, client, messages, onNavigate, onNotify, }: UseSkillEditorSubmitParams) => UseSkillEditorSubmitResult;
401
534
 
402
535
  /** Parameters accepted by {@link useSkillEditorSubmit}. */
403
536
  export declare interface UseSkillEditorSubmitParams {
@@ -417,6 +550,8 @@ export declare interface UseSkillEditorSubmitParams {
417
550
  etagRef: React.MutableRefObject<string | undefined>;
418
551
  /** Where to navigate on a successful save. */
419
552
  returnUrl: string;
553
+ /** Resolves the destination after creation from the normalized skill path. Defaults to `returnUrl`. */
554
+ getCreateReturnUrl?: (path: string) => string;
420
555
  /** Refetches the host's skill listing after a successful save. */
421
556
  refetchSkills: () => Promise<void>;
422
557
  /** Already-configured create/update operations. */
@@ -437,6 +572,10 @@ export declare interface UseSkillEditorSubmitResult {
437
572
  errors: SkillEditorErrors;
438
573
  /** General submit-time error, distinct from a stale-edit `conflict`. */
439
574
  submitError: string | undefined;
575
+ /** Whether `submitError` was caused by something a plain re-send can clear, rather than by the submission itself. */
576
+ isSubmitErrorRetryable: boolean;
577
+ /** Re-submits the values of the attempt that produced `submitError`. No-op before the first submit. */
578
+ retrySubmit: () => void;
440
579
  /** Present when the last save hit a stale-ETag conflict. */
441
580
  conflict: {
442
581
  message: string;
@@ -445,15 +584,22 @@ export declare interface UseSkillEditorSubmitResult {
445
584
  clearConflict: () => void;
446
585
  /** Validates and submits the given form values. */
447
586
  handleSubmit: (values: SkillEditorValues) => Promise<void>;
587
+ /**
588
+ * Re-runs the Instructions frontmatter check against the editor's current
589
+ * values, so a pasted `SKILL.md` is flagged as the text lands rather than
590
+ * only on submit. Pass as the editor's `onValuesChange`.
591
+ */
592
+ handleValuesChange: (values: SkillEditorValues) => void;
448
593
  }
449
594
 
450
595
  /**
451
596
  * Owns the Skill Editor's batch file upload workflow: validating a staged
452
597
  * batch, committing it atomically (supporting files plus an optional
453
- * `SKILL.md` manifest import, with a confirmation gate), and removing
598
+ * `SKILL.md` manifest import, with a confirmation gate), creating empty
599
+ * folders, expanding `.zip` archives for staging, and removing
454
600
  * already-committed nodes.
455
601
  */
456
- export declare const useSkillFileActions: ({ files, setFiles, filesContentRef, frontmatterRef, loadedValues, setLoadedValues, isEditMode, isDirty, setSelectedPath, messages, }: UseSkillFileActionsParams) => UseSkillFileActionsResult;
602
+ export declare const useSkillFileActions: ({ files, setFiles, filesContentRef, frontmatterRef, loadedValues, setLoadedValues, isEditMode, isDirty, setSelectedPath, messages, pickFromFileSystem, }: UseSkillFileActionsParams) => UseSkillFileActionsResult;
457
603
 
458
604
  /** Parameters accepted by {@link useSkillFileActions}. */
459
605
  export declare interface UseSkillFileActionsParams {
@@ -477,6 +623,12 @@ export declare interface UseSkillFileActionsParams {
477
623
  setSelectedPath: Dispatch<SetStateAction<string>>;
478
624
  /** Localized messages, resolved by the host. */
479
625
  messages: SkillFileActionsMessages;
626
+ /**
627
+ * Opens the host's file-system picker; passed through unchanged as
628
+ * `fileActions.pickFromFileSystem`. Omit to hide the editor's "Open DIAL
629
+ * file system" entry.
630
+ */
631
+ pickFromFileSystem?: () => Promise<SkillFileSourceEntry[] | undefined>;
480
632
  }
481
633
 
482
634
  /** Return value of {@link useSkillFileActions}. */
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, unpackSkillArchive as p } from "./skill/skill.js";
2
- import { parseSkillManifestDocument as m } from "./skill/skill-manifest.js";
3
- import { validateSkillFileBatch as h } from "./skill/skill-file-batch-validation.js";
4
- import { skillFileToAttachment as g } from "./skill/skill-file-preview.js";
5
- import { SkillEditorLoadState as _, useSkillEditorLoad as v } from "./skill/useSkillEditorLoad.js";
6
- import { useSkillEditorSubmit as y } from "./skill/useSkillEditorSubmit.js";
7
- import { useSkillFileActions as b } from "./skill/useSkillFileActions.js";
8
- 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, _ as SkillEditorLoadState, i as buildSkillFilesPayload, a as buildSkillManifest, o as buildSkillManifestForSubmit, s as buildSkillManifestFromFrontmatter, c as isValidSkillRelativePath, l as nameFromPath, u as normalizeSkillName, d as parseSkillManifest, m as parseSkillManifestDocument, f as skillFileBytesToBlob, g as skillFileToAttachment, p as unpackSkillArchive, v as useSkillEditorLoad, y as useSkillEditorSubmit, b as useSkillFileActions, h as validateSkillFileBatch };
1
+ import { SKILL_FILE_UPLOAD_MAX_BYTES as e, SKILL_FOLDER_MARKER as t, SKILL_MANIFEST_FILE as n, SKILL_TEXT_FIELD_MAX_LENGTHS as r, SKILL_UPLOAD_MAX_FILES as i, SKILL_UPLOAD_MAX_TOTAL_BYTES as a, buildSkillFilesPayload as o, buildSkillManifest as s, buildSkillManifestForSubmit as c, buildSkillManifestFromFrontmatter as l, getSkillFieldLengthViolations as u, isSkillFolderMarkerPath as d, isValidSkillRelativePath as f, nameFromPath as p, normalizeSkillName as m, parseSkillManifest as h, skillFileBytesToBlob as g, skillFolderMarkerParent as _, startsWithFrontmatterBlock as v, unpackSkillArchive as y } from "./skill/skill.js";
2
+ import { parseSkillManifestDocument as b } from "./skill/skill-manifest.js";
3
+ import { validateSkillFileBatch as x } from "./skill/skill-file-batch-validation.js";
4
+ import { skillFileToAttachment as S } from "./skill/skill-file-preview.js";
5
+ import { SkillEditorLoadState as C, useSkillEditorLoad as w } from "./skill/useSkillEditorLoad.js";
6
+ import { useSkillEditorSubmit as T } from "./skill/useSkillEditorSubmit.js";
7
+ import { useSkillFileActions as E } from "./skill/useSkillFileActions.js";
8
+ import { SkillArchiveImportErrorKind as D, SkillArchiveImportStatus as O, SkillArchiveSelectionRejectionReason as k, classifySkillArchiveImportError as A, useSkillArchiveImport as j } from "./skill/useSkillArchiveImport/useSkillArchiveImport.js";
9
+ export { e as SKILL_FILE_UPLOAD_MAX_BYTES, t as SKILL_FOLDER_MARKER, n as SKILL_MANIFEST_FILE, r as SKILL_TEXT_FIELD_MAX_LENGTHS, i as SKILL_UPLOAD_MAX_FILES, a as SKILL_UPLOAD_MAX_TOTAL_BYTES, D as SkillArchiveImportErrorKind, O as SkillArchiveImportStatus, k as SkillArchiveSelectionRejectionReason, C as SkillEditorLoadState, o as buildSkillFilesPayload, s as buildSkillManifest, c as buildSkillManifestForSubmit, l as buildSkillManifestFromFrontmatter, A as classifySkillArchiveImportError, u as getSkillFieldLengthViolations, d as isSkillFolderMarkerPath, f as isValidSkillRelativePath, p as nameFromPath, m as normalizeSkillName, h as parseSkillManifest, b as parseSkillManifestDocument, g as skillFileBytesToBlob, S as skillFileToAttachment, _ as skillFolderMarkerParent, v as startsWithFrontmatterBlock, y as unpackSkillArchive, j as useSkillArchiveImport, w as useSkillEditorLoad, T as useSkillEditorSubmit, E as useSkillFileActions, x as validateSkillFileBatch };
@@ -0,0 +1,66 @@
1
+ import { formatCost as e } from "@epam/ai-dial-chat-shared";
2
+ import { UsageLimitStatus as t } from "@epam/ai-dial-usage-dashboard";
3
+ //#region src/usage/map-usage-data-to-dashboard.ts
4
+ var n = {
5
+ todayTitle: "usage.todayTitle",
6
+ todayPeriodDescription: "usage.todayPeriodDescription",
7
+ thisWeekTitle: "usage.thisWeekTitle",
8
+ thisWeekPeriodDescription: "usage.thisWeekPeriodDescription",
9
+ thisMonthTitle: "usage.thisMonthTitle",
10
+ thisMonthPeriodDescription: "usage.thisMonthPeriodDescription",
11
+ unlimitedProgressAriaLabel: "usage.unlimitedProgressAriaLabel",
12
+ progressAriaLabel: "usage.progressAriaLabel"
13
+ }, r = 2 ** 53, i = 75, a = (e) => e != null && Number.isFinite(e.total) && Number.isFinite(e.used), o = (e) => e >= 100 ? t.LimitReached : e >= i ? t.RunningLow : t.Default, s = (e) => e ? {
14
+ resetLabel: e.label,
15
+ resetIsoValue: e.isoValue,
16
+ resetAriaLabel: e.ariaLabel
17
+ } : {}, c = (i, a, c, l, u) => {
18
+ let d = Math.max(0, i.used), f = e(d), p = s(u);
19
+ if (i.total >= r) return {
20
+ title: a,
21
+ periodDescription: c,
22
+ used: d,
23
+ total: i.total,
24
+ usedLabel: f,
25
+ isUnlimited: !0,
26
+ status: t.Default,
27
+ progressAriaLabel: l(n.unlimitedProgressAriaLabel, { used: f }),
28
+ ...p
29
+ };
30
+ let m = Math.max(i.total, 0), h = Math.max(m - d, 0), g = m > 0 ? d / m * 100 : 100, _ = e(m);
31
+ return {
32
+ title: a,
33
+ periodDescription: c,
34
+ used: d,
35
+ total: m,
36
+ usedLabel: f,
37
+ totalLabel: _,
38
+ remainingLabel: e(h),
39
+ usedPercent: g,
40
+ status: o(g),
41
+ progressAriaLabel: l(n.progressAriaLabel, {
42
+ used: f,
43
+ total: _,
44
+ percent: Math.round(g)
45
+ }),
46
+ ...p
47
+ };
48
+ }, l = (e, t, r) => [
49
+ {
50
+ stats: e?.dayCostStats,
51
+ titleKey: n.todayTitle,
52
+ periodDescriptionKey: n.todayPeriodDescription
53
+ },
54
+ {
55
+ stats: e?.weekCostStats,
56
+ titleKey: n.thisWeekTitle,
57
+ periodDescriptionKey: n.thisWeekPeriodDescription
58
+ },
59
+ {
60
+ stats: e?.monthCostStats,
61
+ titleKey: n.thisMonthTitle,
62
+ periodDescriptionKey: n.thisMonthPeriodDescription
63
+ }
64
+ ].flatMap(({ stats: e, titleKey: n, periodDescriptionKey: i }) => a(e) ? [c(e, t(n), t(i), t, r(e.resetsAt))] : []);
65
+ //#endregion
66
+ export { n as USAGE_DATA_I18N_KEYS, l as mapUsageDataToDashboard };