@xpert-ai/chatkit-types 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -275,6 +275,26 @@ function normalizeRequestLanguage(locale) {
275
275
  }
276
276
  return normalized;
277
277
  }
278
+ function normalizeThreadReference(value) {
279
+ if (!value || typeof value !== "object" || !("type" in value) || value.type !== "thread")
280
+ return null;
281
+ if (!("conversationId" in value) || !isLocator(value.conversationId) || !("threadId" in value) || !isLocator(value.threadId))
282
+ return null;
283
+ if ("label" in value && value.label !== void 0 && (typeof value.label !== "string" || value.label.length > 300))
284
+ return null;
285
+ if ("id" in value && value.id !== void 0 && !isLocator(value.id))
286
+ return null;
287
+ return {
288
+ type: "thread",
289
+ conversationId: value.conversationId.trim(),
290
+ threadId: value.threadId.trim(),
291
+ ..."label" in value && typeof value.label === "string" ? { label: value.label.trim() } : {},
292
+ ..."id" in value && typeof value.id === "string" ? { id: value.id.trim() } : {}
293
+ };
294
+ }
295
+ function isLocator(value) {
296
+ return typeof value === "string" && value.trim().length > 0 && value.length <= 128;
297
+ }
278
298
  const PET_ANIMATION_NAMES = [
279
299
  "idle",
280
300
  "running-right",
@@ -526,8 +546,281 @@ function getPinnedPetPosition(pin, size, viewport, padding) {
526
546
  }
527
547
  }
528
548
  const CHATKIT_TASK_SUMMARY_OPEN_RESOURCE_EFFECT = "task_summary.open_resource";
549
+ function chatSkillUsageKey(usage) {
550
+ return JSON.stringify([
551
+ usage.source.type,
552
+ usage.source.id,
553
+ usage.skillId,
554
+ usage.version
555
+ ]);
556
+ }
557
+ function mergeChatSkillUsages(...groups) {
558
+ const usages = /* @__PURE__ */ new Map();
559
+ for (const group of groups) {
560
+ for (const usage of group ?? []) {
561
+ const key = chatSkillUsageKey(usage);
562
+ if (!usages.has(key)) usages.set(key, usage);
563
+ }
564
+ }
565
+ return [...usages.values()];
566
+ }
567
+ function normalizeChatSkillUsages(value) {
568
+ if (!Array.isArray(value)) return [];
569
+ const usages = [];
570
+ for (const item of value) {
571
+ if (!item || typeof item !== "object" || item.activation !== "read")
572
+ continue;
573
+ const { source } = item;
574
+ if (!source || typeof source !== "object" || !["workspace", "project", "assistant", "plugin"].includes(source.type) || typeof source.id !== "string" || !source.id.trim())
575
+ continue;
576
+ if (typeof item.skillId !== "string" || !item.skillId.trim() || typeof item.name !== "string" || !item.name.trim() || typeof item.version !== "string" || typeof item.toolCallId !== "string" || !item.toolCallId.trim() || typeof item.loadedAt !== "string" || !Number.isFinite(Date.parse(item.loadedAt)))
577
+ continue;
578
+ usages.push({
579
+ skillId: item.skillId,
580
+ name: item.name,
581
+ version: item.version,
582
+ source: { type: source.type, id: source.id },
583
+ activation: "read",
584
+ toolCallId: item.toolCallId,
585
+ ...typeof item.executionId === "string" && item.executionId ? { executionId: item.executionId } : {},
586
+ loadedAt: item.loadedAt
587
+ });
588
+ }
589
+ return mergeChatSkillUsages(usages);
590
+ }
591
+ function summarySkillUsages(summary) {
592
+ return summary && typeof summary === "object" && "version" in summary && summary.version === 1 && "skillUsages" in summary ? normalizeChatSkillUsages(summary.skillUsages) : [];
593
+ }
594
+ function getMessageSkillUsages(message) {
595
+ var _a;
596
+ const groups = [summarySkillUsages(message.taskSummary)];
597
+ if (Array.isArray(message.content)) {
598
+ for (const part of message.content) {
599
+ if ((part == null ? void 0 : part.type) === "component" && ((_a = part.data) == null ? void 0 : _a.status) === "success") {
600
+ groups.push(summarySkillUsages(part.data.taskSummary));
601
+ }
602
+ }
603
+ }
604
+ return mergeChatSkillUsages(...groups);
605
+ }
529
606
  const TOOL_OUTPUT_PRESENTATION_TYPE = "xpert.tool-output";
