@exellix/graphs-studio-data-flow 0.1.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.
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Memorix entity **content types** for graph entry (`metadata.graphEntry.inputs[].inputTypes`).
3
+ *
4
+ * Catalox catalog `memorix_entity_content_types` holds **metadata only** (labels, which XMemory
5
+ * op-tier to count via `data.countBinding`, optional `data.editorSlot`). Document counts for
6
+ * **Current records** come from Memorix / XMemory via `@exellix/exellix-runtime`, not from Catalox.
7
+ */
8
+
9
+ export const MEMORIX_ENTITY_CONTENT_TYPES_CATALOG_ID = 'memorix_entity_content_types';
10
+
11
+ /** @type {Readonly<Record<string, string>>} Deprecated graph-entry ids → canonical `contentTypeKey`. */
12
+ export const DEPRECATED_GRAPH_ENTRY_INPUT_TYPE_IDS = Object.freeze({
13
+ snapshotsRecords: 'snapshots',
14
+ scoppedQuestions: 'scoping_questions',
15
+ eventTrigger: 'event_trigger',
16
+ });
17
+
18
+ /**
19
+ * @param {unknown} v
20
+ * @returns {string}
21
+ */
22
+ export function pickMemorixContentTypeStr(v) {
23
+ return typeof v === 'string' ? v.trim() : '';
24
+ }
25
+
26
+ /**
27
+ * @param {string} typeId
28
+ * @returns {string}
29
+ */
30
+ export function normalizeMemorixEntityContentTypeId(typeId) {
31
+ const id = pickMemorixContentTypeStr(typeId);
32
+ if (!id) return '';
33
+ return DEPRECATED_GRAPH_ENTRY_INPUT_TYPE_IDS[id] ?? id;
34
+ }
35
+
36
+ /**
37
+ * @param {unknown} rawTypes
38
+ * @returns {string[]|undefined}
39
+ */
40
+ export function normalizeGraphEntryInputTypes(rawTypes) {
41
+ if (!Array.isArray(rawTypes)) return undefined;
42
+ const out = [];
43
+ const seen = new Set();
44
+ for (const t of rawTypes) {
45
+ const id = normalizeMemorixEntityContentTypeId(t);
46
+ if (!id || seen.has(id)) continue;
47
+ seen.add(id);
48
+ out.push(id);
49
+ }
50
+ return out.length ? out : undefined;
51
+ }
52
+
53
+ /**
54
+ * @param {{ itemId?: string, data?: unknown }} row
55
+ * @returns {string}
56
+ */
57
+ export function memorixEntityContentTypeKeyFromRow(row) {
58
+ if (!row || typeof row !== 'object') return '';
59
+ const itemId = pickMemorixContentTypeStr(row.itemId);
60
+ const data =
61
+ row.data != null && typeof row.data === 'object' && !Array.isArray(row.data)
62
+ ? /** @type {Record<string, unknown>} */ (row.data)
63
+ : {};
64
+ const fromData = pickMemorixContentTypeStr(data.contentTypeKey ?? data.key ?? data.slug);
65
+ return fromData || itemId;
66
+ }
67
+
68
+ /**
69
+ * @param {Array<{ itemId?: string, data?: unknown }>} catalogRows
70
+ * @param {string} typeId
71
+ * @returns {{ itemId?: string, data?: unknown } | null}
72
+ */
73
+ export function findMemorixEntityContentTypeCatalogRow(catalogRows, typeId) {
74
+ const id = normalizeMemorixEntityContentTypeId(typeId);
75
+ if (!id || !Array.isArray(catalogRows)) return null;
76
+ for (const row of catalogRows) {
77
+ if (!row || typeof row !== 'object') continue;
78
+ const key = memorixEntityContentTypeKeyFromRow(row);
79
+ const itemId = pickMemorixContentTypeStr(row.itemId);
80
+ if (key === id || itemId === id) return row;
81
+ }
82
+ return null;
83
+ }
84
+
85
+ /**
86
+ * @param {Array<{ itemId?: string, data?: unknown }>} items
87
+ * @param {string} typeId
88
+ * @returns {{ countBinding: string, editorSlot: string | null } | null}
89
+ */
90
+ export function memorixEntityContentTypeBindingFromCatalogItems(items, typeId) {
91
+ const id = normalizeMemorixEntityContentTypeId(typeId);
92
+ if (!id || !Array.isArray(items)) return null;
93
+ for (const it of items) {
94
+ if (!it || typeof it !== 'object') continue;
95
+ const row = /** @type {{ itemId?: string, data?: unknown }} */ (it);
96
+ const key = memorixEntityContentTypeKeyFromRow(row);
97
+ const itemId = pickMemorixContentTypeStr(row.itemId);
98
+ if (key !== id && itemId !== id) continue;
99
+ const data =
100
+ row.data != null && typeof row.data === 'object' && !Array.isArray(row.data)
101
+ ? /** @type {Record<string, unknown>} */ (row.data)
102
+ : {};
103
+ const countBinding =
104
+ pickMemorixContentTypeStr(data.countBinding) || pickMemorixContentTypeStr(data.countTier);
105
+ const editorSlot = pickMemorixContentTypeStr(data.editorSlot) || null;
106
+ if (!countBinding) {
107
+ throw new Error(
108
+ `Memorix entity content type "${id}" is missing data.countBinding in Catalox catalog ` +
109
+ `"${MEMORIX_ENTITY_CONTENT_TYPES_CATALOG_ID}". ` +
110
+ 'Counts are loaded from Memorix (XMemory op-tier); Catalox only declares which tier to use.',
111
+ );
112
+ }
113
+ return { countBinding, editorSlot };
114
+ }
115
+ return null;
116
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Memorix descriptor helpers for scoped local skills — aligned with
3
+ * `@exellix/graph-engine` `memorixScopedConfig.ts` (graph-engine 6.x).
4
+ */
5
+
6
+ /** @typedef {import('@exellix/graph-engine/dist/src/types/taskNodeConfiguration.js').TaskNodeTaskConfiguration} TaskNodeTaskConfiguration */
7
+
8
+ export const DEFAULT_SCOPED_CONTENT_TYPES = ['inferences', 'decisions'];
9
+
10
+ /**
11
+ * @param {TaskNodeTaskConfiguration | Record<string, unknown> | null | undefined} cfg
12
+ * @returns {string | undefined}
13
+ */
14
+ export function resolveMemorixItemDescriptorId(cfg) {
15
+ if (!cfg || typeof cfg !== 'object') return undefined;
16
+ const memorix = typeof cfg.memorixItemDescriptorId === 'string' ? cfg.memorixItemDescriptorId.trim() : '';
17
+ if (memorix) return memorix;
18
+ const item = typeof cfg.itemDescriptorId === 'string' ? cfg.itemDescriptorId.trim() : '';
19
+ return item || undefined;
20
+ }
21
+
22
+ /**
23
+ * @param {TaskNodeTaskConfiguration | Record<string, unknown> | null | undefined} cfg
24
+ * @param {string} contentType
25
+ * @returns {string}
26
+ */
27
+ export function resolveMemorixWriteDescriptorId(cfg, contentType) {
28
+ const base = cfg && typeof cfg === 'object' ? cfg : {};
29
+ const mapped = base.memorixWriteDescriptors?.[contentType];
30
+ if (typeof mapped === 'string' && mapped.trim()) return mapped.trim();
31
+ if (contentType === 'inferences' || contentType === 'decisions') {
32
+ const legacy =
33
+ (typeof base.memorixWriteDescriptorId === 'string' ? base.memorixWriteDescriptorId.trim() : '') ||
34
+ (typeof base.writeDescriptorId === 'string' ? base.writeDescriptorId.trim() : '');
35
+ if (legacy && contentType === 'inferences') return legacy;
36
+ }
37
+ return contentType;
38
+ }
39
+
40
+ /**
41
+ * Pure metadata + `taskConfiguration` execution bag (graph-engine 5.0+).
42
+ *
43
+ * @param {unknown} node
44
+ * @returns {Record<string, unknown>}
45
+ */
46
+ export function nodeAuthoringBag(node) {
47
+ const n = /** @type {{ metadata?: unknown; taskConfiguration?: unknown }} */ (node);
48
+ const meta =
49
+ n?.metadata && typeof n.metadata === 'object' && !Array.isArray(n.metadata)
50
+ ? /** @type {Record<string, unknown>} */ (n.metadata)
51
+ : {};
52
+ const tc =
53
+ n?.taskConfiguration && typeof n.taskConfiguration === 'object' && !Array.isArray(n.taskConfiguration)
54
+ ? /** @type {Record<string, unknown>} */ (n.taskConfiguration)
55
+ : {};
56
+ return { ...meta, ...tc };
57
+ }
58
+
59
+ /**
60
+ * @param {unknown} node
61
+ * @returns {string | undefined}
62
+ */
63
+ export function resolveMemorixItemDescriptorIdFromNode(node) {
64
+ return resolveMemorixItemDescriptorId(nodeAuthoringBag(node));
65
+ }
66
+
67
+ /**
68
+ * Collect unique Memorix item descriptor ids from scoped-data-reader nodes.
69
+ *
70
+ * @param {unknown} graph
71
+ * @returns {string[]}
72
+ */
73
+ export function collectMemorixItemDescriptorIdsFromGraph(graph) {
74
+ /** @type {Set<string>} */
75
+ const ids = new Set();
76
+ const nodes = Array.isArray(graph?.nodes)
77
+ ? graph.nodes
78
+ : graph?.nodes && typeof graph.nodes === 'object'
79
+ ? Object.values(graph.nodes)
80
+ : [];
81
+ for (const node of nodes) {
82
+ if (!node || typeof node !== 'object') continue;
83
+ const sk = /** @type {{ skillKey?: string }} */ (node).skillKey;
84
+ if (sk !== 'scoped-data-reader') continue;
85
+ const bag = nodeAuthoringBag(node);
86
+ const id = resolveMemorixItemDescriptorId(bag);
87
+ if (id) ids.add(id);
88
+ const pack = bag.pack;
89
+ if (Array.isArray(pack)) {
90
+ for (const slot of pack) {
91
+ if (!slot || typeof slot !== 'object') continue;
92
+ const slotId = resolveMemorixItemDescriptorId(/** @type {Record<string, unknown>} */ (slot));
93
+ if (slotId) ids.add(slotId);
94
+ }
95
+ }
96
+ }
97
+ return [...ids].sort();
98
+ }
99
+
100
+ /**
101
+ * @param {unknown} node
102
+ * @returns {boolean}
103
+ */
104
+ export function nodeUsesLegacyScopingMapId(node) {
105
+ const bag = nodeAuthoringBag(node);
106
+ const legacy = typeof bag.scopingMapId === 'string' ? bag.scopingMapId.trim() : '';
107
+ return !!legacy && !resolveMemorixItemDescriptorId(bag);
108
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Canonical graph-engine 5.0+ readers for task execution fields on **`taskConfiguration`**.
3
+ *
4
+ * Legacy shapes (`metadata.aiTaskProfile`, …) are migrated on load by
5
+ * {@link migrateGraphDocumentTaskNodesForEngine5} and {@link migrateTaskNodeWebQueryTemplate}.
6
+ */
7
+
8
+ export {
9
+ readWebScoping,
10
+ readNodeWebScopingEnabled,
11
+ readNodeWebScopingQuestions,
12
+ readNodeWebQueryTemplate,
13
+ readNodeWebQueryTemplates,
14
+ readNodeWebScopeOptions,
15
+ readNodeWebScopeEnabled,
16
+ readNodeWebQueryStrings,
17
+ readAiTaskProfile,
18
+ patchWebQueryTemplateOnNode,
19
+ patchWebScopingOnNode,
20
+ migrateTaskNodeWebQueryTemplate,
21
+ } from './webQueryTemplate.js';
22
+
23
+ import { readTaskConfiguration } from './taskNodeConfiguration.js';
24
+
25
+ /**
26
+ * @param {unknown} node
27
+ * @returns {Record<string, unknown> | null}
28
+ */
29
+ function readAiTaskProfileLocal(node) {
30
+ const tc = readTaskConfiguration(node);
31
+ if (!tc) return null;
32
+ const profile = tc.aiTaskProfile;
33
+ if (!profile || typeof profile !== 'object' || Array.isArray(profile)) return null;
34
+ return /** @type {Record<string, unknown>} */ (profile);
35
+ }
36
+
37
+ /**
38
+ * @param {unknown} node
39
+ * @returns {Record<string, unknown> | null}
40
+ */
41
+ export function readInputSynthesis(node) {
42
+ const profile = readAiTaskProfileLocal(node);
43
+ if (!profile) return null;
44
+ const is = profile.inputSynthesis;
45
+ if (!is || typeof is !== 'object' || Array.isArray(is)) return null;
46
+ return /** @type {Record<string, unknown>} */ (is);
47
+ }
48
+
49
+ /**
50
+ * PRE synthesized-context phase is active iff
51
+ * `taskConfiguration.aiTaskProfile.inputSynthesis.enabled === true`.
52
+ *
53
+ * @param {unknown} node
54
+ * @returns {boolean}
55
+ */
56
+ export function readNodeInputSynthesisEnabled(node) {
57
+ const is = readInputSynthesis(node);
58
+ return is != null && is.enabled === true;
59
+ }