theprogrammablemind 9.7.1-beta.9 → 9.8.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/client.js CHANGED
@@ -167,10 +167,12 @@ const writeTest = (fn, query, objects, generated, paraphrases, responses, contex
167
167
  if (runtime.fs.existsSync(fn)) {
168
168
  tests = JSON.parse(runtime.fs.readFileSync(fn))
169
169
  }
170
+ /*
170
171
  for (const association of associations) {
171
172
  association.sort()
172
173
  }
173
174
  associations.sort()
175
+ */
174
176
  // tests[query] = sortJson({ paraphrases, responses, contexts, objects: convertToStable(objects), associations, metadata, config, developerTest: saveDeveloper }, { depth: 25 })
175
177
  const results = sortJson({
176
178
  query,
@@ -265,7 +267,7 @@ const throwErrorHandler = (error) => {
265
267
  throw error
266
268
  }
267
269
 
268
- const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isProcess, isModule, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = throwErrorHandler } = {}) => {
270
+ const _process = async (config, query, { queryNumber, initializer, commandLineArgs, credentials, writeTests, logs, isProcess, isModule, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = throwErrorHandler } = {}) => {
269
271
  if (credentials) {
270
272
  config.server(credentials.server, credentials.key)
271
273
  }
@@ -296,11 +298,12 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
296
298
  // '\\n' from tests of '\n' from users. the former is because newline is not a valid json character so the testfile has it encoded
297
299
  let queries = query.split(/\\n|\n/)
298
300
  const summaries = [] // for error
301
+ logs = logs || []
299
302
  try {
300
303
  const response = {
301
304
  hierarchy: [],
302
305
  load_cache_time: 0.0,
303
- logs: [],
306
+ logs: logs,
304
307
  metadata: {
305
308
  opChoices: []
306
309
  },
@@ -334,6 +337,9 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
334
337
  data.utterance = queries[0]
335
338
  data.start_counter = startCounter
336
339
  let json = await doWithRetries(retries, url, queryParams, data)
340
+ if (json.logs) {
341
+ logs.push(...json.logs)
342
+ }
337
343
  let resetData = false
338
344
  if (json.code === 'NOT_IN_CACHE') {
339
345
  resetData = true
@@ -367,28 +373,26 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
367
373
  const summary = { summaries: json.summaries, length: json.contexts.length }
368
374
  summaries.push(summary)
369
375
  const { updatedContextIdCounter, contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
370
- await processContextsB({ contextIdCounter, calls, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
376
+ await processContextsB({ contextIdCounter, logs, calls, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
371
377
  contextIdCounter = updatedContextIdCounter
372
378
  if (isTest) {
373
379
  const end = runtime.performance.performance.now()
374
380
  clientSideTime = end - start
375
381
  }
376
- response.associations = json.associations
382
+ // response.associations = json.associations
377
383
  response.learned_contextual_priorities = json.learned_contextual_priorities
378
384
  response.hierarchy = json.hierarchy
379
385
  response.load_cache_time += json.load_cache_time
380
- appendNoDups(response.logs, json.logs)
381
386
  response.memory_free_percent = json.memory_free_percent
382
- // appendNoDups(response.metadata.associations, json.metadata.associations)
383
- // appendNoDups(response.metadata.priorities, json.metadata.priorities)
384
387
  appendNoDups(response.metadata.opChoices, json.metadata.opChoices)
385
388
  response.times += json.times
386
389
  response.clientSideTimes += clientSideTime
387
390
  response.trace = response.trace.concat(json.trace)
388
391
  response.version = json.version
389
392
  response.explain_priorities = json.explain_priorities
393
+ response.explain_associations = json.explain_associations
390
394
  response.contextual_priorities_ambiguities = json.contextual_priorities_ambiguities
391
- response.rtf_associations = json.rtf_associations
395
+ // response.rtf_associations = json.rtf_associations
392
396
 
393
397
  response.contexts = response.contexts.concat(contextsPrime)
394
398
  response.generated = response.generated.concat(generatedPrime)
@@ -414,6 +418,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
414
418
  return response
415
419
  } catch (error) {
416
420
  error.summaries = summaries
421
+ error.queryNumber = queryNumber
417
422
  error.query = query
418
423
  errorHandler(error)
419
424
  }
@@ -506,7 +511,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
506
511
  setupArgs(args, config)
507
512
  await testConfig.initializer(args)
508
513
  }
509
- const result = await _process(config, test, { errorHandler, isTest: true, isProcess: true, isModule: false })
514
+ const result = await _process(config, test, { queryNumber: args.queryNumber, errorHandler, isTest: true, isProcess: true, isModule: false })
510
515
  result.query = test
511
516
  if (debug) {
512
517
  defaultInnerProcess(config, errorHandler, result)
@@ -626,6 +631,7 @@ const runTestsHelper = async (config, tests, failed, juicyBits) => {
626
631
  }
627
632
  const test = tests.shift()
628
633
  juicyBits.index = index
634
+ juicyBits.args.queryNumber = index
629
635
  const result = await runTest(config, test, juicyBits)
630
636
  if (result != null) {
631
637
  result.index = index
@@ -683,13 +689,6 @@ const saveTests = (config, testFile, testConfig) => {
683
689
  return saveTestsHelper(testFile, config, tests, tests.map((test) => test.query), testConfig)
684
690
  }
685
691
 
686
- /*
687
- const showExamples = (testFile) => {
688
- const tests = JSON.parse(fs.readFileSync(testFile))
689
- Object.keys(tests).forEach((test) => console.log(test))
690
- }
691
- */
692
-
693
692
  const showInfo = (description, section, config) => {
694
693
  console.log(JSON.stringify(config.getInfo(), null, 2))
695
694
  }
@@ -803,7 +802,7 @@ const defaultErrorHandler = async (error) => {
803
802
  }
804
803
 
805
804
  if (error.query) {
806
- console.log('query: ', error.query)
805
+ console.log(`query: #${error.queryNumber} ${error.query}`)
807
806
  doErrorExit = true
808
807
  }
809
808
 
@@ -895,6 +894,11 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
895
894
  console.log(` inputs: ${JSON.stringify(inputs)} output: ${JSON.stringify(output)} reason: ${reason}`)
896
895
  }
897
896
  }
897
+
898
+ if (responses.explain_associations) {
899
+ console.log(responses.explain_associations)
900
+ }
901
+
898
902
  // const objects = config.get('objects').namespaced[config.uuid]
899
903
  const actualGetObjects = (name) => {
900
904
  if (!name) {
@@ -1071,7 +1075,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
1071
1075
  config.fragmentsBeingBuilt.push({ query: query.query, contexts: results.contexts })
1072
1076
  }
1073
1077
  accumulators.summaries = accumulators.summaries.concat(results.summaries)
1074
- accumulators.associations = accumulators.associations.concat(results.associations)
1078
+ // accumulators.associations = accumulators.associations.concat(results.associations)
1075
1079
  accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
1076
1080
  await looper(configs)
1077
1081
  } catch (e) {
@@ -1107,7 +1111,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
1107
1111
  await looper([])
1108
1112
  } else {
1109
1113
  try {
1110
- config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true })
1114
+ config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true, addFirst: true })
1111
1115
  } catch (e) {
1112
1116
  const where = extraConfig.where ? ` ${extraConfig.where}` : ''
1113
1117
  throw new Error(`Error processing extra config${where}: ${e.stack}}`)
@@ -1129,7 +1133,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
1129
1133
  associations.sort()
1130
1134
  }
1131
1135
  const stabilizeOutput = (template) => {
1132
- stabilizeAssociations(template.associations)
1136
+ // stabilizeAssociations(template.associations)
1133
1137
  const stabilize = (results) => {
1134
1138
  for (let i = 0; i < results.length; ++i) {
1135
1139
  const result = results[i]
@@ -1143,8 +1147,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
1143
1147
  delete result.memory_free_percent
1144
1148
  delete result.logs
1145
1149
  delete result.version
1146
- result.hierarchy.sort()
1147
- stabilizeAssociations(result.associations)
1150
+ // stabilizeAssociations(result.associations)
1148
1151
  result.learned_contextual_priorities = safeNoDups(result.learned_contextual_priorities)
1149
1152
  }
1150
1153
  }
@@ -1341,6 +1344,7 @@ const knowledgeModuleImpl = async ({
1341
1344
  parser.add_argument('-cl', '--checkForLoop', { nargs: '?', help: 'Check for loops in the priorities, Optional argument is list of operator keys to consider. For example [["banana", 0], ["food", 1]]' })
1342
1345
  parser.add_argument('-r', '--reset', { action: 'store_true', help: 'Get the server to bypass the cache and rebuild everything' })
1343
1346
  parser.add_argument('-q', '--query', { help: 'Run the specified query' })
1347
+ parser.add_argument('-qn', '--queryNumber', { help: 'Run the query specified by the given index' })
1344
1348
  parser.add_argument('-f', '--filter', { help: 'for -pd only the data for the knowledge modules that start with this string will be shown' })
1345
1349
  parser.add_argument('-ip ', '--server', { help: 'Server to run against' })
1346
1350
  parser.add_argument('--trace', { action: 'store_true', help: 'Trace the semantics and generator calls.' })
@@ -1380,6 +1384,7 @@ const knowledgeModuleImpl = async ({
1380
1384
  parser.add_argument('-dcp', '--debugContextualPriority', { action: 'store_true', help: helpDebugContextualPriority })
1381
1385
  parser.add_argument('-db', '--debugBridge', { action: 'store_true', help: helpDebugBridge })
1382
1386
  parser.add_argument('-do', '--debugOperator', { action: 'store_true', help: helpDebugOperator })
1387
+ parser.add_argument('-ea', '--explainAssociations', { action: 'store_true', help: 'The server will return information about the associations used to decide on the interpretation.' })
1383
1388
  parser.add_argument('-ep', '--explainPriorities', { action: 'store_true', help: 'The server will return all priorities including the generated one along with an explanation of there they came from' })
1384
1389
  parser.add_argument('-dic', '--debugIncludeConvolutions', { nargs: '?', help: 'When running with the --debugIncludeConvolutions flag the logs will include convolutions which are somewhat annoyingly verbose. Default is false' })
1385
1390
  parser.add_argument('-bc', '--bypassCache', { action: 'store_true', help: 'Bypass the cache on the server side and rebuild' })
@@ -1387,6 +1392,10 @@ const knowledgeModuleImpl = async ({
1387
1392
  const args = parser.parse_args()
1388
1393
  args.count = args.count || 1
1389
1394
 
1395
+ if (args.queryNumber) {
1396
+ args.query = test.contents[args.queryNumber].query
1397
+ }
1398
+
1390
1399
  if (args.rebuildTemplateFull) {
1391
1400
  args.rebuildTemplate = true
1392
1401
  }
@@ -1480,9 +1489,10 @@ const knowledgeModuleImpl = async ({
1480
1489
 
1481
1490
  if (args.deleteTest) {
1482
1491
  let tests = JSON.parse(runtime.fs.readFileSync(testConfig.name))
1492
+ const nTests = tests.length
1483
1493
  tests = tests.filter((test) => test.query !== args.deleteTest)
1484
1494
  writeTestFile(testConfig.name, tests)
1485
- console.log(`Delete the test for "${args.deleteTest}"`)
1495
+ console.log(`Deleted ${nTests - tests.length} tests for "${args.deleteTest}"`)
1486
1496
  return
1487
1497
  }
1488
1498
 
@@ -1513,6 +1523,10 @@ const knowledgeModuleImpl = async ({
1513
1523
  config.config.explain_priorities = true
1514
1524
  }
1515
1525
 
1526
+ if (args.explainAssociations) {
1527
+ config.config.explain_associations = true
1528
+ }
1529
+
1516
1530
  config.config.debugIncludeConvolutions = args.debugIncludeConvolutions || process.argv.includes('--debugIncludeConvolutions') || process.argv.includes('-dic')
1517
1531
 
1518
1532
  let configPrinted = false
@@ -1532,7 +1546,7 @@ const knowledgeModuleImpl = async ({
1532
1546
  console.log('Test queries')
1533
1547
  let counter = 0
1534
1548
  for (const test of config.tests) {
1535
- console.log(`${counter} - ${test.query}`)
1549
+ console.log(`#${counter} - ${test.query}`)
1536
1550
  counter += 1
1537
1551
  }
1538
1552
  }
@@ -1545,7 +1559,10 @@ const knowledgeModuleImpl = async ({
1545
1559
  if (hasArg('c')) {
1546
1560
  const { data } = setupProcessB({ config })
1547
1561
  console.log('Config as sent to server')
1548
- console.log(JSON.stringify(data, null, 2))
1562
+ const toPrint = { ...data }
1563
+ toPrint['priorities'] = toPrint['priorities'].map((value) => JSON.stringify(value).replace(/\\"/g, '"'))
1564
+ toPrint['associations']['positive'] = toPrint['associations']['positive'].map((value) => JSON.stringify(value).replace(/\\"/g, '"'))
1565
+ console.log(JSON.stringify(toPrint, null, 2).replace(/\\"/g, '"'))
1549
1566
  }
1550
1567
  if (hasArg('l')) {
1551
1568
  console.log('Module load ordering')
@@ -1639,12 +1656,7 @@ const knowledgeModuleImpl = async ({
1639
1656
  }
1640
1657
 
1641
1658
  if (hasArg('s')) {
1642
- const easyToRead = _.cloneDeep(config.config.semantics)
1643
- for (const semantic of easyToRead) {
1644
- semantic.match = semantic.match.toString()
1645
- semantic.apply = semantic.apply.toString()
1646
- }
1647
- console.dir(easyToRead)
1659
+ config.printSemantics()
1648
1660
  }
1649
1661
  }
1650
1662
  }
@@ -1761,7 +1773,7 @@ const knowledgeModuleImpl = async ({
1761
1773
  if (hasError) {
1762
1774
  console.log('**************************** ERRORS ************************')
1763
1775
  for (const result of results) {
1764
- console.log('Utterance: ', result.utterance)
1776
+ console.log(`Utterance: #${result.index} ${result.utterance}`)
1765
1777
  if (!result.hasError) {
1766
1778
  continue
1767
1779
  }
@@ -1777,7 +1789,7 @@ const knowledgeModuleImpl = async ({
1777
1789
  newError = true
1778
1790
  headerShown = true
1779
1791
  if (args.vimdiff) {
1780
- vimdiff(actual, expected, `"${label} - ${result.index} ${result.utterance}"`)
1792
+ vimdiff(actual, expected, `"${label} - #${result.index} ${result.utterance}"`)
1781
1793
  }
1782
1794
  result.hasError = true
1783
1795
  }
@@ -1920,12 +1932,17 @@ const knowledgeModuleImpl = async ({
1920
1932
  console.log('use -v arg to write files expected.json and actual.json in the current directory for detailed comparison. Or do -s and then git diff the changes.')
1921
1933
  // console.log(JSON.stringify(contexts))
1922
1934
  let errorCount = 0
1935
+ const failedTests = []
1923
1936
  for (const result of results) {
1924
1937
  if (result.hasError) {
1925
- console.log(`FAILED ${result.utterance}`)
1938
+ console.log(`FAILED #${result.index} ${result.utterance}`)
1939
+ failedTests.push({ index: result.index, utterance: result.utterance })
1926
1940
  errorCount += 1
1927
1941
  }
1928
1942
  }
1943
+ const failedFile = './FAILED.json'
1944
+ console.log(`Failed tests are written to ${failedFile}`)
1945
+ runtime.fs.writeFileSync(failedFile, JSON.stringify(failedTests, 0, 2))
1929
1946
  console.log(`**************************** THERE WERE ${errorCount} TEST FAILURES ************************`)
1930
1947
  }
1931
1948
  }
@@ -1984,7 +2001,7 @@ const knowledgeModuleImpl = async ({
1984
2001
  global.beforeObjects = _.cloneDeep(objects)
1985
2002
  }
1986
2003
  try {
1987
- await processResults(_process(config, args.query, { commandLineArgs: args, isProcess, isModule: !isProcess, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
2004
+ await processResults(_process(config, args.query, { commandLineArgs: args, isProcess, logs: [], isModule: !isProcess, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
1988
2005
  } catch (error) {
1989
2006
  printConfig()
1990
2007
  console.log('Error', error)
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const { Semantics, Semantic } = require('./src/semantics')
2
2
  const { Generators, Generator } = require('./src/generators')
3
3
  const { Config } = require('./src/config')
4
- const { w, where, OverrideCheck } = require('./src/helpers')
4
+ const { w, where, OverrideCheck, setByPath, getByPath } = require('./src/helpers')
5
5
  const Digraph = require('./src/digraph')
6
6
  const client = require('./client')
7
7
  const flattens = require('./src/flatten')
@@ -16,6 +16,8 @@ module.exports = {
16
16
  runTests: client.runTests,
17
17
  knowledgeModule: client.knowledgeModule,
18
18
  ensureTestFile: client.ensureTestFile,
19
+ setByPath,
20
+ getByPath,
19
21
  where,
20
22
  stableId: client.stableId,
21
23
  w,
package/package.json CHANGED
@@ -73,6 +73,6 @@
73
73
  "scriptjs": "^2.5.9",
74
74
  "uuid": "^8.3.2"
75
75
  },
76
- "version": "9.7.1-beta.9",
76
+ "version": "9.8.0",
77
77
  "license": "UNLICENSED"
78
78
  }
package/src/config.js CHANGED
@@ -563,7 +563,7 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
563
563
  'generatorr',
564
564
  'generators',
565
565
  'id',
566
- 'init',
566
+ 'initial',
567
567
  'inverted',
568
568
  'isA',
569
569
  'level',
@@ -981,6 +981,15 @@ class Config {
981
981
  return config_toServer(config)
982
982
  }
983
983
 
984
+ printSemantics() {
985
+ const easyToRead = _.cloneDeep(this.config.semantics)
986
+ for (const semantic of easyToRead) {
987
+ semantic.match = semantic.match.toString()
988
+ semantic.apply = semantic.apply.toString()
989
+ }
990
+ console.dir(easyToRead)
991
+ }
992
+
984
993
  async run(handler) {
985
994
  return configHelpers.run(this, handler)
986
995
  }
@@ -1291,6 +1300,8 @@ class Config {
1291
1300
  } else {
1292
1301
  return fi
1293
1302
  }
1303
+ } else {
1304
+ throw new Error(`The fragment for '${query} was not found.`)
1294
1305
  }
1295
1306
  }
1296
1307
 
@@ -1681,6 +1692,7 @@ class Config {
1681
1692
  return
1682
1693
  }
1683
1694
  }
1695
+
1684
1696
  if (global.transitoryMode) {
1685
1697
  def.transitoryMode = true
1686
1698
  }
@@ -3382,6 +3394,10 @@ class Config {
3382
3394
  let duplicated = new Set()
3383
3395
  const seen = new Set()
3384
3396
  for (const bridge of this.config.bridges) {
3397
+ if (typeof bridge.id !== 'string') {
3398
+ throw new Error('Config.addBridge: expected the bridge id to be a non-empty string.')
3399
+ }
3400
+
3385
3401
  const id = `${bridge.id}/${bridge.level} (namespace: ${bridge.uuid || this.uuid})`
3386
3402
  if (seen.has(id)) {
3387
3403
  duplicated.add(id)
@@ -165,10 +165,14 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
165
165
  }
166
166
  args.contextHierarchy = new ContextHierarchy()
167
167
  args.namespaced = {
168
- get: (km, context, property) => {
168
+ get: (km, context, property, _default) => {
169
169
  context.namespaced ??= {}
170
170
  context.namespaced[km] ??= {}
171
- return context.namespaced[km][property]
171
+ const value = context.namespaced[km][property]
172
+ if (value == undefined) {
173
+ return _default
174
+ }
175
+ return value
172
176
  },
173
177
  set: (km, context, property, value) => {
174
178
  context.namespaced ??= {}
@@ -345,9 +349,11 @@ const processContext = async (context, { objects = {}, config, logs = [] }) => {
345
349
  const setupProcessB = ({ config, initializer, allowDelta = false, rebuildingTemplate = false } = {}) => {
346
350
  const key = config._key
347
351
  const data = Object.assign({ key, version: '3' }, { uuid: config._uuid })
352
+ /*
348
353
  if (rebuildingTemplate) {
349
354
  data.return_rtf_associations = true
350
355
  }
356
+ */
351
357
  if (allowDelta && config.allowDelta && config.hasDelta()) {
352
358
  // console.log('config', config)
353
359
  data.delta = config.delta()
@@ -405,7 +411,7 @@ const setupContexts = (rawContexts) => {
405
411
  return contexts
406
412
  }
407
413
 
408
- const processContextsB = async ({ config, calls, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
414
+ const processContextsB = async ({ config, calls, hierarchy, logs, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
409
415
  // TODO fix this name to contextsPrime
410
416
  const contextsPrime = []
411
417
  const generatedPrime = []
@@ -417,10 +423,7 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
417
423
 
418
424
  const objects = config.get('objects')
419
425
  const args = { objects, isResponse: true, response: json, isTest, isInstance, getObjects: getObjects(objects), instance, contexts, isProcess, isModule, calls }
420
- if (!json.logs) {
421
- json.logs = []
422
- }
423
- setupArgs(args, config, json.logs, hierarchy)
426
+ setupArgs(args, config, logs, hierarchy)
424
427
  const toDo = [...contexts]
425
428
  args.insert = (context) => toDo.unshift(context)
426
429
  let overlap, lastRange
@@ -438,7 +441,7 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
438
441
  }
439
442
  const generateParenthesized = isTest || (commandLineArgs && commandLineArgs.save)
440
443
  if (!config.get('skipSemantics')) {
441
- const semantics = config.getSemantics(json.logs)
444
+ const semantics = config.getSemantics(logs)
442
445
  try {
443
446
  contextPrime = await semantics.apply(args, context)
444
447
  // contextPrime.greg = 'yes'
@@ -481,11 +484,11 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
481
484
  // noop
482
485
  } else {
483
486
  let assumed = { isResponse: true }
484
- const generated = contextPrime.isResponse ? await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
487
+ const generated = contextPrime.isResponse ? await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
485
488
  let generatedParenthesized = []
486
489
  if (generateParenthesized) {
487
490
  config.setParenthesized(true)
488
- generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
491
+ generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
489
492
  config.setParenthesized(false)
490
493
  }
491
494
  // assumed = { paraphrase: true, response: false };
@@ -493,11 +496,11 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
493
496
  if (generateParenthesized) {
494
497
  config.setParenthesized(false)
495
498
  }
496
- const paraphrases = await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed)
499
+ const paraphrases = await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed)
497
500
  let paraphrasesParenthesized = []
498
501
  if (generateParenthesized) {
499
502
  config.setParenthesized(true)
500
- paraphrasesParenthesized = await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed)
503
+ paraphrasesParenthesized = await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed)
501
504
  config.setParenthesized(false)
502
505
  }
503
506
  contextsPrime.push(contextPrime)
@@ -526,9 +529,9 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
526
529
  }
527
530
  e.context = contextPrime
528
531
  if (e.logs) {
529
- e.logs = e.logs.concat(json.logs)
532
+ e.logs = e.logs.concat(logs)
530
533
  } else {
531
- e.logs = json.logs
534
+ e.logs = logs
532
535
  }
533
536
  e.metadata = json.metadata
534
537
  if (json.trace) {
@@ -545,10 +548,12 @@ const loadInstance = async (config, instance) => {
545
548
  const transitoryMode = global.transitoryMode
546
549
  global.transitoryMode = false
547
550
 
551
+ /*
548
552
  const rl = instance.resultss.length
549
553
  if (rl > 0) {
550
554
  config.addAssociations(instance.resultss[instance.resultss.length - 1].rtf_associations || [])
551
555
  }
556
+ */
552
557
  /*
553
558
  TODO needs updating if still wanted
554
559
  if (instance && (instance.associations || instance.learned_contextual_priorities)) {
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
@@ -76,6 +76,9 @@ const flatten = (markers, value) => {
76
76
  if (value.flatten === false) {
77
77
  return [[value], false]
78
78
  }
79
+
80
+ const flatten_ignore = value.flatten_ignore || []
81
+
79
82
  const marker = value.marker
80
83
  let properties = value
81
84
 
@@ -105,8 +108,9 @@ const flatten = (markers, value) => {
105
108
  for (const key in properties) {
106
109
  let wf = false
107
110
  let values
108
- // if isinstance(properties[key], Context) {
109
- if (isObject(properties[key])) {
111
+ if (flatten_ignore.includes(key)) {
112
+ values = [properties[key]]
113
+ } else if (isObject(properties[key])) {
110
114
  const context = properties[key];
111
115
  [values, wf] = flatten(markers, context)
112
116
  // } else if (isinstance(properties[key], list)) {
package/src/generators.js CHANGED
@@ -125,11 +125,10 @@ class Generator {
125
125
  args.g = args.gp
126
126
  }
127
127
  return await debug.hitScoped(args.callId, async () => {
128
- if ((options.debug || {}).apply ||
129
- callId === this.callId) {
128
+ if ((options.debug || {}).apply || process.env.DEBUG_CALLID == args.callId || callId === this.callId) {
130
129
  debugger // eslint-disable-line no-debugger
131
130
  }
132
- return await this._apply(args)
131
+ return await this._apply(args) // DEBUG: This is the line you want to step into
133
132
  })
134
133
  }
135
134
  }
@@ -191,6 +190,13 @@ class Generators {
191
190
  const log = (message) => { this.logs.push(message) }
192
191
  // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
193
192
  let errorMessage = 'The apply function did not return a value'
193
+ if (process.env.TPMKMS_TRACE) {
194
+ console.error("TPMKMS_TRACE", debug.counter("TPMKMS_TRACE"))
195
+ console.error(generator.toLabel())
196
+ console.error(generator.toString())
197
+ console.log(`To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
198
+ }
199
+
194
200
  try {
195
201
  generated = await generator.apply(args, objects, context, hierarchy, config, response, log, options)
196
202
  } catch (e) {
@@ -225,7 +231,7 @@ class Generators {
225
231
  lines.setElement(0, 2, stack)
226
232
  lines.newRow()
227
233
  lines.setElement(0, 1, 'DEBUG')
228
- lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
234
+ lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
229
235
  lines.newRow()
230
236
  lines.setElement(0, 1, 'ERROR')
231
237
  lines.setElement(0, 2, errorMessage)
package/src/helpers.js CHANGED
@@ -544,52 +544,77 @@ const stableId = (tag) => {
544
544
  }
545
545
 
546
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
+
547
556
  let current = obj;
548
- for (const key of path) {
557
+ for (const key of keys) {
549
558
  if (current === null || current === undefined) return defaultValue;
550
- if (typeof current !== 'object') return defaultValue;
559
+ if (typeof current !== "object") return defaultValue;
551
560
  current = current[key];
552
561
  }
553
562
  return current === undefined ? defaultValue : current;
554
563
  }
555
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
+
556
581
  /**
557
- * Set a value in an object by path array.
582
+ * Set a value in an object by path (string or array).
558
583
  * Automatically creates missing objects {} or arrays [] as needed.
559
584
  *
560
585
  * @param {Object} obj - The root object to modify
561
- * @param {Array<string|number>} path - Array of keys/indices
586
+ * @param {string|Array<string|number>} path - Path keys/indices
562
587
  * @param {*} value - Value to set
563
588
  * @returns {*} The set value (for chaining)
564
589
  */
565
590
  function setByPath(obj, path, value) {
566
- if (!Array.isArray(path) || path.length === 0) {
567
- 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");
568
599
  }
569
600
 
570
601
  let current = obj;
571
602
 
572
- for (let i = 0; i < path.length; i++) {
573
- const key = path[i];
574
- 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;
575
606
 
576
607
  if (isLast) {
577
- // Final step — just assign
578
608
  current[key] = value;
579
609
  } else {
580
- // Not last ensure next level exists
581
- const nextKey = path[i + 1];
582
-
583
- if (current[key] == null) {
584
- // Auto-create: array if next key is number, otherwise object
585
- current[key] = typeof nextKey === 'number' || String(nextKey >>> 0) === nextKey
586
- ? []
587
- : {};
588
- } else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
589
- // 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) {
590
616
  current[key] = { ...current[key] };
591
- } else if (!Array.isArray(current[key]) && typeof nextKey === 'number') {
592
- // If next expects array but current is object → convert
617
+ } else if (!Array.isArray(current[key]) && nextIsIndex) {
593
618
  current[key] = Object.values(current[key]);
594
619
  }
595
620
 
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) {
package/src/semantics.js CHANGED
@@ -77,10 +77,11 @@ class Semantic {
77
77
  this.fixUpArgs(args, context)
78
78
  return await debug.hitScoped(args.callId, async () => {
79
79
  const matches = await this.matcher(args)
80
- if (matches && (options.debug || {}).match || args.callId === this.callId) {
81
- // next line is the matcher
82
- debugger // eslint-disable-line no-debugger
83
- await this.matcher(args)
80
+ if (matches) {
81
+ if ((options.debug || {}).match || args.callId === this.callId || process.env.DEBUG_CALLID == args.callId) {
82
+ debugger // eslint-disable-line no-debugger
83
+ await this.matcher(args) // DEBUG: This is the line you step into
84
+ }
84
85
  }
85
86
  return matches
86
87
  })
@@ -100,8 +101,8 @@ class Semantic {
100
101
  this.fixUpArgs(args, contextPrime)
101
102
 
102
103
  return await debug.hitScoped(args.callId, async () => {
103
- if ((options.debug || {}).apply || args.callId === this.callId) {
104
- debugger // eslint-disable-line no-debugger
104
+ if ((options.debug || {}).apply || args.callId === this.callId || process.env.DEBUG_CALLID == args.callId) {
105
+ debugger // eslint-disable-line no-debugger // STEP ABOUT THREE TIMES TO THE DEBUG LINE
105
106
  }
106
107
  if (args.breakOnSemantics) {
107
108
  debugger // eslint-disable-line no-debugger
@@ -109,7 +110,7 @@ class Semantic {
109
110
 
110
111
  try {
111
112
  args.stack.push(this)
112
- await this._apply(args)
113
+ await this._apply(args) // DEBUG: This is the line you want to step into
113
114
  args.stack.pop()
114
115
  } catch( e ) {
115
116
  args.stack.pop()
@@ -192,6 +193,8 @@ class Semantics {
192
193
  let seenQuestion = false
193
194
  const deferred = []
194
195
  args.log = (message) => { this.logs.push(message) }
196
+ const finallyList = []; // called after the semantic is processed
197
+ args._finally = (call) => finallyList.unshift(call)
195
198
  for (const isemantic in this.semantics) {
196
199
  const semantic = this.semantics[isemantic]
197
200
  // only one question at a time
@@ -258,7 +261,7 @@ class Semantics {
258
261
  lines.setElement(0, 2, semantic.toString())
259
262
  lines.newRow()
260
263
  lines.setElement(0, 1, 'DEBUG')
261
- lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
264
+ lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') in the code or DEBUG_CALLID="${args.calls.current()}"`)
262
265
  lines.newRow()
263
266
  lines.setElement(0, 1, 'TO')
264
267
  lines.setElement(0, 2, `context_id: ${context.context_id}`)
@@ -293,7 +296,7 @@ class Semantics {
293
296
  lines.setElement(0, 2, semantic.toString())
294
297
  lines.newRow()
295
298
  lines.setElement(0, 1, 'DEBUG')
296
- lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
299
+ lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') in the code or DEBUG_CALLID="${args.calls.current()}"`)
297
300
  lines.newRow()
298
301
  lines.setElement(0, 1, 'TO')
299
302
  lines.setElement(0, 2, `context_id: ${context.context_id}`)
@@ -324,6 +327,9 @@ class Semantics {
324
327
  }
325
328
  counter += 1
326
329
  }
330
+ for (const f of finallyList) {
331
+ await f()
332
+ }
327
333
  args.calls.pop()
328
334
  if (!applied && debug) {
329
335
  const widths = Lines.addRemainder([10, 10])