530
607
  const TOOL_OUTPUT_PRESENTATION_VERSION = 1;
608
+ function parseFileActivityContent(value) {
609
+ if (!value || typeof value !== "object") return null;
610
+ const part = value;
611
+ if (part.type !== "file_activity" || typeof part.id !== "string" || !part.id || !part.data || typeof part.data !== "object") return null;
612
+ const data = part.data;
613
+ if (data.version !== 1 || data.receiptId !== part.id || typeof data.toolCallId !== "string" || !data.toolCallId || typeof data.updatedAt !== "string" || !Number.isFinite(Date.parse(data.updatedAt))) return null;
614
+ const base = { version: 1, receiptId: part.id, toolCallId: data.toolCallId, updatedAt: data.updatedAt };
615
+ let receipt;
616
+ if (data.kind === "changes" && ["bounded", "partial", "unavailable"].includes(data.coverage) && Array.isArray(data.fileChanges)) {
617
+ const fileChanges = normalizeFileChanges(data.fileChanges);
618
+ if (fileChanges.length !== data.fileChanges.length) return null;
619
+ receipt = { ...base, kind: "changes", coverage: data.coverage, fileChanges };
620
+ } else if (data.kind === "delivery" && data.status === "success" && Array.isArray(data.outputs)) {
621
+ const outputs = normalizeFileOutputs(data.outputs);
622
+ if (outputs.length !== data.outputs.length) return null;
623
+ receipt = { ...base, kind: "delivery", status: "success", outputs };
624
+ } else if (data.kind === "delivery" && data.status === "error" && typeof data.error === "string") {
625
+ receipt = { ...base, kind: "delivery", status: "error", error: data.error };
626
+ } else return null;
627
+ return {
628
+ id: part.id,
629
+ type: "file_activity",
630
+ data: receipt,
631
+ ...typeof part.messageId === "string" ? { messageId: part.messageId } : {},
632
+ ...typeof part.executionId === "string" ? { executionId: part.executionId } : {},
633
+ ...typeof part.agentKey === "string" ? { agentKey: part.agentKey } : {},
634
+ ...typeof part.parentExecutionId === "string" ? { parentExecutionId: part.parentExecutionId } : {},
635
+ ...typeof part.runId === "string" ? { runId: part.runId } : {}
636
+ };
637
+ }
638
+ function getLegacyFileActivityContribution(value) {
639
+ var _a;
640
+ if (!value || typeof value !== "object") return null;
641
+ const part = value;
642
+ const step = part.type === "component" ? part.data : value;
643
+ if (!step || typeof step !== "object") return null;
644
+ const summary = step.taskSummary ?? ((_a = step._meta) == null ? void 0 : _a["xpertai/taskSummary"]);
645
+ const id = part.id ?? step.id;
646
+ return (summary == null ? void 0 : summary.version) === 1 && summary.fileActivityVersion === 1 && typeof summary.fileActivityToolCallId === "string" && Boolean(summary.fileActivityToolCallId) && typeof id === "string" && id !== summary.fileActivityToolCallId ? summary : null;
647
+ }
648
+ function isFileActivityContent(value) {
649
+ return Boolean(value && typeof value === "object" && "type" in value && value.type === "file_activity") || getLegacyFileActivityContribution(value) !== null;
650
+ }
651
+ function getFileActivityContribution(value) {
652
+ const part = parseFileActivityContent(value);
653
+ if (!part) return getLegacyFileActivityContribution(value);
654
+ const receipt = part.data;
655
+ return {
656
+ version: 1,
657
+ fileActivityVersion: 1,
658
+ fileActivityToolCallId: receipt.toolCallId,
659
+ ...receipt.kind === "changes" ? { fileChanges: receipt.fileChanges, fileChangeCoverage: receipt.coverage } : receipt.status === "success" ? { outputs: receipt.outputs } : {}
660
+ };
661
+ }
662
+ function upsertFileActivityContent(content, receipt) {
663
+ const index = content.findIndex((item) => {
664
+ var _a;
665
+ return ((_a = parseFileActivityContent(item)) == null ? void 0 : _a.id) === receipt.id;
666
+ });
667
+ if (index < 0) return [...content, receipt];
668
+ const previous = parseFileActivityContent(content[index]);
669
+ if (previous && Date.parse(previous.data.updatedAt) >= Date.parse(receipt.data.updatedAt)) return content;
670
+ return content.map((item, position) => position === index ? receipt : item);
671
+ }
672
+ function fileChangeRangeKey(resource) {
673
+ return JSON.stringify([resource.first.artifactId, resource.first.artifactVersionId, resource.last.artifactId, resource.last.artifactVersionId]);
674
+ }
675
+ const writeTools = /* @__PURE__ */ new Set(["sandbox_write_file", "sandbox_append_file", "sandbox_edit_file", "sandbox_multi_edit_file"]);
676
+ function normalizeFileChanges(value) {
677
+ if (!Array.isArray(value)) return [];
678
+ return value.filter((item) => {
679
+ if (!item || typeof item !== "object") return false;
680
+ const change = item;
681
+ return typeof change.id === "string" && typeof change.workspacePath === "string" && typeof change.title === "string" && ["added", "modified", "deleted", "unknown"].includes(change.operation ?? "") && ["observed", "legacy"].includes(change.coverage ?? "") && (!change.resource || change.resource.type === "file_change" && validVersion(change.resource.first) && validVersion(change.resource.last)) && validRevision(change.before) && validRevision(change.after);
682
+ }).map(({ id, title, workspacePath, operation, before, after, resource, coverage, messageId, startedAt, updatedAt }) => ({
683
+ id,
684
+ title,
685
+ workspacePath,
686
+ operation,
687
+ before: compactRevision(before),
688
+ after: compactRevision(after),
689
+ resource,
690
+ coverage,
691
+ messageId,
692
+ startedAt,
693
+ updatedAt
694
+ }));
695
+ }
696
+ function compactRevision(value) {
697
+ return value ? { sha256: value.sha256, size: value.size } : value;
698
+ }
699
+ function normalizeFileOutputs(value) {
700
+ if (!Array.isArray(value)) return [];
701
+ return value.flatMap((item) => {
702
+ if (!item || typeof item !== "object") return [];
703
+ const output = compactOutput(item);
704
+ return output ? [output] : [];
705
+ });
706
+ }
707
+ function compactOutput(value) {
708
+ if (!value || typeof value.id !== "string" || typeof value.title !== "string" || !["file", "image", "document", "spreadsheet", "presentation", "site", "url", "mcp_app"].includes(value.kind) || value.status !== void 0 && value.status !== "success") return null;
709
+ const ref = value.resource;
710
+ const resource = (ref == null ? void 0 : ref.type) === "artifact" && typeof ref.artifactId === "string" ? { type: "artifact", artifactId: ref.artifactId, ...typeof ref.artifactVersionId === "string" ? { artifactVersionId: ref.artifactVersionId } : {} } : (ref == null ? void 0 : ref.type) === "workspace_file" && typeof ref.workspacePath === "string" ? { type: "workspace_file", workspacePath: ref.workspacePath, fileAssetId: ref.fileAssetId, storageFileId: ref.storageFileId } : (ref == null ? void 0 : ref.type) === "url" && typeof ref.url === "string" ? { type: "url", url: ref.url } : void 0;
711
+ if (!resource) return null;
712
+ const { id, kind, title, description, status, origin, workspacePath, mimeType, size, sha256, messageId, updatedAt } = value;
713
+ return { id, kind, title, description, status, resource, origin, workspacePath, mimeType, size, sha256, messageId, updatedAt };
714
+ }
715
+ function validVersion(value) {
716
+ return Boolean(value && typeof value.artifactId === "string" && typeof value.artifactVersionId === "string");
717
+ }
718
+ function validRevision(value) {
719
+ return value == null || typeof value.sha256 === "string" && /^[a-f0-9]{64}$/.test(value.sha256) && Number.isSafeInteger(value.size) && value.size >= 0;
720
+ }
721
+ function mergeFileChanges(items) {
722
+ const byPath = /* @__PURE__ */ new Map();
723
+ for (const item of [...items].sort((a, b) => (a.startedAt ?? a.updatedAt ?? "").localeCompare(b.startedAt ?? b.updatedAt ?? ""))) {
724
+ const previous = byPath.get(item.workspacePath);
725
+ if (!previous || previous.coverage === "legacy") {
726
+ byPath.set(item.workspacePath, item);
727
+ continue;
728
+ }
729
+ if (item.coverage === "legacy") continue;
730
+ const latest = (item.updatedAt ?? "") >= (previous.updatedAt ?? "") ? item : previous;
731
+ const earliest = (item.startedAt ?? item.updatedAt ?? "") < (previous.startedAt ?? previous.updatedAt ?? "") ? item : previous;
732
+ const before = earliest.before;
733
+ const after = latest.after;
734
+ byPath.set(item.workspacePath, {
735
+ ...latest,
736
+ before,
737
+ after,
738
+ startedAt: earliest.startedAt ?? earliest.updatedAt,
739
+ operation: before === null ? "added" : after === null ? "deleted" : "modified",
740
+ resource: earliest.resource && latest.resource ? { type: "file_change", first: earliest.resource.first, last: latest.resource.last } : latest.resource
741
+ });
742
+ }
743
+ return [...byPath.values()].filter((item) => {
744
+ var _a, _b;
745
+ return item.coverage === "legacy" || ((_a = item.before) == null ? void 0 : _a.sha256) !== ((_b = item.after) == null ? void 0 : _b.sha256);
746
+ }).sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""));
747
+ }
748
+ function projectMessageFileActivity(message, contribution) {
749
+ var _a, _b, _c, _d, _e;
750
+ const parts = Array.isArray(message.content) ? message.content : [];
751
+ const observed = [];
752
+ const legacyChanges = [];
753
+ const legacyOutputIds = /* @__PURE__ */ new Set();
754
+ const date = message.updatedAt ?? message.createdAt;
755
+ const updatedAt = date instanceof Date ? date.toISOString() : date;
756
+ const observedToolCalls = new Set(parts.flatMap((part) => {
757
+ var _a2, _b2, _c2;
758
+ const summary = getFileActivityContribution(part) ?? ((_a2 = part.data) == null ? void 0 : _a2.taskSummary) ?? ((_c2 = (_b2 = part.data) == null ? void 0 : _b2._meta) == null ? void 0 : _c2["xpertai/taskSummary"]);
759
+ return (summary == null ? void 0 : summary.fileActivityToolCallId) ? [summary.fileActivityToolCallId] : [];
760
+ }));
761
+ for (const part of parts) {
762
+ const receipt = getFileActivityContribution(part);
763
+ if (receipt) {
764
+ observed.push(receipt);
765
+ continue;
766
+ }
767
+ if ((part == null ? void 0 : part.type) !== "component" || !part.data) continue;
768
+ const data = part.data;
769
+ const explicit = data.taskSummary ?? ((_a = data._meta) == null ? void 0 : _a["xpertai/taskSummary"]);
770
+ if ((explicit == null ? void 0 : explicit.version) === 1) observed.push(explicit);
771
+ if (!writeTools.has(data.tool ?? "") || data.status !== "success") continue;
772
+ const path = (_b = data.input) == null ? void 0 : _b.file_path;
773
+ if (typeof path !== "string" || !path || path.startsWith("/") || path.split("/").includes("..")) continue;
774
+ legacyOutputIds.add(`workspace-file:${path}`);
775
+ if ((explicit == null ? void 0 : explicit.fileActivityVersion) === 1 || part.id && observedToolCalls.has(part.id)) continue;
776
+ legacyChanges.push({ id: `file-change:${path}`, title: path, workspacePath: path, operation: "unknown", coverage: "legacy", messageId: message.id, updatedAt });
777
+ }
778
+ if (!observed.length && !legacyOutputIds.size && !((_c = contribution.outputs) == null ? void 0 : _c.length) && !((_d = contribution.fileChanges) == null ? void 0 : _d.length)) return contribution;
779
+ const outputs = [...contribution.outputs ?? [], ...observed.flatMap((item) => item.outputs ?? [])];
780
+ const byId = /* @__PURE__ */ new Map();
781
+ for (const raw of outputs) {
782
+ const output = compactOutput(raw);
783
+ if (!output) continue;
784
+ if (legacyOutputIds.has(output.id) && output.origin !== "tool" && output.origin !== "integration") continue;
785
+ if ((((_e = byId.get(output.id)) == null ? void 0 : _e.updatedAt) ?? "") > (output.updatedAt ?? updatedAt ?? "")) continue;
786
+ byId.set(output.id, { ...output, origin: output.origin ?? "legacy", messageId: message.id ?? output.messageId, updatedAt: output.updatedAt ?? updatedAt });
787
+ }
788
+ const changes = mergeFileChanges([
789
+ ...legacyChanges,
790
+ ...normalizeFileChanges(contribution.fileChanges),
791
+ ...observed.flatMap((item) => normalizeFileChanges(item.fileChanges))
792
+ ].map((item) => ({ ...item, messageId: message.id ?? item.messageId })));
793
+ const coverage = [contribution.fileChangeCoverage, ...observed.map((item) => item.fileChangeCoverage)];
794
+ const fileChangeCoverage = coverage.includes("unavailable") ? "unavailable" : coverage.includes("partial") ? "partial" : coverage.includes("bounded") ? "bounded" : void 0;
795
+ return { ...contribution, fileActivityVersion: 1, fileChangeCoverage, outputs: [...byId.values()], fileChanges: changes };
796
+ }
797
+ function parseFileChangeReport(value) {
798
+ if (!value || typeof value !== "object") return null;
799
+ const report = value;
800
+ const revision = (item) => item === null || Boolean(item && validRevision(item) && (item.text === void 0 || typeof item.text === "string" && item.text.length <= 32768));
801
+ return report.schema === "xpert.file-change.v1" && typeof report.workspacePath === "string" && revision(report.before) && revision(report.after) ? report : null;
802
+ }
803
+ const MAX_DIFF_CELLS = 4e6;
804
+ function countFileChangeLines(report) {
805
+ var _a, _b;
806
+ if (report.before && report.before.text === void 0 || report.after && report.after.text === void 0) return { status: "unavailable" };
807
+ const lines = (text) => text ? text.replace(/\r\n/g, "\n").replace(/\n$/, "").split("\n") : [];
808
+ const before = lines(((_a = report.before) == null ? void 0 : _a.text) ?? ""), after = lines(((_b = report.after) == null ? void 0 : _b.text) ?? "");
809
+ let start = 0, endBefore = before.length, endAfter = after.length;
810
+ while (start < endBefore && start < endAfter && before[start] === after[start]) start++;
811
+ while (endBefore > start && endAfter > start && before[endBefore - 1] === after[endAfter - 1]) {
812
+ endBefore--;
813
+ endAfter--;
814
+ }
815
+ const n = endBefore - start, m = endAfter - start;
816
+ if (n * m > MAX_DIFF_CELLS) return { status: "unavailable" };
817
+ let previous = new Uint32Array(m + 1), current = new Uint32Array(m + 1);
818
+ for (let i = 0; i < n; i++) {
819
+ for (let j = 0; j < m; j++) current[j + 1] = before[start + i] === after[start + j] ? previous[j] + 1 : Math.max(previous[j + 1], current[j]);
820
+ [previous, current] = [current, previous];
821
+ }
822
+ return { status: "ready", added: m - previous[m], removed: n - previous[m] };
823
+ }
531
824
  exports.CHAT_EVENT_TYPE_FOLLOW_UP_CONSUMED = constants.CHAT_EVENT_TYPE_FOLLOW_UP_CONSUMED;
