@aikdna/kdna-core 0.1.0 → 0.2.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.
- package/package.json +1 -1
- package/src/compose.js +123 -0
- package/src/index.js +2 -0
- package/src/index.mjs +2 -0
- package/src/types.d.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikdna/kdna-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "KDNA core library — pure logic for loading, validating, linting, and rendering KDNA domain cognition packages. Zero Node.js dependencies.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "src/index.js",
|
package/src/compose.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KDNA Compose — Multi-domain composition logic.
|
|
3
|
+
*
|
|
4
|
+
* Merges judgment constraints from multiple domains into a single
|
|
5
|
+
* agent context. Domains contribute independently; conflicts are
|
|
6
|
+
* surfaced, not silently resolved.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { formatContext } = require('./loader');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compose multiple loaded domains into a single agent context string.
|
|
13
|
+
*
|
|
14
|
+
* Each domain contributes its own section. If two domains define
|
|
15
|
+
* conflicting axioms or banned terms, both are included — the agent
|
|
16
|
+
* must report the conflict, not pick one.
|
|
17
|
+
*
|
|
18
|
+
* @param {Array<{core:object, patterns:object}>} domains
|
|
19
|
+
* @param {object} [options]
|
|
20
|
+
* @param {string} [options.separator] — section separator
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
function composeContext(domains, options = {}) {
|
|
24
|
+
if (!domains || !domains.length) return '';
|
|
25
|
+
|
|
26
|
+
const separator = options.separator || '\n\n---\n\n';
|
|
27
|
+
|
|
28
|
+
return domains
|
|
29
|
+
.filter((d) => d && d.core && d.patterns)
|
|
30
|
+
.map((d) => formatContext(d))
|
|
31
|
+
.filter((ctx) => ctx)
|
|
32
|
+
.join(separator);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Match user input against domain trigger_signals to determine
|
|
37
|
+
* which domains should be activated.
|
|
38
|
+
*
|
|
39
|
+
* Each domain can define trigger_signals in its core (array of
|
|
40
|
+
* keywords or phrases). This function checks if any signal matches
|
|
41
|
+
* the input and returns the list of matching domain indices.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} input — user task description
|
|
44
|
+
* @param {Array<{id:string, core:{trigger_signals?:string[]}}>} domains
|
|
45
|
+
* @returns {number[]} — indices of matching domains
|
|
46
|
+
*/
|
|
47
|
+
function classifySignals(input, domains) {
|
|
48
|
+
if (!input || !domains || !domains.length) return [];
|
|
49
|
+
|
|
50
|
+
const lower = input.toLowerCase();
|
|
51
|
+
const active = [];
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < domains.length; i++) {
|
|
54
|
+
const domain = domains[i];
|
|
55
|
+
const signals = domain.core?.trigger_signals || [];
|
|
56
|
+
|
|
57
|
+
if (!signals.length) {
|
|
58
|
+
// No signals defined → domain is primary (always active)
|
|
59
|
+
active.push(i);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const matched = signals.some((signal) => lower.includes(signal.toLowerCase()));
|
|
64
|
+
if (matched) active.push(i);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return active;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Compose self-check items from multiple domains into a single
|
|
72
|
+
* checklist. Each domain's checks are prefixed with its domain name
|
|
73
|
+
* so conflicts are visible.
|
|
74
|
+
*
|
|
75
|
+
* @param {Array<{id:string, core:{meta:{domain:string}}, patterns:{self_check:string[]}}>} domains
|
|
76
|
+
* @returns {string[]}
|
|
77
|
+
*/
|
|
78
|
+
function composeChecks(domains) {
|
|
79
|
+
if (!domains || !domains.length) return [];
|
|
80
|
+
|
|
81
|
+
const checks = [];
|
|
82
|
+
|
|
83
|
+
for (const domain of domains) {
|
|
84
|
+
const name = domain.core?.meta?.domain || domain.id || 'unknown';
|
|
85
|
+
const items = domain.patterns?.self_check || [];
|
|
86
|
+
|
|
87
|
+
if (!items.length) continue;
|
|
88
|
+
|
|
89
|
+
if (domains.length === 1) {
|
|
90
|
+
checks.push(...items);
|
|
91
|
+
} else {
|
|
92
|
+
for (const item of items) {
|
|
93
|
+
checks.push(`[${name}] ${item}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return checks;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Load multiple domains from data maps and compose their context.
|
|
103
|
+
* Convenience function: loads each domain, then composes.
|
|
104
|
+
*
|
|
105
|
+
* @param {Array<object>} dataMaps — array of file data maps
|
|
106
|
+
* @param {object} [options] — passed to loadDomainFromFiles + composeContext
|
|
107
|
+
* @returns {{ domains: Array, context: string, activeIndices: number[] }}
|
|
108
|
+
*/
|
|
109
|
+
function loadAndCompose(dataMaps, options = {}) {
|
|
110
|
+
const { loadDomainFromFiles } = require('./loader');
|
|
111
|
+
|
|
112
|
+
const domains = dataMaps.map((dm) => loadDomainFromFiles(dm, options)).filter(Boolean);
|
|
113
|
+
|
|
114
|
+
const { input = '' } = options;
|
|
115
|
+
const activeIndices = classifySignals(input, domains);
|
|
116
|
+
|
|
117
|
+
const activeDomains = activeIndices.map((i) => domains[i]);
|
|
118
|
+
const context = composeContext(activeDomains, options);
|
|
119
|
+
|
|
120
|
+
return { domains, context, activeIndices };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = { composeContext, classifySignals, composeChecks, loadAndCompose };
|
package/src/index.js
CHANGED
|
@@ -5,10 +5,12 @@ const loader = require('./loader');
|
|
|
5
5
|
const lint = require('./lint-pure');
|
|
6
6
|
const validate = require('./validate-pure');
|
|
7
7
|
const render = require('./render');
|
|
8
|
+
const compose = require('./compose');
|
|
8
9
|
|
|
9
10
|
module.exports = {
|
|
10
11
|
...loader,
|
|
11
12
|
...lint,
|
|
12
13
|
...validate,
|
|
13
14
|
...render,
|
|
15
|
+
...compose,
|
|
14
16
|
};
|
package/src/index.mjs
CHANGED
|
@@ -15,3 +15,5 @@ export { lintDomain } from './lint-pure.js';
|
|
|
15
15
|
export { validateDomainSchema, validateCrossFile } from './validate-pure.js';
|
|
16
16
|
|
|
17
17
|
export { renderPreviewHTML, escHtml, renderCard } from './render.js';
|
|
18
|
+
|
|
19
|
+
export { composeContext, classifySignals, composeChecks, loadAndCompose } from './compose.js';
|
package/src/types.d.ts
CHANGED
|
@@ -252,3 +252,9 @@ export function validateCrossFile(dataMap: KDNAFileDataMap): ValidationResult;
|
|
|
252
252
|
export function renderPreviewHTML(domain: LoadedDomain, manifest?: KDNAManifest): string;
|
|
253
253
|
export function escHtml(s: string): string;
|
|
254
254
|
export function renderCard(title: string, count: number | undefined, items: string): string;
|
|
255
|
+
|
|
256
|
+
// Compose
|
|
257
|
+
export function composeContext(domains: LoadedDomain[], options?: { separator?: string }): string;
|
|
258
|
+
export function classifySignals(input: string, domains: Array<{ id: string; core: { trigger_signals?: string[] } }>): number[];
|
|
259
|
+
export function composeChecks(domains: Array<{ id: string; core: { meta: { domain: string } }; patterns: { self_check: string[] } }>): string[];
|
|
260
|
+
export function loadAndCompose(dataMaps: KDNAFileDataMap[], options?: LoadOptions & { separator?: string }): { domains: LoadedDomain[]; context: string; activeIndices: number[] };
|