theprogrammablemind 9.7.1 → 9.8.0-beta.1

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/src/debug.js CHANGED
@@ -27,6 +27,18 @@ const unhit = (name) => {
27
27
  hits[name] = false
28
28
  }
29
29
 
30
+ const hitScoped = async (name, call) => {
31
+ hit(name)
32
+ try {
33
+ const result = await call()
34
+ unhit(name)
35
+ return result
36
+ } catch( e ) {
37
+ unhit(name)
38
+ throw e
39
+ }
40
+ }
41
+
30
42
  const wasHit = (name) => {
31
43
  return hits[name]
32
44
  }
@@ -64,16 +76,19 @@ const _break = (name) => {
64
76
  }
65
77
  }
66
78
 
79
+ const breakAt = _break;
80
+
67
81
  module.exports = {
68
82
  counter,
69
83
  get,
70
84
  _break, // break is a keyword
71
-
85
+ breakAt,
72
86
  // used for tests
73
87
  reset,
74
88
  hit,
75
89
  unhit,
76
90
  wasHit,
77
91
  getDb,
78
- setDb
92
+ setDb,
93
+ hitScoped,
79
94
  }
package/src/digraph.js CHANGED
@@ -73,11 +73,25 @@ class Digraph {
73
73
  this._edges = edges
74
74
  }
75
75
 
76
- /*
77
- set edges(edges) {
78
- this._edges = edges.map( toA )
76
+ tos(from) {
77
+ const tos = []
78
+ for (const edge of this._edges) {
79
+ if (edge[0] == from) {
80
+ tos.push(edge[1])
81
+ }
82
+ }
83
+ return tos
84
+ }
85
+
86
+ froms(to) {
87
+ const froms = []
88
+ for (const edge of this._edges) {
89
+ if (edge[1] == to) {
90
+ froms.push(edge[0])
91
+ }
92
+ }
93
+ return froms
79
94
  }
80
- */
81
95
 