532
825
  exports.ChatMessageEventTypeEnum = constants.ChatMessageEventTypeEnum;
533
826
  exports.ChatMessageStepCategory = constants.ChatMessageStepCategory;
@@ -546,12 +839,19 @@ exports.REQUEST_USER_INPUT_RESULT_TYPE = REQUEST_USER_INPUT_RESULT_TYPE;
546
839
  exports.REQUEST_USER_INPUT_TOOL_NAME = REQUEST_USER_INPUT_TOOL_NAME;
547
840
  exports.TOOL_OUTPUT_PRESENTATION_TYPE = TOOL_OUTPUT_PRESENTATION_TYPE;
548
841
  exports.TOOL_OUTPUT_PRESENTATION_VERSION = TOOL_OUTPUT_PRESENTATION_VERSION;
842
+ exports.chatSkillUsageKey = chatSkillUsageKey;
549
843
  exports.clampPetPosition = clampPetPosition;
844
+ exports.countFileChangeLines = countFileChangeLines;
845
+ exports.fileChangeRangeKey = fileChangeRangeKey;
846
+ exports.getFileActivityContribution = getFileActivityContribution;
847
+ exports.getLegacyFileActivityContribution = getLegacyFileActivityContribution;
848
+ exports.getMessageSkillUsages = getMessageSkillUsages;
550
849
  exports.getPinnedPetPosition = getPinnedPetPosition;
