theprogrammablemind 7.5.8-beta.8 → 7.5.8-beta.80

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
@@ -2,6 +2,7 @@ const { Semantics, Semantic } = require('./src/semantics')
2
2
  const { Generators, Generator } = require('./src/generators')
3
3
  const DigraphInternal = require('./src/digraph_internal')
4
4
  const Digraph = require('./src/digraph')
5
+ const { project } = require('./src/project')
5
6
  const fetch = require('node-fetch')
6
7
  const base64 = require('base-64')
7
8
  const deepEqual = require('deep-equal')
@@ -9,20 +10,38 @@ const _ = require('lodash')
9
10
  const stringify = require('json-stable-stringify')
10
11
  const Lines = require('./lines')
11
12
  const flattens = require('./src/flatten')
12
- const { appendNoDups, InitCalls, updateQueries } = require('./src/helpers')
13
+ const { appendNoDups, InitCalls, updateQueries, safeNoDups } = require('./src/helpers')
13
14
  const runtime = require('./runtime')
14
15
  const sortJson = runtime.sortJson
15
16
 
17
+ const getConfig_getObjectsCheck = (testConfig) => {
18
+ return (testConfig.checks && testConfig.checks.objects) || []
19
+ }
20
+
21
+ const getConfig_getContextCheck = (testConfig) => {
22
+ return (testConfig.checks && testConfig.checks.context) || []
23
+ }
24
+
25
+ const pickContext = (testConfig) => (context) => {
26
+ return project(context, getConfig_getContextCheck(testConfig))
27
+ }
28
+
29
+ const pickObjects = (testConfig, objects) => {
30
+ return project(objects, getConfig_getObjectsCheck(testConfig))
31
+ }
32
+
16
33
  const getAsk = (config) => (uuid) => (asks) => {
17
34
  for (let ask of asks) {
18
- config.addMotivation({
35
+ config.addSemantic({
19
36
  uuid,
37
+ oneShot: true,
20
38
  match: (args) => ask.matchr(args),
21
39
  apply: (args) => ask.applyr(args)
22
40
  })
23
41
  }
24
- config.addMotivation({
42
+ config.addSemantic({
25
43
  uuid,
44
+ oneShot: true,
26
45
  match: ({context}) => context.marker == 'controlEnd' || context.marker == 'controlBetween',
27
46
  apply: (args) => {
28
47
  for (let ask of asks) {
@@ -37,7 +56,7 @@ const getAsk = (config) => (uuid) => (asks) => {
37
56
  }
38
57
  }
39
58
  if (matchq(args)) {
40
- args.context.motivationKeep = true
59
+ // args.context.motivationKeep = true
41
60
  args.context.verbatim = applyq(args)
42
61
  args.context.isResponse = true;
43
62
  delete args.context.controlRemove;
@@ -49,6 +68,12 @@ const getAsk = (config) => (uuid) => (asks) => {
49
68
  })
50
69
  }
51
70
 
71
+ const sameJSON = (json1, json2) => {
72
+ const sjson1 = sortJson(json1, { depth: 25 })
73
+ const sjson2 = sortJson(json2, { depth: 25 })
74
+ return JSON.stringify(sjson1) == JSON.stringify(sjson2)
75
+ }
76
+
52
77
  const vimdiff = (actualJSON, expectedJSON) => {
53
78
  const path = '.'
54
79
  const actual = sortJson(actualJSON, { depth: 25 })
@@ -58,7 +83,6 @@ const vimdiff = (actualJSON, expectedJSON) => {
58
83
  // console.log(`vimdiff ${path}/actual.json ${path}/expected.json`)
59
84
  {
60
85
  const editor = runtime.process.env.EDITOR || 'vimdiff'
61
- debugger
62
86
  // const child = runtime.child_process.spawn(editor, [`${path}/expected.json`, `${path}/actual.json`], { stdio: 'inherit' })
63
87
  console.log(`${editor} ${path}/expected.json ${path}/actual.json`)
64
88
  runtime.child_process.execSync(`${editor} ${path}/expected.json ${path}/actual.json`, {stdio: 'inherit'})
@@ -109,11 +133,12 @@ class ErrorReason extends Error {
109
133
 
110
134
  const setupArgs = (args, config, logs, hierarchy) => {
111
135
  config.setArgs(args)
112
- args.calls = new InitCalls(config.name)
136
+ args.calls = new InitCalls(args.isInstance ? `${args.isInstance}#${config.name}` : config.name)
113
137
  if (global.theprogrammablemind && global.theprogrammablemind.loadForTesting) {
114
138
  args.calls = new InitCalls(Object.keys(global.theprogrammablemind.loadForTesting)[0])
115
139
  }
116
140
  args.km = (name) => config.getConfig(name)
141
+ args.api = (name) => config.getConfig(name).api
117
142
  args.error = (context) => {
118
143
  throw new ErrorReason(context)
119
144
  }
@@ -124,6 +149,7 @@ const setupArgs = (args, config, logs, hierarchy) => {
124
149
  args.listable = listable(hierarchy)
125
150
  args.asList = asList
126
151
  args.retry = () => { throw new RetryError() }
152
+ args.fragments = (query) => config.fragment(query)
127
153
  const scopedAsk = getAsk(config)
128
154
 
129
155
  const getAPI = (uuid) => {
@@ -143,7 +169,6 @@ const setupArgs = (args, config, logs, hierarchy) => {
143
169
  apis: getAPIs(uuid)
144
170
  }
145
171
  }
146
- args.motivation = (m) => config.addMotivation(m)
147
172
  args.breakOnSemantics = false
148
173
  args.theDebugger = {
149
174
  breakOnSemantics: (value) => args.breakOnSemantics = value
@@ -157,10 +182,10 @@ const setupArgs = (args, config, logs, hierarchy) => {
157
182
  }
158
183
  args.e = (c) => config.getEvaluator(args.s, args.calls, logs, c)
159
184
  args.log = (message) => logs.push(message)
160
- // config.getAddedArgs(args)
161
185
  args.gs = gs(args.g)
162
186
  args.gsp = gs(args.gp)
163
187
  args.gsr = gs(args.gr)
188
+ config.getAddedArgs(args)
164
189
  }
165
190
 
166
191
  const gs = (g) => (contexts, separator, lastSeparator) => {
@@ -298,7 +323,6 @@ const writeTest = (fn, query, objects, generated, paraphrases, responses, contex
298
323
  }
299
324
  associations.sort()
300
325
  // tests[query] = sortJson({ paraphrases, responses, contexts, objects: convertToStable(objects), associations, metadata, config, developerTest: saveDeveloper }, { depth: 25 })
301
- debugger
302
326
  results = sortJson({
303
327
  query,
304
328
  paraphrases,
@@ -367,7 +391,7 @@ const setupContexts = (rawContexts) => {
367
391
  return contexts
368
392
  }
369
393
 
370
- const processContextsB = ({ config, hierarchy, semantics, generators, json, isTest, query, data, retries, url, commandLineArgs }) => {
394
+ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTest, isInstance, instance, query, data, retries, url, commandLineArgs }) => {
371
395
  // TODO fix this name to contextsPrime
372
396
  const contextsPrime = []
373
397
  const generatedPrime = []
@@ -378,7 +402,7 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
378
402
  const contexts = setupContexts(json.contexts)
379
403
 
380
404
  const objects = config.get('objects')
381
- const args = { objects, isResponse: true, response: json, isTest, getObjects: getObjects(objects) }
405
+ const args = { objects, isResponse: true, response: json, isTest, isInstance, getObjects: getObjects(objects), instance }
382
406
  if (!json.logs) {
383
407
  json.logs = []
384
408
  }
@@ -389,28 +413,6 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
389
413
  config.debugLoops = commandLineArgs && commandLineArgs.debugLoops
390
414
  while (toDo.length > 0) {
391
415
  const context = toDo.shift()
392
- /*
393
- if (false && query) {
394
- if (config.wasChanged()) {
395
- // process contexts that overlap
396
- overlap = lastRange
397
- } else {
398
- config.watch()
399
- }
400
- if (overlap) {
401
- if (overlaps(overlap, context)) {
402
- // okay
403
- query = query.slice(overlap.end+1)
404
- data.utterance = query
405
- const json = await doWithRetries(retries, url, data)
406
- toDo = setupContexts(json.contexts).slice(1) // take off the start context
407
- }
408
- overlap = undefined
409
- }
410
- lastRange = context.range
411
- }
412
- */
413
-
414
416
  args.calls.next()
415
417
  let contextPrime = context
416
418
  context.topLevel = true
@@ -418,19 +420,21 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
418
420
  if (json.has_errors) {
419
421
  throw new Error('There are errors in the logs. Run with the -d flag and grep for Error')
420
422
  }
423
+ const generateParenthesized = isTest || (commandLineArgs && commandLineArgs.save)
421
424
  if (!config.get('skipSemantics')) {
422
- if (!config.doMotivations(args, context)) {
423
- const semantics = config.getSemantics(json.logs)
424
- try {
425
- contextPrime = semantics.apply(args, context)
426
- } catch( e ) {
427
- if (e.message == 'Maximum call stack size exceeded') {
428
- const mostCalled = semantics.getMostCalled()
429
- e.message += `\nThe most called semantic was:\nnotes: ${mostCalled.notes}\nmatch: ${mostCalled.matcher.toString()}\napply: ${mostCalled._apply.toString()}\n`
430
- }
431
- // contextPrime = semantics.apply(args, { marker: 'error', context, error: e })
432
- contextPrime = semantics.apply(args, { marker: 'error', context, reason: e.reason })
425
+ const semantics = config.getSemantics(json.logs)
426
+ try {
427
+ contextPrime = semantics.apply(args, context)
428
+ } catch( e ) {
429
+ if (e.message == 'Maximum call stack size exceeded') {
430
+ const mostCalled = semantics.getMostCalled()
431
+ e.message += `\nThe most called semantic was:\nnotes: ${mostCalled.notes}\nmatch: ${mostCalled.matcher.toString()}\napply: ${mostCalled._apply.toString()}\n`
432
+ }
433
+ // contextPrime = semantics.apply(args, { marker: 'error', context, error: e })
434
+ if (isInstance) {
435
+ console.log('error', e.error)
433
436
  }
437
+ contextPrime = semantics.apply(args, { marker: 'error', context, reason: e.reason, error: e.stack })
434
438
  }
435
439
  }
436
440
  if (contextPrime.controlRemove) {
@@ -439,7 +443,7 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
439
443
  let assumed = { isResponse: true };
440
444
  const generated = contextPrime.isResponse ? config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0] : ''
441
445
  let generatedParenthesized = []
442
- if (isTest) {
446
+ if (generateParenthesized) {
443
447
  config.parenthesized = true
444
448
  generatedParenthesized = contextPrime.isResponse ? config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0] : ''
445
449
  config.parenthesized = false
@@ -452,12 +456,12 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
452
456
  args.gs = gs(args.g)
453
457
  args.gsp = gs(args.gsp)
454
458
  args.gsr = gs(args.gr)
455
- if (isTest) {
459
+ if (generateParenthesized) {
456
460
  config.parenthesized = false
457
461
  }
458
462
  const paraphrases = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
459
463
  let paraphrasesParenthesized = []
460
- if (isTest) {
464
+ if (generateParenthesized) {
461
465
  config.parenthesized = true
462
466
  paraphrasesParenthesized = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
463
467
  config.parenthesized = false
@@ -471,7 +475,7 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
471
475
  contextsPrime.push(contextPrime)
472
476
  generatedPrime.push(generated)
473
477
  paraphrasesPrime.push(paraphrases)
474
- if (isTest) {
478
+ if (generateParenthesized) {
475
479
  paraphrasesParenthesizedPrime.push(paraphrasesParenthesized)
476
480
  generatedParenthesizedPrime.push(generatedParenthesized)
477
481
  }
@@ -549,8 +553,11 @@ const setupProcessB = ({ config, initializer, allowDelta=false } = {}) => {
549
553
  // console.log('config', config)
550
554
  data.delta = config.delta()
551
555
  } else {
552
- Object.assign(data, config.config)
556
+ config.toData(data)
557
+ // Object.assign(data, config.config)
553
558
  }
559
+
560
+ // config.toServer(data)
554
561
 
555
562
  if (data.namespaces) {
556
563
  for (const uuid of Object.keys(data.namespaces)) {
@@ -573,10 +580,22 @@ const setupProcessB = ({ config, initializer, allowDelta=false } = {}) => {
573
580
  }
574
581
  }
575
582
 
576
- // instance template
577
- const processInstance = (config, instance) => {
583
+ // instance template loadTemplate
584
+ const loadInstance = (config, instance) => {
578
585
  const transitoryMode = global.transitoryMode
579
586
  global.transitoryMode = false
587
+
588
+ if (instance && (instance.associations || instance.learned_contextual_priorities)) {
589
+ if (!config.config.retrain) {
590
+ if (instance.associations) {
591
+ config.addAssociations(instance.associations)
592
+ }
593
+ if (instance.learned_contextual_priorities && instance.learned_contextual_priorities.length > 0) {
594
+ config.addPriorities(instance.learned_contextual_priorities)
595
+ }
596
+ }
597
+ }
598
+
580
599
  const { /* data, generators, semantics, */ hierarchy } = setupProcessB({ config })
581
600
  // for (const results of (instance.resultss || [])) {
582
601
  for (const i in (instance.resultss || [])) {
@@ -584,15 +603,21 @@ const processInstance = (config, instance) => {
584
603
  if (results.extraConfig) {
585
604
  // config.addInternal(results, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false)
586
605
  // config.addInternal(config.template.queries[i], { handleCalculatedProps: true } )
587
- config.addInternal(instance.template.queries[i], { handleCalculatedProps: true } )
606
+ config.addInternal(instance.template.queries[i], { addFirst: true, handleCalculatedProps: true } )
588
607
  } else {
589
- processContextsB({ config, hierarchy, json: results/*, generators, semantics */, commandLineArgs: {} })
608
+ if (results.skipSemantics) {
609
+ config.config.skipSemantics = results.skipSemantics
610
+ }
611
+ processContextsB({ config, hierarchy, json: results/*, generators, semantics */, commandLineArgs: {}, isInstance: `instance${i}`, instance: instance.queries[i] })
612
+ if (results.skipSemantics) {
613
+ config.config.skipSemantics = null
614
+ }
590
615
  }
591
616
  }
592
617
  global.transitoryMode = transitoryMode
593
618
  }
594
619
 
595
- const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isTest, saveDeveloper, testConfig, testsFN, errorHandler = defaultErrorHandler } = {}) => {
620
+ const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = defaultErrorHandler } = {}) => {
596
621
  if (credentials) {
597
622
  config.server(credentials.server, credentials.key)
598
623
  }
@@ -606,7 +631,6 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
606
631
  if (writeTests) {
607
632
  config.rebuild()
608
633
  const objects = getObjects(config.config.objects)(config.uuid)
609
- config.beforeQuery({ query, isModule: false, objects })
610
634
  }
611
635
  } catch(error) {
612
636
  throw error
@@ -614,7 +638,10 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
614
638
 
615
639
  let { data, /* generators, semantics, */ hierarchy } = setupProcessB({ config, initializer, allowDelta: true })
616
640
  if (commandLineArgs && commandLineArgs.checkForLoop) {
617
- data.checkForLoop = true
641
+ data.checkForLoop = commandLineArgs.checkForLoop
642
+ }
643
+ if (rebuildingTemplate) {
644
+ data.errors_ignore_contextual_priorities_non_existant_ops = true
618
645
  }
619
646
  let queries = query.split('\\n')
620
647
 
@@ -671,6 +698,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
671
698
  const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
672
699
  processContextsB({ isTest, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
673
700
  response.associations = json.associations
701
+ response.learned_contextual_priorities = json.learned_contextual_priorities
674
702
  response.hierarchy = json.hierarchy
675
703
  response.load_cache_time += json.load_cache_time
676
704
  appendNoDups(response.logs, json.logs)
@@ -681,6 +709,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
681
709
  response.times += json.times
682
710
  response.trace = response.trace.concat(json.trace)
683
711
  response.version = json.version
712
+ response.explain_priorities = json.explain_priorities
684
713
 
685
714
  response.contexts = response.contexts.concat(contextsPrime)
686
715
  response.generated = response.generated.concat(generatedPrime)
@@ -694,7 +723,12 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
694
723
 
695
724
  if (writeTests) {
696
725
  const actual_config = getConfigForTest(config, testConfig)
697
- writeTest(testsFN, query, config.config.objects, response.generated, response.paraphrases, response.responses, response.contexts, response.associations, response.metadata, actual_config, saveDeveloper, response.paraphrasesParenthesized, response.generatedParenthesized)
726
+ const saveObjects = {...config.config.objects}
727
+ saveObjects.nameToUUID = {}
728
+ for (let km of config.configs) {
729
+ saveObjects.nameToUUID[km.name] = km.uuid
730
+ }
731
+ writeTest(testsFN, query, saveObjects, response.generated, response.paraphrases, response.responses, response.contexts, response.associations, response.metadata, actual_config, saveDeveloper, response.paraphrasesParenthesized, response.generatedParenthesized)
698
732
  }
699
733
 
700
734
  return response
@@ -734,7 +768,7 @@ const getConfigForTest = (config, testConfig) => {
734
768
  return configForTest
735
769
  }
736
770
 
737
- const runTest = async (config, expected, { args, verbose, afterTest, testConfig, debug }) => {
771
+ const runTest = async (config, expected, { args, verbose, testConfig, debug }) => {
738
772
  const test = expected.query
739
773
  // initialize in between test so state is not preserved since the test was adding without state
740
774
  config.rebuild()
@@ -759,8 +793,6 @@ const runTest = async (config, expected, { args, verbose, afterTest, testConfig,
759
793
  objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
760
794
  testConfigName = testConfig.testModuleName
761
795
  }
762
- config.beforeQuery({ query: test, isModule: false, objects })
763
- // config.resetMotivations()
764
796
  try {
765
797
  const result = await _process(config, test, { errorHandler, isTest: true })
766
798
  result.query = test
@@ -778,38 +810,29 @@ const runTest = async (config, expected, { args, verbose, afterTest, testConfig,
778
810
  delete expected_objects.nameToUUID
779
811
  const actual_objects = sortJson(convertToStable(config.config.objects), { depth: 25 })
780
812
  const failed_paraphrases = !matching(result.paraphrases, expected.paraphrases)
781
- const failed_paraphrasesParenthesized = !matching(result.paraphrasesParenthesized, expected.paraphrasesParenthesized)
782
- const failed_generatedParenthesized = !matching(result.generatedParenthesized, expected.generatedParenthesized)
813
+ let failed_paraphrasesParenthesized = !matching(result.paraphrasesParenthesized, expected.paraphrasesParenthesized)
814
+ let failed_generatedParenthesized = !matching(result.generatedParenthesized, expected.generatedParenthesized)
815
+ // TODO fix the naming conventions: camelcase + use actual instead of result
783
816
  const failed_responses = !matching(result.responses, expected.responses)
784
817
  const failed_contexts = !matching(result.contexts, expected.contexts)
785
818
  const failed_objects = !matching(actual_objects, expected_objects)
786
819
 
787
- const pickEm = (getObjects) => {
788
- const picked = {}
789
- for (let prop of (testConfig.check || [])) {
790
- if (prop.km) {
791
- c = config.getConfig(prop.km)
792
- o = getObjects(prop.km)
793
- picked[prop.km] = {}
794
- for (let p of c.testConfig.check) {
795
- if (p.km) {
796
- continue
797
- }
798
- picked[p] = o[p]
799
- }
800
- } else {
801
- picked[prop] = getObjects(testConfigName)[prop]
802
- }
803
- }
804
- return picked
820
+ if (args.testNoParenthesized) {
821
+ failed_paraphrasesParenthesized = false
822
+ failed_generatedParenthesized = false
805
823
  }
824
+
825
+ const pickedResultContexts = result.contexts.map(pickContext(testConfig))
826
+ const pickedExpectedContexts = expected.contexts.map(pickContext(testConfig))
827
+ const failedCheckedContexts = !matching(pickedResultContexts, pickedExpectedContexts)
828
+
806
829
  const expectedGetObjects = (name) => {
807
830
  if (!name) {
808
831
  name = config.name
809
832
  }
810
833
  return expected.objects.namespaced[expected.objects.nameToUUID[name]]
811
834
  }
812
- const expected_checked = sortJson(pickEm(expectedGetObjects), { depth: 25 })
835
+ const expected_checked = sortJson(pickObjects(testConfig, objects), { depth: 25 })
813
836
  const actualGetObjects = (name) => {
814
837
  if (!name) {
815
838
  name = config.name
@@ -817,45 +840,14 @@ const runTest = async (config, expected, { args, verbose, afterTest, testConfig,
817
840
  const km = config.configs.find( (km) => km.name == name )
818
841
  return config.config.objects.namespaced[km.uuid]
819
842
  }
820
- const actual_checked = sortJson(pickEm(actualGetObjects), { depth: 25 })
843
+ const actual_checked = sortJson(pickObjects(testConfig, actualGetObjects(testConfigName)), { depth: 25 })
821
844
  const failed_checked = !matching(actual_objects, expected_objects)
822
845
 
823
846
  const failed_checks = !matching(actual_objects, expected_objects)
824
847
  const actual_config = sortJson(convertToStable(getConfigForTest(config, testConfig)), { depth: 25 })
825
848
  const expected_config = sortJson(convertToStable(expected.config), { depth: 25 })
826
849
  const failed_config = !matching(actual_config, expected_config)
827
- let failed = failed_paraphrases || failed_paraphrasesParenthesized || failed_generatedParenthesized || failed_responses || failed_contexts || failed_objects || failed_config || failed_checked
828
- if (!failed) {
829
- if (config.afterTest) {
830
- failed = config.afterTest({ query: test, expected, actual: result, config })
831
- if (failed) {
832
- return {
833
- utterance: test,
834
- errorFromAfterTest: failed,
835
- expected: {
836
- responses: expected.responses,
837
- paraphrases: expected.paraphrases,
838
- paraphrasesParenthesized: expected.paraphrasesParenthesized,
839
- generatedParenthesized: expected.generatedParenthesized,
840
- results: expected.contexts,
841
- checked: expected_checked,
842
- objects: expected_objects,
843
- config: expected.config
844
- },
845
- actual: {
846
- responses: result.responses,
847
- paraphrases: result.paraphrases,
848
- paraphrasesParenthesized: result.paraphrasesParenthesized,
849
- generatedParenthesized: result.generatedParenthesized,
850
- results: result.contexts,
851
- checked: actual_checked,
852
- objects: actual_objects,
853
- config: actual_config
854
- }
855
- }
856
- }
857
- }
858
- }
850
+ let failed = failed_paraphrases || failed_paraphrasesParenthesized || failed_generatedParenthesized || failed_responses || failed_contexts || failed_objects || failed_config || failed_checked || failedCheckedContexts
859
851
 
860
852
  if (expected.metadata && result.metadata && failed) {
861
853
  const priorities = analyzeMetaData(expected.metadata, result.metadata)
@@ -874,6 +866,7 @@ const runTest = async (config, expected, { args, verbose, afterTest, testConfig,
874
866
  generatedParenthesized: expected.generatedParenthesized,
875
867
  results: expected.contexts,
876
868
  checked: expected_checked,
869
+ checkedContexts: pickedExpectedContexts,
877
870
  objects: expected_objects,
878
871
  config: expected.config
879
872
  },
@@ -884,6 +877,7 @@ const runTest = async (config, expected, { args, verbose, afterTest, testConfig,
884
877
  generatedParenthesized: result.generatedParenthesized,
885
878
  results: result.contexts,
886
879
  checked: actual_checked,
880
+ checkedContexts: pickedResultContexts,
887
881
  objects: actual_objects,
888
882
  config: actual_config
889
883
  }
@@ -923,20 +917,16 @@ const runTestsHelper = async (config, tests, failed, juicyBits) => {
923
917
 
924
918
  const runTests = async (config, testFile, juicyBits) => {
925
919
  const tests = JSON.parse(runtime.fs.readFileSync(testFile))
926
- config.beforeTests()
927
920
  if (juicyBits.verbose) {
928
921
  console.log('\n', testFile, '-----------------------------------------------', '\n')
929
922
  }
930
923
  const v = await runTestsHelper(config, [...tests], [], juicyBits)
931
- config.afterTests()
932
924
  return v
933
925
  }
934
926
 
935
927
  const saveTest = async (testFile, config, test, expected, testConfig, saveDeveloper) => {
936
928
  config.rebuild()
937
929
  const objects = getObjects(config.config.objects)(config.uuid)
938
- //config.resetMotivations()
939
- config.beforeQuery({ query: test, isModule: false, objects })
940
930
  console.log(test)
941
931
  const result = await _process(config, test, { isTest: true })
942
932
  // const actualObjects = config.config.objects
@@ -1118,10 +1108,11 @@ const defaultErrorHandler = async (error) => {
1118
1108
  doErrorExit = true
1119
1109
  }
1120
1110
 
1121
- if (doErrorExit) {
1111
+ if (typeof runtime.process.exit == 'function' && doErrorExit) {
1122
1112
  runtime.process.exit(-1)
1123
1113
  }
1124
- // throw error
1114
+
1115
+ throw error
1125
1116
  }
1126
1117
 
1127
1118
  const defaultInnerProcess = (config, errorHandler, responses) => {
@@ -1131,6 +1122,13 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1131
1122
  }
1132
1123
  console.log("KM's loaded", config.configs.map((c) => c.name))
1133
1124
  console.log('This is the global objects from running semantics:\n', config.objects)
1125
+ if (!_.isEmpty(responses.learned_contextual_priorities)) {
1126
+ console.log('\nThe learned contextual priorties are :\n')
1127
+ for (const lcp of responses.learned_contextual_priorities) {
1128
+ console.log(` ${JSON.stringify(lcp)},\n`)
1129
+ }
1130
+ console.log("\n")
1131
+ }
1134
1132
  if (responses.logs) {
1135
1133
  console.log('Logs')
1136
1134
  responses.logs.forEach((log) => console.log(` ${log}`))
@@ -1142,6 +1140,50 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1142
1140
  } else {
1143
1141
  console.log('objects', runtime.util.inspect(config.get('objects'), { depth: Infinity, sorted: true }))
1144
1142
  }
1143
+
1144
+ const pickEm = () => {
1145
+ const picked = {}
1146
+ const namespaced = config.get('objects')['namespaced']
1147
+ for (let prop of getConfig_getObjectCheck(config.testConfig)) {
1148
+ if (prop.km) {
1149
+ /*
1150
+ const objects = namespaced[prop.km]]
1151
+ picked[prop.km] = {}
1152
+ for (let p of c.testConfig.check) {
1153
+ if (p.km) {
1154
+ continue
1155
+ }
1156
+ picked[p] = objects[p]
1157
+ }
1158
+ */
1159
+ console.log('TODO implement this if needed')
1160
+ } else {
1161
+ const objects = namespaced[config.uuid]
1162
+ picked[prop] = objects[prop]
1163
+ }
1164
+ }
1165
+ return picked
1166
+ }
1167
+
1168
+ if (responses.explain_priorities) {
1169
+ console.log("Explain Priorities")
1170
+ for ([inputss, outpus, reason] of responses.explain_priorities) {
1171
+ console.log(` ${JSON.stringify(inputss)} reason: ${reason}`)
1172
+ }
1173
+ }
1174
+ const objects = config.get('objects').namespaced[config.uuid]
1175
+ const picked = sortJson(pickObjects(config.testConfig, objects), { depth: 25 })
1176
+ if (!_.isEmpty(picked)) {
1177
+ console.log('--- Object showing only the checked values ---')
1178
+ console.log(JSON.stringify(picked, null, 2))
1179
+ }
1180
+
1181
+ const pickedResultContexts = responses.contexts.map(pickContext(config.testConfig))
1182
+ if (pickedResultContexts.some( (context) => Object.keys(context).length > 0 )) {
1183
+ console.log('--- Contexts showing only the checked values ---')
1184
+ console.log(JSON.stringify(pickedResultContexts, null, 2))
1185
+ }
1186
+
1145
1187
  console.log('--- The contexts are ----------')
1146
1188
  console.log(JSON.stringify(sortJson(responses.contexts, { depth: 25 }), null, 2))
1147
1189
  console.log('')
@@ -1182,37 +1224,14 @@ const defaultProcess = ({ config, errorHandler }) => async (promise) => {
1182
1224
  }
1183
1225
  }
1184
1226
 
1185
- /*
1186
- const kmFileTemplate = (kmBaseName, kmName) =>
1187
- `const entodicton = require('entodicton')
1188
- const base = require('./${kmBaseName}').copy()
1189
- const ${kmName}_tests = require('./${kmName}.test.json')
1190
- const ${kmName}_instance = require('./${kmBaseName}.${kmName}.instance.json')
1191
-
1192
- const config = new entodicton.Config({ name: '${kmName}' })
1193
- config.add(base)
1194
- kirk_instance.base = '${kmBaseName}'
1195
- config.load(${kmName}_instance)
1196
-
1197
- entodicton.knowledgeModule( {
1198
- module,
1199
- description: '${kmName} related concepts',
1200
- section,
1201
- config,
1202
- test: {
1203
- name: './${kmName}.test.json',
1204
- contents: ${kmName}_tests
1205
- },
1206
- })
1207
- `
1208
- */
1209
-
1210
- const build = async ({ config, target, template, errorHandler = defaultErrorHandler }) => {
1227
+ // builtTemplate saveInstance
1228
+ const rebuildTemplate = async ({ config, target, template, errorHandler = defaultErrorHandler }) => {
1211
1229
  const accumulators = {
1212
1230
  resultss: [],
1213
1231
  fragments: [],
1214
1232
  semantics: [],
1215
1233
  associations: [],
1234
+ learned_contextual_priorities: [],
1216
1235
  }
1217
1236
  const looper = async (queries) => {
1218
1237
  if (queries.length === 0) {
@@ -1231,8 +1250,6 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1231
1250
  if (property == 'fragments') {
1232
1251
  global.transitoryMode = true
1233
1252
  }
1234
- // greg32
1235
- // config.addInternal( query )
1236
1253
  if (hierarchy) {
1237
1254
  for (let edge of hierarchy) {
1238
1255
  if (Array.isArray(edge)) {
@@ -1242,9 +1259,8 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1242
1259
  }
1243
1260
  }
1244
1261
  }
1245
-
1246
1262
  try {
1247
- const results = await _process(config, query.query, {initializer})
1263
+ const results = await _process(config, query.query, {initializer, rebuildingTemplate: true})
1248
1264
  if (config.config.debug) {
1249
1265
  // TODO pass in the error handler like the other ones
1250
1266
  defaultInnerProcess(config, defaultErrorHandler, results)
@@ -1259,10 +1275,12 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1259
1275
  global.transitoryMode = transitoryMode
1260
1276
  config.config.skipSemantics = null
1261
1277
  results.query = query.query
1278
+ results.skipSemantics = skipSemantics
1262
1279
  results.development = query.development
1263
1280
  results.key = { query: query.query, hierarchy }
1264
1281
  accumulators[property].push(results)
1265
1282
  accumulators.associations = accumulators.associations.concat(results.associations)
1283
+ accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
1266
1284
  await looper(queries)
1267
1285
  } catch(e) {
1268
1286
  const error = { errors: [e], query: query.query };
@@ -1274,6 +1292,12 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1274
1292
  // it will just get added to the config
1275
1293
  const extraConfig = queryOrExtraConfig
1276
1294
  console.log('config', extraConfig)
1295
+ try {
1296
+ config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true } )
1297
+ } catch ( e ) {
1298
+ const where = extraConfig.where ? ` ${extraConfig.where}` : ''
1299
+ throw new Error(`Error processing extra config${where}: ${e.stack}}`)
1300
+ }
1277
1301
  accumulators[property].push({ extraConfig: true, ...extraConfig })
1278
1302
  await looper(queries)
1279
1303
  }
@@ -1301,6 +1325,7 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1301
1325
  delete result.version
1302
1326
  result.hierarchy.sort()
1303
1327
  stabilizeAssociations(result.associations)
1328
+ result.learned_contextual_priorities = safeNoDups(result.learned_contextual_priorities)
1304
1329
  }
1305
1330
  }
1306
1331
  }
@@ -1321,14 +1346,14 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1321
1346
 
1322
1347
  const toProperties = (queryStringOrProperties) => {
1323
1348
  if (typeof queryStringOrProperties == 'string') {
1324
- return { query: queryStringOrProperties}
1349
+ return { query: queryStringOrProperties }
1325
1350
  } else {
1326
1351
  return queryStringOrProperties
1327
1352
  }
1328
1353
  }
1329
1354
  let todo = []
1330
- todo = todo.concat((template.initializers || []).map((query) => { return { initializer: true, property: 'resultss', query, skipSemantics: false } }))
1331
- todo = todo.concat((template.queries || []).map((query) => { return { property: 'resultss', query, skipSemantics: false } }))
1355
+ todo = todo.concat((template.initializers || []).map((query) => { return { initializer: true, property: 'resultss', query, skipSemantics: false || query.skipSemantics } }))
1356
+ todo = todo.concat((template.queries || []).map((query) => { return { property: 'resultss', query, skipSemantics: false || query.skipSemantics} }))
1332
1357
  todo = todo.concat((template.fragments || []).map((query) => { return Object.assign({}, toProperties(query), { property: 'fragments', skipSemantics: false }) }))
1333
1358
  todo = todo.concat((template.semantics || []).map((definition) => { return { property: 'semantics', query: `${definition.from}\n${definition.to}`, skipSemantics: true } }))
1334
1359
  await looper(Object.assign([], todo))
@@ -1338,36 +1363,31 @@ const knowledgeModule = async ({
1338
1363
  module: moduleFromJSFile,
1339
1364
  description,
1340
1365
  section,
1341
- config,
1366
+ // config, createConfig,
1367
+ createConfig,
1368
+ newWay,
1342
1369
  demo,
1343
1370
  test,
1344
1371
  template,
1345
1372
  errorHandler = defaultErrorHandler,
1346
1373
  process: processResults = defaultProcess,
1347
1374
  stopAtFirstFailure = true,
1348
- beforeQuery = () => {},
1349
- beforeTests = () => {},
1350
- afterTests = () => {},
1351
- beforeTest = () => {},
1352
- afterTest = () => {}
1375
+ ...rest
1353
1376
  } = {}) => {
1354
1377
 
1355
- config.beforeQuery = beforeQuery
1356
- config.beforeTests = beforeTests
1357
- config.afterTests = afterTests
1358
- config.beforeTest = beforeTest
1359
- config.afterTest = afterTest
1378
+ const unknownArgs = Object.keys(rest)
1379
+ if (unknownArgs.length > 0) {
1380
+ throw new Error(`Unknown arguments to knowledgeModule: ${unknownArgs.join()}`)
1381
+ }
1360
1382
 
1361
1383
  const testConfig = test
1362
1384
 
1363
1385
  if (!moduleFromJSFile) {
1364
1386
  throw new Error("'module' is a required parameter. The value should be either 'module' or a lambda that will be called when the file is acting as a module.")
1365
1387
  }
1366
- if (!config) {
1367
- throw new Error("'config' is a required parameter. The value should the config that defines the knowledge module.")
1368
- }
1369
- if (!config.name) {
1370
- throw new Error("config must have 'name' set to the knowledge module name.")
1388
+ // if (!config && !createConfig) {
1389
+ if (!createConfig) {
1390
+ throw new Error("'config' or 'createConfig' is a required parameter. The value should the config that defines the knowledge module.")
1371
1391
  }
1372
1392
  if (!description) {
1373
1393
  throw new Error("'description' is a required parameter. The value should the description of the knowledge module.")
@@ -1377,86 +1397,52 @@ const knowledgeModule = async ({
1377
1397
  }
1378
1398
 
1379
1399
  const isProcess = require.main === moduleFromJSFile
1380
- let loadForTesting = false
1381
- if (global.theprogrammablemind) {
1382
- if (global.theprogrammablemind.loadForTesting[config.name]) {
1383
- loadForTesting = true
1400
+
1401
+ const setupConfig = (config) => {
1402
+ if (!config.name) {
1403
+ throw new Error("config must have 'name' set to the knowledge module name.")
1384
1404
  }
1385
- }
1386
1405
 
1387
- // remove test only stuff
1388
- if (!isProcess && !loadForTesting) {
1389
- config.config.operators = config.config.operators.filter( (operator) => {
1390
- if (operator.development) {
1391
- return false
1392
- } else {
1393
- return true
1394
- }
1395
- })
1396
- config.config.bridges = config.config.bridges.filter( (bridge) => {
1397
- if (bridge.development) {
1398
- return false
1399
- } else {
1400
- return true
1406
+ config.description = description
1407
+ if (typeof test === 'object') {
1408
+ if (test.contents) {
1409
+ config.tests = test.contents
1410
+ test = test.name
1401
1411
  }
1402
- })
1403
- }
1404
-
1405
- let module
1406
- if (_.isFunction(moduleFromJSFile)) {
1407
- module = moduleFromJSFile
1408
- } else {
1409
- module = () => {
1410
- config.rebuild({ isModule: true })
1411
- moduleFromJSFile.exports = config
1412
- }
1413
- }
1414
- processResults = processResults({ config, errorHandler })
1415
- config.description = description
1416
- config.demo = demo
1417
- if (typeof test === 'object') {
1418
- if (test.contents) {
1419
- config.tests = test.contents
1420
- test = test.name
1421
- }
1422
- } else {
1423
- if (runtime.fs && runtime.fs.existsSync(test)) {
1424
- config.tests = JSON.parse(runtime.fs.readFileSync(test))
1425
1412
  } else {
1426
- config.tests = {}
1427
- }
1428
- }
1429
- config.setTestConfig(testConfig)
1430
-
1431
- if (!isProcess) {
1432
- if (template) {
1433
- if (config.needsRebuild(template.template, template.instance)) {
1434
- throw new Error(`This module "${config.name}" cannot be used because the instance file needs rebuilding. Run on the command line with no arguements or the -rt argument to rebuild.`)
1435
- }
1436
- try {
1437
- config.load(template.template, template.instance)
1438
- } catch( e ) {
1439
- errorHandler(e)
1413
+ if (runtime.fs && runtime.fs.existsSync(test)) {
1414
+ config.tests = JSON.parse(runtime.fs.readFileSync(test))
1415
+ } else {
1416
+ config.tests = []
1440
1417
  }
1441
1418
  }
1419
+ config.setTestConfig(testConfig)
1442
1420
  }
1421
+
1422
+
1443
1423
  if (isProcess) {
1424
+ const config = createConfig()
1425
+ setupConfig(config)
1426
+ processResults = processResults({ config, errorHandler })
1444
1427
  // setup();
1445
1428
  const parser = new runtime.ArgumentParser({
1446
1429
  description: 'Entodicton knowledge module'
1447
1430
  })
1448
1431
 
1449
- const helpDebugAssociation = 'In order to get a debug break when a specific association is created set the DEBUG_ASSOCIATION environment variable to the JSON of the association to break on. For example DEBUG_ASSOCIATION=\'["the#0", "mammel#0"]\' })'
1450
- 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#1", "mammel#1"]\' })'
1451
- const helpDebugPriority = 'In order to get a debug break when a specific set of priorities is created set set DEBUG_PRIORITY environment variable to the JSON of the priorities that you want to break on. For example DEBUG_PRIORITY=\'["verb#0", "article#0"]\' })'
1452
- const helpDebugBridge = 'In order to get a debug break when a specific bridge is created set the DEBUG_BRIDGE environment variable to id/level to break on. For example DEBUG_BRIDGE=\'id#level\' })'
1453
- const helpDebugOperator = 'In order to get a debug break when a specific hierarcy is created set the DEBUG_OPERATOR environment variable to debug any config loaded. For example DEBUG_OPERATOR=\'([operator] ([arg]))\' })'
1432
+ const helpDebugAssociation = 'In order to get a debug break when a specific association is created set the DEBUG_ASSOCIATION environment variable to the JSON of the association to break on. For example DEBUG_ASSOCIATION=\'[["the", 0], ["mammal", 1]]\''
1433
+ 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", 1], ["mammel", 1]]\''
1434
+ const helpDebugPriority = 'In order to get a debug break when a specific set of priorities is created set set DEBUG_PRIORITY environment variable to the JSON of the priorities that you want to break on. For example DEBUG_PRIORITY=\'[["verb", 0], ["article", 0]]\''
1435
+ const helpDebugContextualPriority = 'In order to get a debug break when a specific set of contextual priorities is created set set DEBUG_CONTEXTUAL_PRIORITY environment variable to the JSON of the priorities that you want to break on. For example DEBUG_CONTEXTUAL_PRIORITY=\'{ context: [["verb", 0], ["article", 0], select: 1}\''
1436
+ const helpDebugBridge = 'In order to get a debug break when a specific bridge is created set the DEBUG_BRIDGE environment variable to id/level to break on. For example DEBUG_BRIDGE=\'id#level\''
1437
+ const helpDebugOperator = 'In order to get a debug break when a specific hierarcy is created set the DEBUG_OPERATOR environment variable to debug any config loaded. For example DEBUG_OPERATOR=\'([operator] ([arg]))\''
1454
1438
 
1455
1439
 
1456
1440
  parser.add_argument('-tmn', '--testModuleName', { help: 'When running tests instead of using the current modules tests use the specified modules tests' })
1457
1441
  parser.add_argument('-t', '--test', { action: 'store_true', help: 'Run the tests. Create tests by running with the --query + --save flag' })
1458
1442
  parser.add_argument('-tv', '--testVerbose', { action: 'store_true', help: 'Run the tests in verbose mode. Create tests by running with the --query or --loop with the --save flag' })
1443
+ // parser.add_argument('-ttr', '--testToRun', { help: 'Only the specified test will be run' })
1459
1444
  parser.add_argument('-tva', '--testAllVerbose', { action: 'store_true', help: 'Run the tests in verbose mode. All the tests will be run instead of stopping at first failure. Create tests by running with the --query or --loop with the --save flag' })
1445
+ parser.add_argument('-tnp', '--testNoParenthesized', { action: 'store_true', help: 'Don\' check parenthesized differences for the tests' })
1460
1446
  parser.add_argument('-n', '--count', { help: 'Number of times to run the tests. Default is one. Use this to check for flakey test. If possible the system will print out a message with the word "hint" suggesting how to fix the problem' })
1461
1447
  // parser.add_argument('-b', '--build', { help: 'Specify the template file name of the form <kmName>. There should be a file called <baseKmName>.<kmName>.template.json with the queries to run. For example { queries: [...] }. The template file will be run and generate an instantiation called <baseKmName>.<kmName>.instance.json and a file called <kmName>.js that will load the template file (this is file generated only if not already existing) and a test file called <KmName>.tests.json. This can then be loaded into an instance of the current knowledge module to setup initial conditions.' })
1462
1448
  parser.add_argument('-rt', '--rebuildTemplate', { action: 'store_true', help: 'Force a template rebuild' })
@@ -1464,7 +1450,7 @@ const knowledgeModule = async ({
1464
1450
  parser.add_argument('-i', '--info', { action: 'store_true', help: 'Print meta-data for the module' })
1465
1451
  parser.add_argument('-v', '--vimdiff', { action: 'store_true', help: 'For failures run vimdiff' })
1466
1452
  parser.add_argument('-g', '--greg', { action: 'store_true', help: 'Set the server to be localhost so I can debug stuff' })
1467
- parser.add_argument('-cl', '--checkForLoop', { action: 'store_true', help: 'Check for loops in the priorities' })
1453
+ 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]]' })
1468
1454
  parser.add_argument('-r', '--retrain', { action: 'store_true', help: 'Get the server to retrain the neural nets' })
1469
1455
  parser.add_argument('-q', '--query', { help: 'Run the specified query' })
1470
1456
  parser.add_argument('-ip ', '--server', { help: 'Server to run against' })
@@ -1477,14 +1463,16 @@ const knowledgeModule = async ({
1477
1463
  parser.add_argument('-p', '--print', { help: 'Print the specified elements c === config, w === words, b === bridges, o === operators d === objects (d for data), h === hierarchy, g === generators, s === semantics, l === load t=tests ordering p === priorities a == associations j == JSON sent to server. for example --print wb' })
1478
1464
  parser.add_argument('-s', '--save', { action: 'store_true', help: 'When running with the --query flag this will save the current run to the test file. When running without the --query flag all tests will be run and resaved.' })
1479
1465
  parser.add_argument('-sd', '--saveDeveloper', { action: 'store_true', help: 'Same as -s but the query will not show up in the info command.' })
1480
- parser.add_argument('-dic', '--debugIncludeConvolutions', { action: 'store_true', help: 'When running with the --debugIncludeConvolutions flag the logs will include convolutions which are somewhat annoying verbose. Default is false' })
1481
1466
  parser.add_argument('-dl', '--debugLoops', { action: 'store_true', help: 'When running with the --debugLoops flag the logs calls to semantics and generators will be immediately written to the console '})
1482
1467
  parser.add_argument('-d', '--debug', { action: 'store_true', help: 'When running with the --debug flag this set the debug flag in the config' })
1483
- parser.add_argument('-da', '--debugAssociation', { help: helpDebugAssociation })
1484
- parser.add_argument('-dh', '--debugHierarchy', { help: helpDebugHierarchy })
1485
- parser.add_argument('-dp', '--debugPriority', { help: helpDebugPriority })
1486
- parser.add_argument('-db', '--debugBridge', { help: helpDebugBridge })
1487
- parser.add_argument('-do', '--debugOperator', { help: helpDebugOperator })
1468
+ parser.add_argument('-da', '--debugAssociation', { action: 'store_true', help: helpDebugAssociation })
1469
+ parser.add_argument('-dh', '--debugHierarchy', { action: 'store_true', help: helpDebugHierarchy })
1470
+ parser.add_argument('-dp', '--debugPriority', { action: 'store_true', help: helpDebugPriority })
1471
+ parser.add_argument('-dcp', '--debugContextualPriority', { action: 'store_true', help: helpDebugContextualPriority })
1472
+ parser.add_argument('-db', '--debugBridge', { action: 'store_true', help: helpDebugBridge })
1473
+ parser.add_argument('-do', '--debugOperator', { action: 'store_true', help: helpDebugOperator })
1474
+ 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"})
1475
+ 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' })
1488
1476
 
1489
1477
  const args = parser.parse_args()
1490
1478
  args.count = args.count || 1
@@ -1492,7 +1480,35 @@ const knowledgeModule = async ({
1492
1480
  if (args.parenthesized) {
1493
1481
  config.parenthesized = true
1494
1482
  }
1495
-
1483
+ if (args.checkForLoop) {
1484
+ try {
1485
+ args.checkForLoop = JSON.parse(args.checkForLoop)
1486
+ const isKey = (what) => {
1487
+ if (!Array.isArray(what)) {
1488
+ return false
1489
+ }
1490
+ if (what.length !== 2) {
1491
+ return false
1492
+ }
1493
+ if (!typeof what[0] == 'string') {
1494
+ return false
1495
+ }
1496
+ if (!typeof what[1] == 'number') {
1497
+ return false
1498
+ }
1499
+ return true
1500
+ }
1501
+ if (!Array.isArray(args.checkForLoop) || args.checkForLoop.some((value) => !isKey(value))) {
1502
+ throw new Error(`Error for the checkForLoop argument. Expected a JSON array of operator keys of the form "[<id>, <level>]"`)
1503
+ }
1504
+ } catch( e ) {
1505
+ throw new Error(`Error parsing JSON of the checkForLoop argument. ${e}`)
1506
+ }
1507
+ } else {
1508
+ if (process.argv.includes('--checkForLoop') || process.argv.includes('-cl')) {
1509
+ args.checkForLoop = true
1510
+ }
1511
+ }
1496
1512
  if (args.debugAssociation) {
1497
1513
  console.log(helpDebugAssociation)
1498
1514
  runtime.process.exit(-1)
@@ -1550,35 +1566,12 @@ const knowledgeModule = async ({
1550
1566
  if (args.debug) {
1551
1567
  config.config.debug = true
1552
1568
  }
1553
- config.config.debugIncludeConvolutions = args.debugIncludeConvolutions
1554
-
1555
- if (template) {
1556
- const needsRebuild = config.needsRebuild(template.template, template.instance, options)
1557
- if (needsRebuild) {
1558
- console.log(`This module "${config.name}" needs rebuilding all other arguments will be ignored. Try again after the template is rebuilt.`)
1559
-
1560
- }
1561
- config.load(template.template, template.instance, { rebuild: needsRebuild })
1562
- if (needsRebuild) {
1563
- return
1564
- }
1565
- }
1566
1569
 
1567
- if (!args.save && !args.rebuildTemplate && !args.dontAddAssociations) {
1568
- config.addAssociationsFromTests(config.tests);
1569
- //for (let query in config.tests) {
1570
- // config.addAssociations(config.tests[query].associations || []);
1571
- //}
1570
+ if (args.explainPriorities) {
1571
+ config.config.explain_priorities = true
1572
1572
  }
1573
1573
 
1574
- /*
1575
- if (args.buildTemplate) {
1576
- if (template) {
1577
- config.rebuild()
1578
- config.load(template.template, template.instance, { rebuild: true })
1579
- }
1580
- }
1581
- */
1574
+ config.config.debugIncludeConvolutions = args.debugIncludeConvolutions || process.argv.includes('--debugIncludeConvolutions') || process.argv.includes('-dic')
1582
1575
 
1583
1576
  let configPrinted = false
1584
1577
  const printConfig = () => {
@@ -1671,6 +1664,24 @@ const knowledgeModule = async ({
1671
1664
  }
1672
1665
  }
1673
1666
 
1667
+ if (template) {
1668
+ const needsRebuild = config.needsRebuild(template.template, template.instance, options)
1669
+ if (needsRebuild) {
1670
+ console.log(`This module "${config.name}" needs rebuilding all other arguments will be ignored. Try again after the template is rebuilt.`)
1671
+ options.rebuild = true
1672
+ config.config.rebuild = true
1673
+ }
1674
+ config.load(template.template, template.instance, { rebuild: needsRebuild })
1675
+ printConfig()
1676
+ if (needsRebuild) {
1677
+ return
1678
+ }
1679
+ }
1680
+
1681
+ if (!args.save && !args.rebuildTemplate && !args.dontAddAssociations) {
1682
+ config.addAssociationsFromTests(config.tests);
1683
+ }
1684
+
1674
1685
  if (args.retrain) {
1675
1686
  config.config.retrain = true
1676
1687
  }
@@ -1712,11 +1723,13 @@ const knowledgeModule = async ({
1712
1723
  if (JSON.stringify(result.expected.paraphrases) !== JSON.stringify(result.actual.paraphrases)) {
1713
1724
  hasError = true
1714
1725
  }
1715
- if (JSON.stringify(result.expected.paraphrasesParenthesized) !== JSON.stringify(result.actual.paraphrasesParenthesized)) {
1716
- hasError = true
1717
- }
1718
- if (JSON.stringify(result.expected.generatedParenthesized) !== JSON.stringify(result.actual.generatedParenthesized)) {
1719
- hasError = true
1726
+ if (!args.testNoParenthesized) {
1727
+ if (JSON.stringify(result.expected.paraphrasesParenthesized) !== JSON.stringify(result.actual.paraphrasesParenthesized)) {
1728
+ hasError = true
1729
+ }
1730
+ if (JSON.stringify(result.expected.generatedParenthesized) !== JSON.stringify(result.actual.generatedParenthesized)) {
1731
+ hasError = true
1732
+ }
1720
1733
  }
1721
1734
  if (JSON.stringify(result.expected.responses) !== JSON.stringify(result.actual.responses)) {
1722
1735
  hasError = true
@@ -1724,6 +1737,9 @@ const knowledgeModule = async ({
1724
1737
  if (JSON.stringify(result.expected.checked) !== JSON.stringify(result.actual.checked)) {
1725
1738
  hasError = true
1726
1739
  }
1740
+ if (!sameJSON(result.expected.checkedContexts, result.actual.checkedContexts)) {
1741
+ hasError = true
1742
+ }
1727
1743
  }
1728
1744
 
1729
1745
  if (hasError) {
@@ -1742,9 +1758,13 @@ const knowledgeModule = async ({
1742
1758
  }
1743
1759
  }
1744
1760
  show('paraphrases', result.expected.paraphrases, result.actual.paraphrases)
1745
- show('paraphrases parenthesized', result.expected.paraphrasesParenthesized, result.actual.paraphrasesParenthesized)
1761
+ if (!args.testNoParenthesized) {
1762
+ show('paraphrases parenthesized', result.expected.paraphrasesParenthesized, result.actual.paraphrasesParenthesized)
1763
+ }
1746
1764
  show('responses', result.expected.responses, result.actual.responses)
1747
- show('responses parenthesized', result.expected.generatedParenthesized, result.actual.generatedParenthesized)
1765
+ if (!args.testNoParenthesized) {
1766
+ show('responses parenthesized', result.expected.generatedParenthesized, result.actual.generatedParenthesized)
1767
+ }
1748
1768
  /*
1749
1769
  if (JSON.stringify(result.expected.paraphrases) !== JSON.stringify(result.actual.paraphrases)) {
1750
1770
  if (!headerShown) {
@@ -1783,6 +1803,24 @@ const knowledgeModule = async ({
1783
1803
  newError = true
1784
1804
  headerShown = true
1785
1805
  }
1806
+ if (!sameJSON(result.expected.checkedContexts, result.actual.checkedContexts)) {
1807
+ if (!headerShown) {
1808
+ console.log(' Failure')
1809
+ }
1810
+ const widths = [4, 18, 72]
1811
+ const lines = new Lines(widths)
1812
+ lines.setElement(1, 1, 'expected checkedContexts', true)
1813
+ lines.setElement(2, 2, JSON.stringify(result.expected.checkedContexts, null, 2))
1814
+ lines.log()
1815
+ lines.setElement(1, 1, 'actual checkedContexts', true)
1816
+ lines.setElement(2, 2, JSON.stringify(result.actual.checkedContexts, null, 2))
1817
+ lines.log()
1818
+ if (args.vimdiff) {
1819
+ vimdiff(result.actual.checkedContexts, result.expected.checkedContexts)
1820
+ }
1821
+ newError = true
1822
+ headerShown = true
1823
+ }
1786
1824
  }
1787
1825
  } else {
1788
1826
  if (results.length > 0 && args.vimdiff) {
@@ -1821,7 +1859,6 @@ const knowledgeModule = async ({
1821
1859
  if (query.length === 0) {
1822
1860
  return readline.close()
1823
1861
  }
1824
- // const promise = processResults(_process(config, query, { testsFN: test }))
1825
1862
  const promise = _process(config, query, { testsFN: test }).then((results) => {
1826
1863
  console.log(results.responses.join(' '))
1827
1864
  })
@@ -1849,7 +1886,6 @@ const knowledgeModule = async ({
1849
1886
  if (args.objectDiff) {
1850
1887
  global.beforeObjects = _.cloneDeep(objects)
1851
1888
  }
1852
- config.beforeQuery({ query: args.query, isModule: false, objects })
1853
1889
  try {
1854
1890
  await processResults(_process(config, args.query, { commandLineArgs: args, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
1855
1891
  } catch( error ) {
@@ -1858,11 +1894,55 @@ const knowledgeModule = async ({
1858
1894
  }
1859
1895
  printConfig()
1860
1896
  } else {
1861
- config.addAssociationsFromTests(config.tests);
1862
- //for (let query in config.tests) {
1863
- // config.addAssociations(config.tests[query].associations || []);
1864
- //}
1865
- module()
1897
+ const initConfig = (config) => {
1898
+ setupConfig(config)
1899
+
1900
+ let loadForTesting = false
1901
+ if (global.theprogrammablemind) {
1902
+ if (global.theprogrammablemind.loadForTesting[config.name]) {
1903
+ loadForTesting = true
1904
+ }
1905
+ }
1906
+ // remove test only stuff
1907
+ if (!isProcess && !loadForTesting) {
1908
+ config.config.operators = config.config.operators.filter( (operator) => {
1909
+ if (operator.development) {
1910
+ return false
1911
+ } else {
1912
+ return true
1913
+ }
1914
+ })
1915
+ config.config.bridges = config.config.bridges.filter( (bridge) => {
1916
+ if (bridge.development) {
1917
+ return false
1918
+ } else {
1919
+ return true
1920
+ }
1921
+ })
1922
+ }
1923
+
1924
+ if (template) {
1925
+ if (config.needsRebuild(template.template, template.instance, { isModule: !isProcess })) {
1926
+ const error = `This module "${config.name}" cannot be used because the instance file needs rebuilding. Run on the command line with no arguments or the -rt argument to rebuild.`
1927
+ throw new Error(error)
1928
+ }
1929
+ try {
1930
+ config.load(template.template, template.instance)
1931
+ } catch( e ) {
1932
+ errorHandler(e)
1933
+ }
1934
+ }
1935
+
1936
+ config.addAssociationsFromTests(config.tests);
1937
+ }
1938
+
1939
+ createConfigExport = () => {
1940
+ const config = createConfig()
1941
+ initConfig(config)
1942
+ config.rebuild({ isModule: true })
1943
+ return config
1944
+ }
1945
+ moduleFromJSFile.exports = createConfigExport
1866
1946
  }
1867
1947
 
1868
1948
  }
@@ -1918,7 +1998,7 @@ module.exports = {
1918
1998
  w,
1919
1999
  // submitBug,
1920
2000
  ensureTestFile,
1921
- build,
2001
+ rebuildTemplate,
1922
2002
  processContext,
1923
2003
  processContexts,
1924
2004
  runTests,
@@ -1930,8 +2010,9 @@ module.exports = {
1930
2010
  Digraph,
1931
2011
  analyzeMetaData,
1932
2012
  processContextsB,
1933
- processInstance,
2013
+ loadInstance,
1934
2014
  gs,
1935
2015
  flattens,
1936
2016
  writeTest
1937
2017
  }
2018
+