82
96
  acdcs (s, from, to) {
83
97
  if (!s) {
@@ -170,18 +184,6 @@ class Digraph {
170
184
  return this.minima(common)
171
185
  }
172
186
 
173
- /*
174
- maxima (nodes) {
175
- const maxima = new Set(nodes)
176
- const descendants = new Set([])
177
- nodes.forEach((node) => {
178
- this.descendants(node).forEach((n) => descendants.add(n))
179
- })
180
- descendants.forEach((n) => maxima.delete(n))
181
- return maxima
182
- }
183
- */
184
-
185
187
  add (child, parent) {
186
188
  this._edges.push([child, parent])
187
189
  }
@@ -39,6 +39,26 @@ class DigraphInternal {
39
39
  this._edges = edges
40
40
  }
41
41
 
42
+ tos(from) {
43
+ const tos = []
44
+ for (const edge of this._edges) {
45
+ if (edge[0] == from) {
46
+ tos.push(edge[1])
47
+ }
48
+ }
49
+ return tos
50
+ }
51
+
52
+ froms(to) {
53
+ const froms = []
54
+ for (const edge of this._edges) {
55
+ if (edge[1] == to) {
56
+ froms.push(edge[0])
57
+ }
58
+ }
59
+ return froms
60
+ }
61
+
42
62
  get length () {
43
63
  return this._edges.length
44
64
  }
@@ -137,18 +157,6 @@ class DigraphInternal {
137
157
  return this.minima(common)
138
158
  }
139
159
 
140
- /*
141
- maxima (nodes) {
142
- const maxima = new Set(nodes)
143
- const descendants = new Set([])
144
- nodes.forEach((node) => {
145
- this.descendants(node).forEach((n) => descendants.add(n))
146
- })
147
- descendants.forEach((n) => maxima.delete(n))
148
- return maxima
149
- }
150
- */
151
-
152
160
  add (child, parent) {
153
161
  this._edges.push([child, parent])
154
162
  }
package/src/flatten.js CHANGED
@@ -1,7 +1,8 @@
1
- const { isArray, isObject, isCompound } = require('./helpers')
1
+ const { isArray, isObject, isCompound, } = require('./helpers')
2
+ const debug = require('./debug')
2
3
  const _ = require('lodash')
3
4
 
4
- const DEBUG = (...args) => {
5
+ const DEBUG = (label, details) => {
5
6
  // DEBUG(...args)
6
7
  }
7
8
 
@@ -46,33 +47,24 @@ const zip = (a1, a2) => {
46
47
  }
47
48
 
48
49
  const flattenListHelper = (markers, values) => {
49
- const flats = []
50
50
  let wasFlattened = false
51
- let singles = []
51
+ const all = []
52
52
  for (const value of values) {
53
53
  if (!isCompound(value)) {
54
- singles.push(value)
54
+ all.push([value])
55
55
  } else {
56
56
  const [more, wf] = flatten(markers, value)
57
57
  if (wf) {
58
58
  wasFlattened = wasFlattened || wf
59
- flats.push(more)
59
+ all.push(more)
60
60
  } else {
61
- singles = singles.concat(more)
61
+ all.push(...more.map((m) => [m]))
62
62
  }
63
63
  }
64
64
  }
65
65
 
66
- // product does weirdness with only choice
67
- if (!wasFlattened) {
68
- return [[singles], wasFlattened]
69
- } else {
70
- const results = []
71
- for (const flat of cartesian(...flats)) {
72
- results.push(singles.concat(flat))
73
- }
74
- return [results, wasFlattened]
75
- }
66
+ const result = cartesian(...all)
67
+ return [result, wasFlattened]
76
68
  }
77
69
 
78
70
  // returns (list, wasFlattened)
@@ -84,6 +76,9 @@ const flatten = (markers, value) => {
84
76
  if (value.flatten === false) {
85
77
  return [[value], false]
86
78
  }
79
+
80
+ const flatten_ignore = value.flatten_ignore || []
81
+
87
82
  const marker = value.marker
88
83
  let properties = value
89
84
 
@@ -113,8 +108,9 @@ const flatten = (markers, value) => {
113
108
  for (const key in properties) {
114
109
  let wf = false
115
110
  let values
116
- // if isinstance(properties[key], Context) {
117
- if (isObject(properties[key])) {
111
+ if (flatten_ignore.includes(key)) {
112
+ values = [properties[key]]
113
+ } else if (isObject(properties[key])) {
118
114
  const context = properties[key];
119
115
  [values, wf] = flatten(markers, context)
120
116
  // } else if (isinstance(properties[key], list)) {
package/src/fragments.js CHANGED
@@ -1,6 +1,28 @@
1
1
  const _ = require('lodash')
2
2
  const helpers = require('./helpers')
3
3
 
4
+ function createChangeTracker(obj) {
5
+ const changes = new Set();
6
+
7
+ const handler = {
8
+ set(target, prop, value) {
9
+ changes.add(prop);
10
+ target[prop] = value;
11
+ return true;
12
+ },
13
+ deleteProperty(target, prop) {
14
+ changes.add(prop);
15
+ delete target[prop];
16
+ return true;
17
+ }
18
+ };
19
+
20
+ return {
21
+ proxy: new Proxy(obj, handler),
22
+ getChanges: () => Array.from(changes)
23
+ };
24
+ }
25
+
4
26
  function fragmentInstantiator (args, contexts) {
5
27
  return new Object({
6
28
  contexts: () => {
@@ -13,13 +35,15 @@ function fragmentInstantiator (args, contexts) {
13
35
  args.pathEquals = helpers.pathEquals
14
36
  while (todo.length > 0) {
15
37
  const { context, path } = todo.pop()
16
- args.context = context
38
+ const { proxy, getChanges } = createChangeTracker(context);
39
+ args.context = proxy
17
40
  args.path = path
18
41
  for (const mapping of mappings) {
19
42
  if (await mapping.match(args)) {
20
43
  await mapping.apply(args)
21
44
  }
22
45
  }
46
+ const ignore = getChanges()
23
47
  for (const key of Object.keys(context)) {
24
48
  // if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
25
49
  if (!helpers.isCompound(context[key])) {
@@ -28,7 +52,9 @@ function fragmentInstantiator (args, contexts) {
28
52
  if (context[key].instantiated) {
29
53
  continue
30
54
  }
31
- todo.push({ context: context[key], path: [...path, key] })
55
+ if (!ignore.includes(key)) {
56
+ todo.push({ context: context[key], path: [...path, key] })
57
+ }
32
58
  }
33
59
  }
34
60
  if (contexts.length == 1 && instantiated.length == 1) {
package/src/generators.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const { args: contextArgs, normalizeGenerator } = require('./helpers')
2
2
  const Lines = require('../lines')
3
3
  const helpers = require('./helpers')
4
+ const debug = require('./debug')
4
5
 
5
6
  class Generator {
6
7
  // constructor ({ match, apply, uuid, index, km, priority, notes }) {
@@ -65,14 +66,16 @@ class Generator {
65
66
  }
66
67
  const args = Object.assign({}, baseArgs, moreArgs, (baseArgs.getUUIDScoped || (() => { return {} }))(this.uuid))
67
68
  // return this.match(args)
68
- const matches = await this.match(args)
69
- if ((matches && (options.debug || {}).match) ||
70
- callId === this.callId) {
71
- // next line is the matcher
72
- debugger // eslint-disable-line no-debugger
73
- await this.match(args)
74
- }
75
- return matches
69
+ return await debug.hitScoped(args.callId, async () => {
70
+ const matches = await this.match(args)
71
+ if ((matches && (options.debug || {}).match) ||
72
+ callId === this.callId) {
73
+ // next line is the matcher
74
+ debugger // eslint-disable-line no-debugger
75
+ await this.match(args)
76
+ }
77
+ return matches
78
+ })
76
79
  }
77
80
 
78
81
  // apply (baseArgs, objects, g, gs, context, hierarchy, config, response, log, options = {}) {
@@ -121,11 +124,12 @@ class Generator {
121
124
  if (this.property === 'generatorp') {
122
125
  args.g = args.gp
123
126
  }
124
- if ((options.debug || {}).apply ||
125
- callId === this.callId) {
126
- debugger // eslint-disable-line no-debugger
127
- }
128
- return await this._apply(args)
127
+ return await debug.hitScoped(args.callId, async () => {
128
+ if ((options.debug || {}).apply || process.env.DEBUG_CALLID == args.callId || callId === this.callId) {
129
+ debugger // eslint-disable-line no-debugger
130
+ }
131
+ return await this._apply(args) // DEBUG: This is the line you want to step into
132
+ })
129
133
  }
130
134
  }
131
135
 
@@ -180,12 +184,22 @@ class Generators {
180
184
  let generated = ''
181
185
  let applied = false
182
186
  const stack = args.calls.push()
187
+ const pOrRTag = assumed.isResponse ? "(RESPONSE)" : "(PARAPHRASE)"
188
+ const finallyList = []; // called after the generator is processed
189
+ args._finally = (call) => finallyList.unshift(call)
183
190
  for (let igenerator = 0; igenerator < this.generators.length; ++igenerator) {
184
191
  const generator = this.generators[igenerator]
185
192
  if (await generator.matches(args, objects, context, hierarchy, config, options)) {
186
193
  const log = (message) => { this.logs.push(message) }
187
194
  // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
188
195
  let errorMessage = 'The apply function did not return a value'
196
+ if (process.env.TPMKMS_TRACE) {
197
+ console.error("TPMKMS_TRACE", debug.counter("TPMKMS_TRACE"))
198
+ console.error(generator.toLabel())
199
+ console.error(generator.toString())
200
+ console.log(`To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
201
+ }
202
+
189
203
  try {
190
204
  generated = await generator.apply(args, objects, context, hierarchy, config, response, log, options)
191
205
  } catch (e) {
@@ -207,6 +221,7 @@ class Generators {
207
221
  const widths = Lines.addRemainder([10, 10])
208
222
  const lines = new Lines(widths)
209
223
  lines.setElement(0, 0, 'Generator')
224
+ lines.setElement(0, 1, `#${context.context_id || "?"}`)
210
225
  const source = `${generator.km}/#${generator.index}`
211
226
  lines.setElement(0, 2, `ERROR while applying (${source}) ${generator.toLabel()}`)
212
227
  lines.newRow()
@@ -220,7 +235,7 @@ class Generators {
220
235
  lines.setElement(0, 2, stack)
221
236
  lines.newRow()
222
237
  lines.setElement(0, 1, 'DEBUG')
223
- lines.setElement(0, 2, `To debug this use args.callId === '${args.calls.current()}'`)
238
+ lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
224
239
  lines.newRow()
225
240
  lines.setElement(0, 1, 'ERROR')
226
241
  lines.setElement(0, 2, errorMessage)
@@ -235,6 +250,7 @@ class Generators {
235
250
  const widths = Lines.addRemainder([10, 10])
236
251
  const lines = new Lines(widths)
237
252
  lines.setElement(0, 0, 'Generator')
253
+ lines.setElement(0, 1, `#${context.context_id || "?"}`)
238
254
  if (generator.index > -1 && generator.km) {
239
255
  // lines.setElement(0, 2, `KM '${generator.km}' ordinal: ${generator.index}`)
240
256
  lines.setElement(0, 2, generator.toLabel())
@@ -246,13 +262,13 @@ class Generators {
246
262
  lines.setElement(0, 2, generator.toString())
247
263
  lines.newRow()
248
264
  lines.setElement(0, 1, 'RESULT')
249
- lines.setElement(0, 2, generated)
265
+ lines.setElement(0, 2, generated + " " + pOrRTag)
250
266
  lines.newRow()
251
267
  lines.setElement(0, 1, 'STACK')
252
268
  lines.setElement(0, 2, stack)
253
269
  lines.newRow()
254
270
  lines.setElement(0, 1, 'DEBUG')
255
- lines.setElement(0, 2, `To debug this use args.callId === '${args.calls.current()}'`)
271
+ lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
256
272
  lines.newRow()
257
273
  lines.setElement(0, 1, 'TO')
258
274
  lines.setElement(0, 2, `context_id: ${context.context_id}`)
@@ -263,11 +279,15 @@ class Generators {
263
279
  break
264
280
  }
265
281
  }
282
+ for (const f of finallyList) {
283
+ await f()
284
+ }
266
285
  args.calls.pop()
267
286
  if (!applied && config.getDebug()) {
268
287
  const widths = Lines.addRemainder([10, 10])
269
288
  const lines = new Lines(widths)
270
289
  lines.setElement(0, 0, 'Generator')
290
+ lines.setElement(0, 1, `#${context.context_id || "?"}`)
271
291
  lines.setElement(0, 2, 'No generator applied')
272
292
  lines.newRow()
273
293
  lines.setElement(0, 1, 'STACK')
package/src/helpers.js CHANGED
@@ -1,6 +1,27 @@
1
1
  const deepEqual = require('deep-equal')
2
2
  const stringify = require('json-stable-stringify')
3
3
 
4
+
5
+ // check if member function of a class have been overriden by an subclass
6
+ class OverrideCheck {
7
+ constructor(base, suffix='API') {
8
+ this.base = base
9
+ this.checks = Object.getOwnPropertyNames(base.prototype).filter(key => typeof base.prototype[key] === 'function' && key.endsWith(suffix));
10
+ }
11
+
12
+ check(obj) {
13
+ const overriden = obj.constructor !== obj.baseAPI
14
+ if (!overriden) {
15
+ return
16
+ }
17
+ for (const check of this.checks) {
18
+ if (obj[check] == this.base.prototype[check]) {
19
+ throw new Error(`For ${obj.constructor.name} you need to override ${check}`)
20
+ }
21
+ }
22
+ }
23
+ }
24
+
4
25
  function pathEquals (p1, p2) {
5
26
  if (p1.length !== p2.length) {
6
27
  return false
@@ -523,52 +544,77 @@ const stableId = (tag) => {
523
544
  }
524
545
 
525
546
  function getByPath(obj, path, defaultValue) {
547
+ const segments = Array.isArray(path) ? path : [path];
548
+ const keys = segments.flatMap((segment) => {
549
+ if (typeof segment !== "string") return [segment];
550
+ return segment
551
+ .replace(/\[(\d+)\]/g, ".$1")
552
+ .split(".")
553
+ .filter((key) => key !== "");
554
+ });
555
+
526
556
  let current = obj;
527
- for (const key of path) {
557
+ for (const key of keys) {
528
558
  if (current === null || current === undefined) return defaultValue;
529
- if (typeof current !== 'object') return defaultValue;
559
+ if (typeof current !== "object") return defaultValue;
530
560
  current = current[key];
531
561
  }
532
562
  return current === undefined ? defaultValue : current;
533
563
  }
534
564
 
565
+ function normalizePath(path) {
566
+ const segments = Array.isArray(path) ? path : [path];
567
+ return segments.flatMap((segment) => {
568
+ if (typeof segment !== "string") return [segment];
569
+ return segment
570
+ .replace(/\[(\d+)\]/g, ".$1")
571
+ .split(".")
572
+ .filter((key) => key !== "");
573
+ });
574
+ }
575
+
576
+ function isArrayIndex(key) {
577
+ if (typeof key === "number") return Number.isInteger(key) && key >= 0;
578
+ return key !== "" && String(key >>> 0) === String(key);
579
+ }
580
+
535
581
  /**
536
- * Set a value in an object by path array.
582
+ * Set a value in an object by path (string or array).
537
583
  * Automatically creates missing objects {} or arrays [] as needed.
538
584
  *
539
585
  * @param {Object} obj - The root object to modify
540
- * @param {Array<string|number>} path - Array of keys/indices
586
+ * @param {string|Array<string|number>} path - Path keys/indices
541
587
  * @param {*} value - Value to set
542
588
  * @returns {*} The set value (for chaining)
543
589
  */
544
590
  function setByPath(obj, path, value) {
545
- if (!Array.isArray(path) || path.length === 0) {
546
- throw new Error('Path must be a non-empty array');
591
+ const keys = normalizePath(path);
592
+
593
+ if (keys.length === 0) {
594
+ throw new Error("Path must be a non-empty string or array");
595
+ }
596
+
597
+ if (obj == null || typeof obj !== "object") {
598
+ throw new Error("Target must be an object or array");
547
599
  }
548
600
 
549
601
  let current = obj;
550
602
 
551
- for (let i = 0; i < path.length; i++) {
552
- const key = path[i];
553
- const isLast = i === path.length - 1;
603
+ for (let i = 0; i < keys.length; i++) {
604
+ const key = keys[i];
605
+ const isLast = i === keys.length - 1;
554
606
 
555
607
  if (isLast) {
556
- // Final step — just assign
557
608
  current[key] = value;
558
609
  } else {
559
- // Not last — ensure next level exists
560
- const nextKey = path[i + 1];
561
-
562
- if (current[key] == null) {
563
- // Auto-create: array if next key is number, otherwise object
564
- current[key] = typeof nextKey === 'number' || String(nextKey >>> 0) === nextKey
565
- ? []
566
- : {};
567
- } else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
568
- // Safety: if current is array but next key isn't a valid index → convert to object
610
+ const nextKey = keys[i + 1];
611
+ const nextIsIndex = isArrayIndex(nextKey);
612
+
613
+ if (current[key] == null || typeof current[key] !== "object") {
614
+ current[key] = nextIsIndex ? [] : {};
615
+ } else if (Array.isArray(current[key]) && !nextIsIndex) {
569
616
  current[key] = { ...current[key] };
570
- } else if (!Array.isArray(current[key]) && typeof nextKey === 'number') {
571
- // If next expects array but current is object → convert
617
+ } else if (!Array.isArray(current[key]) && nextIsIndex) {
572
618
  current[key] = Object.values(current[key]);
573
619
  }
574
620
 
@@ -579,7 +625,64 @@ function setByPath(obj, path, value) {
579
625
  return value;
580
626
  }
581
627
 
628
+ const helpDebugHierarchy = 'In order to get a debug break when a specific hierarchy is created set the DEBUG_HIERARCHY environment variable to the JSON of the child-parent pair to break on. For example DEBUG_HIERARCHY=\'["cat", "mammel"]\''
629
+
630
+ // removeProp.js
631
+ function removeProp(obj, testFn, { maxDepth = Infinity, seen = new WeakSet() } = {}) {
632
+ if (!obj || typeof obj !== 'object' || maxDepth <= 0) return obj;
633
+ if (seen.has(obj)) return obj;
634
+ seen.add(obj);
635
+
636
+ if (Array.isArray(obj)) {
637
+ // ---- ARRAY: process each element (but don't remove elements unless testFn says so)
638
+ let writeIdx = 0;
639
+ for (let i = 0; i < obj.length; i++) {
640
+ const element = obj[i];
641
+ const shouldRemoveElement = testFn(element, i, obj);
642
+
643
+ if (shouldRemoveElement) {
644
+ // Remove the whole array element
645
+ if (element && typeof element === 'object') {
646
+ // Still walk inside it in case testFn wants side effects
647
+ removeProp(element, testFn, { maxDepth: maxDepth - 1, seen });
648
+ }
649
+ // Skip writing it back
650
+ } else {
651
+ // Keep element, but walk into it to remove inner props
652
+ removeProp(element, testFn, { maxDepth: maxDepth - 1, seen });
653
+ if (writeIdx !== i) {
654
+ obj[writeIdx] = element;
655
+ }
656
+ writeIdx++;
657
+ }
658
+ }
659
+ obj.length = writeIdx;
660
+ return obj;
661
+ }
662
+
663
+ // ---- OBJECT: iterate over own keys
664
+ const keys = Reflect.ownKeys(obj);
665
+ for (const key of keys) {
666
+ const val = obj[key];
667
+ const shouldRemove = testFn(val, key, obj);
668
+
669
+ if (shouldRemove) {
670
+ delete obj[key];
671
+ if (val && typeof val === 'object') {
672
+ removeProp(val, testFn, { maxDepth: maxDepth - 1, seen });
673
+ }
674
+ } else {
675
+ removeProp(val, testFn, { maxDepth: maxDepth - 1, seen });
676
+ }
677
+ }
678
+
679
+ return obj;
680
+ }
681
+
582
682
  module.exports = {
683
+ removeProp,
684
+ helpDebugHierarchy,
685
+
583
686
  stableId,
584
687
  ecatch,
585
688
  functionsToStrings,
@@ -611,4 +714,5 @@ module.exports = {
611
714
  assignAssumed,
612
715
  watchProperty,
613
716
  pathEquals,
717
+ OverrideCheck,
614
718
  }
package/src/project2.js CHANGED
@@ -101,6 +101,10 @@ function project(source, filters, path=[]) {
101
101
  } else if (prop.property && source.hasOwnProperty(prop.property)) {
102
102
  // If the property is an object and not null, recursively project it
103
103
  if (typeof source[prop.property] === 'object' && source[prop.property] !== null) {
104
+ if (prop.all) {
105
+ result[prop.property] = source[prop.property]
106
+ return
107
+ }
104
108
  result[prop.property] = {}
105
109
  const instantiatedCheck = []
106
110
  for (const check of prop.check) {