551
850
  exports.isClientToolInterrupt = isClientToolInterrupt;
552
851
  exports.isClientToolInterruptPayload = isClientToolInterruptPayload;
553
852
  exports.isClientToolInterruptTask = isClientToolInterruptTask;
554
853
  exports.isClientToolRequest = isClientToolRequest;
854
+ exports.isFileActivityContent = isFileActivityContent;
555
855
  exports.isHITLDecisionType = isHITLDecisionType;
556
856
  exports.isHITLInterrupt = isHITLInterrupt;
557
857
  exports.isHITLInterruptPayload = isHITLInterruptPayload;
@@ -566,12 +866,22 @@ exports.isToolCallInterrupt = isToolCallInterrupt;
566
866
  exports.isToolCallInterruptPayload = isToolCallInterruptPayload;
567
867
  exports.isToolCallInterruptTask = isToolCallInterruptTask;
568
868
  exports.isToolCallRequest = isToolCallRequest;
869
+ exports.mergeChatSkillUsages = mergeChatSkillUsages;
870
+ exports.mergeFileChanges = mergeFileChanges;
569
871
  exports.mergePetSpriteAtlas = mergePetSpriteAtlas;
570
872
  exports.normalizeBoundsPadding = normalizeBoundsPadding;
873
+ exports.normalizeChatSkillUsages = normalizeChatSkillUsages;
874
+ exports.normalizeFileChanges = normalizeFileChanges;
875
+ exports.normalizeFileOutputs = normalizeFileOutputs;
571
876
  exports.normalizeHITLRequest = normalizeHITLRequest;
572
877
  exports.normalizePetOptions = normalizePetOptions;
573
878
  exports.normalizeRequestLanguage = normalizeRequestLanguage;
879
+ exports.normalizeThreadReference = normalizeThreadReference;
880
+ exports.parseFileActivityContent = parseFileActivityContent;
881
+ exports.parseFileChangeReport = parseFileChangeReport;
574
882
  exports.petSpriteAtlas = petSpriteAtlas;
883
+ exports.projectMessageFileActivity = projectMessageFileActivity;
575
884
  exports.resolveLocalizedText = resolveLocalizedText;
576
885
  exports.resolvePetCharacter = resolvePetCharacter;
886
+ exports.upsertFileActivityContent = upsertFileActivityContent;
577
887
  //# sourceMappingURL=index.cjs.map