theprogrammablemind_4wp 7.5.8 → 7.6.0

Sign up to get free protection for your applications and to get access to all the features.
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,10 +83,9 @@ 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
- const child = runtime.child_process.spawn(editor, [`${path}/expected.json`, `${path}/actual.json`], { stdio: 'inherit' })
62
- child.on('exit', function (e, code) {
63
- console.log('finished')
64
- })
86
+ // const child = runtime.child_process.spawn(editor, [`${path}/expected.json`, `${path}/actual.json`], { stdio: 'inherit' })
87
+ console.log(`${editor} ${path}/expected.json ${path}/actual.json`)
88
+ runtime.child_process.execSync(`${editor} ${path}/expected.json ${path}/actual.json`, {stdio: 'inherit'})
65
89
  }
66
90
  }
67
91
 
@@ -100,10 +124,24 @@ const asList = (context) => {
100
124
  }
101
125
  }
102
126
 
127
+ class ErrorReason extends Error {
128
+ constructor(context) {
129
+ super(JSON.stringify(context))
130
+ this.reason = context
131
+ }
132
+ }
133
+
103
134
  const setupArgs = (args, config, logs, hierarchy) => {
104
135
  config.setArgs(args)
105
- args.calls = new InitCalls()
136
+ args.calls = new InitCalls(args.isInstance ? `${args.isInstance}#${config.name}` : config.name)
137
+ if (global.theprogrammablemind && global.theprogrammablemind.loadForTesting) {
138
+ args.calls = new InitCalls(Object.keys(global.theprogrammablemind.loadForTesting)[0])
139
+ }
106
140
  args.km = (name) => config.getConfig(name)
141
+ args.api = (name) => config.getConfig(name).api
142
+ args.error = (context) => {
143
+ throw new ErrorReason(context)
144
+ }
107
145
  args.kms = config.getConfigs()
108
146
  args.config = config
109
147
  args.hierarchy = hierarchy
@@ -111,6 +149,7 @@ const setupArgs = (args, config, logs, hierarchy) => {
111
149
  args.listable = listable(hierarchy)
112
150
  args.asList = asList
113
151
  args.retry = () => { throw new RetryError() }
152
+ args.fragments = (query) => config.fragment(query)
114
153
  const scopedAsk = getAsk(config)
115
154
 
116
155
  const getAPI = (uuid) => {
@@ -130,7 +169,6 @@ const setupArgs = (args, config, logs, hierarchy) => {
130
169
  apis: getAPIs(uuid)
131
170
  }
132
171
  }
133
- args.motivation = (m) => config.addMotivation(m)
134
172
  args.breakOnSemantics = false
135
173
  args.theDebugger = {
136
174
  breakOnSemantics: (value) => args.breakOnSemantics = value
@@ -139,12 +177,15 @@ const setupArgs = (args, config, logs, hierarchy) => {
139
177
  args.g = (c) => config.getGenerators(logs).apply(args, c)
140
178
  args.gp = (c) => config.getGenerators(logs).apply(args, { ...c, paraphrase: true, isResponse: false, response: false})
141
179
  args.gr = (c) => config.getGenerators(logs).apply(args, { ...c, paraphrase: false, isResponse: true })
142
- args.e = (c) => config.getEvaluator(args.s, logs, c)
180
+ if (!logs) {
181
+ debugger
182
+ }
183
+ args.e = (c) => config.getEvaluator(args.s, args.calls, logs, c)
143
184
  args.log = (message) => logs.push(message)
144
- // config.getAddedArgs(args)
145
185
  args.gs = gs(args.g)
146
186
  args.gsp = gs(args.gp)
147
187
  args.gsr = gs(args.gr)
188
+ config.getAddedArgs(args)
148
189
  }
149
190
 
150
191
  const gs = (g) => (contexts, separator, lastSeparator) => {
@@ -272,7 +313,7 @@ const writeTestFile = (fn, tests) => {
272
313
  runtime.fs.writeFileSync(fn, stringify(tests, { space: 2 }), { encoding: 'utf8', flag: 'w+' })
273
314
  }
274
315
 
275
- const writeTest = (fn, query, objects, generated, paraphrases, responses, contexts, associations, metadata, config, saveDeveloper) => {
316
+ const writeTest = (fn, query, objects, generated, paraphrases, responses, contexts, associations, metadata, config, saveDeveloper, paraphrasesParenthesized, generatedParenthesized) => {
276
317
  let tests = []
277
318
  if (runtime.fs.existsSync(fn)) {
278
319
  tests = JSON.parse(runtime.fs.readFileSync(fn))
@@ -282,7 +323,18 @@ const writeTest = (fn, query, objects, generated, paraphrases, responses, contex
282
323
  }
283
324
  associations.sort()
284
325
  // tests[query] = sortJson({ paraphrases, responses, contexts, objects: convertToStable(objects), associations, metadata, config, developerTest: saveDeveloper }, { depth: 25 })
285
- results = sortJson({ query, paraphrases, responses, contexts, objects: convertToStable(objects), associations, metadata, config, developerTest: saveDeveloper }, { depth: 25 })
326
+ results = sortJson({
327
+ query,
328
+ paraphrases,
329
+ responses,
330
+ contexts,
331
+ objects: convertToStable(objects),
332
+ associations,
333
+ metadata,
334
+ config,
335
+ developerTest: saveDeveloper,
336
+ paraphrasesParenthesized,
337
+ generatedParenthesized }, { depth: 25 })
286
338
  let wasSet = false;
287
339
  tests.forEach( (test, index) => {
288
340
  if (test.query == query) {
@@ -339,16 +391,21 @@ const setupContexts = (rawContexts) => {
339
391
  return contexts
340
392
  }
341
393
 
342
- 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 }) => {
343
395
  // TODO fix this name to contextsPrime
344
396
  const contextsPrime = []
345
397
  const generatedPrime = []
346
398
  const paraphrasesPrime = []
399
+ const paraphrasesParenthesizedPrime = []
400
+ const generatedParenthesizedPrime = []
347
401
  const responsesPrime = []
348
402
  const contexts = setupContexts(json.contexts)
349
403
 
350
404
  const objects = config.get('objects')
351
- 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 }
406
+ if (!json.logs) {
407
+ json.logs = []
408
+ }
352
409
  setupArgs(args, config, json.logs, hierarchy)
353
410
  const toDo = [...contexts]
354
411
  args.insert = (context) => toDo.unshift(context)
@@ -356,28 +413,6 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
356
413
  config.debugLoops = commandLineArgs && commandLineArgs.debugLoops
357
414
  while (toDo.length > 0) {
358
415
  const context = toDo.shift()
359
- /*
360
- if (false && query) {
361
- if (config.wasChanged()) {
362
- // process contexts that overlap
363
- overlap = lastRange
364
- } else {
365
- config.watch()
366
- }
367
- if (overlap) {
368
- if (overlaps(overlap, context)) {
369
- // okay
370
- query = query.slice(overlap.end+1)
371
- data.utterance = query
372
- const json = await doWithRetries(retries, url, data)
373
- toDo = setupContexts(json.contexts).slice(1) // take off the start context
374
- }
375
- overlap = undefined
376
- }
377
- lastRange = context.range
378
- }
379
- */
380
-
381
416
  args.calls.next()
382
417
  let contextPrime = context
383
418
  context.topLevel = true
@@ -385,25 +420,40 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
385
420
  if (json.has_errors) {
386
421
  throw new Error('There are errors in the logs. Run with the -d flag and grep for Error')
387
422
  }
423
+ const generateParenthesized = isTest || (commandLineArgs && commandLineArgs.save)
388
424
  if (!config.get('skipSemantics')) {
389
- if (!config.doMotivations(args, context)) {
390
- const semantics = config.getSemantics(json.logs)
391
- try {
392
- contextPrime = semantics.apply(args, context)
393
- } catch( e ) {
394
- if (e.message == 'Maximum call stack size exceeded') {
395
- const mostCalled = semantics.getMostCalled()
396
- e.message += `\nThe most called semantic was:\nnotes: ${mostCalled.notes}\nmatch: ${mostCalled.matcher.toString()}\napply: ${mostCalled._apply.toString()}\n`
397
- }
398
- throw e;
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)
399
436
  }
437
+ contextPrime = semantics.apply(args, {
438
+ marker: 'error',
439
+ context,
440
+ text: e ? e.toString() : 'not available',
441
+ reason: e.reason,
442
+ error: e.stack || e.error
443
+ })
400
444
  }
401
445
  }
402
446
  if (contextPrime.controlRemove) {
403
447
  continue
404
448
  }
405
449
  let assumed = { isResponse: true };
406
- const generated = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
450
+ const generated = contextPrime.isResponse ? config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0] : ''
451
+ let generatedParenthesized = []
452
+ if (generateParenthesized) {
453
+ config.parenthesized = true
454
+ generatedParenthesized = contextPrime.isResponse ? config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0] : ''
455
+ config.parenthesized = false
456
+ }
407
457
  // assumed = { paraphrase: true, response: false };
408
458
  assumed = { paraphrase: true };
409
459
  args.g = (c) => config.getGenerators(json.logs).apply(args, c, assumed)
@@ -412,7 +462,16 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
412
462
  args.gs = gs(args.g)
413
463
  args.gsp = gs(args.gsp)
414
464
  args.gsr = gs(args.gr)
465
+ if (generateParenthesized) {
466
+ config.parenthesized = false
467
+ }
415
468
  const paraphrases = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
469
+ let paraphrasesParenthesized = []
470
+ if (generateParenthesized) {
471
+ config.parenthesized = true
472
+ paraphrasesParenthesized = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
473
+ config.parenthesized = false
474
+ }
416
475
  args.g = (c) => config.getGenerators(json.logs).apply(args, c)
417
476
  args.gp = (c) => config.getGenerators(json.logs).apply(args, {...c, paraphrase: true, isResponse: false, response: false })
418
477
  args.gr = (c) => config.getGenerators(json.logs).apply(args, {...c, paraphrase: false })
@@ -422,6 +481,10 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
422
481
  contextsPrime.push(contextPrime)
423
482
  generatedPrime.push(generated)
424
483
  paraphrasesPrime.push(paraphrases)
484
+ if (generateParenthesized) {
485
+ paraphrasesParenthesizedPrime.push(paraphrasesParenthesized)
486
+ generatedParenthesizedPrime.push(generatedParenthesized)
487
+ }
425
488
  if (contextPrime.isResponse) {
426
489
  responsesPrime.push(generated)
427
490
  } else {
@@ -431,7 +494,7 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
431
494
  // add results to processed list
432
495
  config.config.objects.processed = config.config.objects.processed || []
433
496
  config.config.objects.processed = config.config.objects.processed.slice(0, 5)
434
- config.config.objects.processed.unshift({ context: contextPrime, paraphrases: paraphrases, responses: responsesPrime })
497
+ config.config.objects.processed.unshift({ context: contextPrime, paraphrases: paraphrases, paraphrasesParenthesized, generatedParenthesized, responses: responsesPrime })
435
498
  } catch (e) {
436
499
  if (Array.isArray(e)) {
437
500
  e = {
@@ -451,7 +514,7 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
451
514
  throw e
452
515
  }
453
516
  }
454
- return { contextsPrime, generatedPrime, paraphrasesPrime, responsesPrime }
517
+ return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime }
455
518
  }
456
519
 
457
520
  const doWithRetries = async (n, url, queryParams, data) => {
@@ -473,17 +536,17 @@ const doWithRetries = async (n, url, queryParams, data) => {
473
536
  }
474
537
  if (result.status === 504) {
475
538
  if (n === 0) {
476
- throw `Error ${result.status} - ${result.statusText}`
539
+ throw new Error(`Error ${result.status} - ${result.statusText}`)
477
540
  } else {
478
541
  continue
479
542
  }
480
543
  }
481
544
  if (result.status >= 500 && result.status < 600) {
482
- throw `Error ${result.status} - ${result.statusText}.`
545
+ throw new Error(`Error ${result.status} - ${result.statusText}.`)
483
546
  } if (result.status >= 404) {
484
- throw `Error ${result.status} - ${result.statusText} - Trying it connect to ${url}`
547
+ throw new Error(`Error ${result.status} - ${result.statusText} - Trying it connect to ${url}`)
485
548
  } else {
486
- throw `Error ${result.status} - ${result.statusText}`
549
+ throw new Error(`Error ${result.status} - ${result.statusText}`)
487
550
  }
488
551
  }
489
552
  }
@@ -496,8 +559,11 @@ const setupProcessB = ({ config, initializer, allowDelta=false } = {}) => {
496
559
  // console.log('config', config)
497
560
  data.delta = config.delta()
498
561
  } else {
499
- Object.assign(data, config.config)
562
+ config.toData(data)
563
+ // Object.assign(data, config.config)
500
564
  }
565
+
566
+ // config.toServer(data)
501
567
 
502
568
  if (data.namespaces) {
503
569
  for (const uuid of Object.keys(data.namespaces)) {
@@ -520,10 +586,22 @@ const setupProcessB = ({ config, initializer, allowDelta=false } = {}) => {
520
586
  }
521
587
  }
522
588
 
523
- // instance template
524
- const processInstance = (config, instance) => {
589
+ // instance template loadTemplate
590
+ const loadInstance = (config, instance) => {
525
591
  const transitoryMode = global.transitoryMode
526
592
  global.transitoryMode = false
593
+
594
+ if (instance && (instance.associations || instance.learned_contextual_priorities)) {
595
+ if (!config.config.retrain) {
596
+ if (instance.associations) {
597
+ config.addAssociations(instance.associations)
598
+ }
599
+ if (instance.learned_contextual_priorities && instance.learned_contextual_priorities.length > 0) {
600
+ config.addPriorities(instance.learned_contextual_priorities)
601
+ }
602
+ }
603
+ }
604
+
527
605
  const { /* data, generators, semantics, */ hierarchy } = setupProcessB({ config })
528
606
  // for (const results of (instance.resultss || [])) {
529
607
  for (const i in (instance.resultss || [])) {
@@ -531,15 +609,21 @@ const processInstance = (config, instance) => {
531
609
  if (results.extraConfig) {
532
610
  // config.addInternal(results, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false)
533
611
  // config.addInternal(config.template.queries[i], { handleCalculatedProps: true } )
534
- config.addInternal(instance.template.queries[i], { handleCalculatedProps: true } )
612
+ config.addInternal(instance.template.queries[i], { addFirst: true, handleCalculatedProps: true } )
535
613
  } else {
536
- processContextsB({ config, hierarchy, json: results/*, generators, semantics */, commandLineArgs: {} })
614
+ if (results.skipSemantics) {
615
+ config.config.skipSemantics = results.skipSemantics
616
+ }
617
+ processContextsB({ config, hierarchy, json: results/*, generators, semantics */, commandLineArgs: {}, isInstance: `instance${i}`, instance: instance.queries[i] })
618
+ if (results.skipSemantics) {
619
+ config.config.skipSemantics = null
620
+ }
537
621
  }
538
622
  }
539
623
  global.transitoryMode = transitoryMode
540
624
  }
541
625
 
542
- const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isTest, saveDeveloper, testConfig, testsFN, errorHandler = defaultErrorHandler } = {}) => {
626
+ const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = defaultErrorHandler } = {}) => {
543
627
  if (credentials) {
544
628
  config.server(credentials.server, credentials.key)
545
629
  }
@@ -553,7 +637,6 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
553
637
  if (writeTests) {
554
638
  config.rebuild()
555
639
  const objects = getObjects(config.config.objects)(config.uuid)
556
- config.beforeQuery({ query, isModule: false, objects })
557
640
  }
558
641
  } catch(error) {
559
642
  throw error
@@ -561,7 +644,10 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
561
644
 
562
645
  let { data, /* generators, semantics, */ hierarchy } = setupProcessB({ config, initializer, allowDelta: true })
563
646
  if (commandLineArgs && commandLineArgs.checkForLoop) {
564
- data.checkForLoop = true
647
+ data.checkForLoop = commandLineArgs.checkForLoop
648
+ }
649
+ if (rebuildingTemplate) {
650
+ data.errors_ignore_contextual_priorities_non_existant_ops = true
565
651
  }
566
652
  let queries = query.split('\\n')
567
653
 
@@ -578,6 +664,8 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
578
664
  contexts: [],
579
665
  generated: [],
580
666
  paraphrases: [],
667
+ paraphrasesParenthesized: [],
668
+ generatedParenthesized: [],
581
669
  responses: [],
582
670
  associations: [],
583
671
  }
@@ -613,9 +701,10 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
613
701
  if (json.status !== 200) {
614
702
  throw json
615
703
  } else {
616
- const { contextsPrime, generatedPrime, paraphrasesPrime, responsesPrime } =
704
+ const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
617
705
  processContextsB({ isTest, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
618
706
  response.associations = json.associations
707
+ response.learned_contextual_priorities = json.learned_contextual_priorities
619
708
  response.hierarchy = json.hierarchy
620
709
  response.load_cache_time += json.load_cache_time
621
710
  appendNoDups(response.logs, json.logs)
@@ -626,10 +715,13 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
626
715
  response.times += json.times
627
716
  response.trace = response.trace.concat(json.trace)
628
717
  response.version = json.version
718
+ response.explain_priorities = json.explain_priorities
629
719
 
630
720
  response.contexts = response.contexts.concat(contextsPrime)
631
721
  response.generated = response.generated.concat(generatedPrime)
632
722
  response.paraphrases = response.paraphrases.concat(paraphrasesPrime)
723
+ response.paraphrasesParenthesized = response.paraphrasesParenthesized.concat(paraphrasesParenthesizedPrime)
724
+ response.generatedParenthesized = response.generatedParenthesized.concat(generatedParenthesizedPrime)
633
725
  response.responses = response.responses.concat(responsesPrime)
634
726
  queries = queries.slice(1)
635
727
  }
@@ -637,13 +729,18 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
637
729
 
638
730
  if (writeTests) {
639
731
  const actual_config = getConfigForTest(config, testConfig)
640
- writeTest(testsFN, query, config.config.objects, response.generated, response.paraphrases, response.responses, response.contexts, response.associations, response.metadata, actual_config, saveDeveloper)
732
+ const saveObjects = {...config.config.objects}
733
+ saveObjects.nameToUUID = {}
734
+ for (let km of config.configs) {
735
+ saveObjects.nameToUUID[km.name] = km.uuid
736
+ }
737
+ writeTest(testsFN, query, saveObjects, response.generated, response.paraphrases, response.responses, response.contexts, response.associations, response.metadata, actual_config, saveDeveloper, response.paraphrasesParenthesized, response.generatedParenthesized)
641
738
  }
642
739
 
643
740
  return response
644
741
  } catch(error) {
645
742
  error.query = query
646
- throw error
743
+ errorHandler(error)
647
744
  }
648
745
  }
649
746
 
@@ -677,11 +774,13 @@ const getConfigForTest = (config, testConfig) => {
677
774
  return configForTest
678
775
  }
679
776
 
680
- const runTest = async (config, expected, { verbose, afterTest, testConfig, debug }) => {
777
+ const runTest = async (config, expected, { args, verbose, testConfig, debug }) => {
681
778
  const test = expected.query
682
779
  // initialize in between test so state is not preserved since the test was adding without state
683
780
  config.rebuild()
684
- config.addAssociationsFromTests(config.tests)
781
+ if (!args.dontAddAssociations) {
782
+ config.addAssociationsFromTests(config.tests)
783
+ }
685
784
  // config.addAssocationsFromTests(
686
785
  const errorHandler = (error) => {
687
786
  if (error.metadata) {
@@ -700,8 +799,6 @@ const runTest = async (config, expected, { verbose, afterTest, testConfig, debug
700
799
  objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
701
800
  testConfigName = testConfig.testModuleName
702
801
  }
703
- config.beforeQuery({ query: test, isModule: false, objects })
704
- // config.resetMotivations()
705
802
  try {
706
803
  const result = await _process(config, test, { errorHandler, isTest: true })
707
804
  result.query = test
@@ -716,66 +813,48 @@ const runTest = async (config, expected, { verbose, afterTest, testConfig, debug
716
813
  lines.log()
717
814
  }
718
815
  const expected_objects = sortJson(convertToStable(expected.objects), { depth: 25 })
816
+ delete expected_objects.nameToUUID
719
817
  const actual_objects = sortJson(convertToStable(config.config.objects), { depth: 25 })
720
818
  const failed_paraphrases = !matching(result.paraphrases, expected.paraphrases)
819
+ let failed_paraphrasesParenthesized = !matching(result.paraphrasesParenthesized, expected.paraphrasesParenthesized)
820
+ let failed_generatedParenthesized = !matching(result.generatedParenthesized, expected.generatedParenthesized)
821
+ // TODO fix the naming conventions: camelcase + use actual instead of result
721
822
  const failed_responses = !matching(result.responses, expected.responses)
722
823
  const failed_contexts = !matching(result.contexts, expected.contexts)
723
824
  const failed_objects = !matching(actual_objects, expected_objects)
724
825
 
725
- const pickEm = (getObjects) => {
726
- const picked = {}
727
- for (let prop of (testConfig.check || [])) {
728
- if (prop.km) {
729
- c = config.getConfig(prop.km)
730
- o = getObjects(prop.km)
731
- picked[prop.km] = {}
732
- for (let p of c.testConfig.check) {
733
- if (p.km) {
734
- continue
735
- }
736
- picked[p] = o[p]
737
- }
738
- } else {
739
- picked[prop] = getObjects(testConfigName)[prop]
740
- }
741
- }
742
- return picked
826
+ if (args.testNoParenthesized) {
827
+ failed_paraphrasesParenthesized = false
828
+ failed_generatedParenthesized = false
743
829
  }
830
+
831
+ const pickedResultContexts = result.contexts.map(pickContext(testConfig))
832
+ const pickedExpectedContexts = expected.contexts.map(pickContext(testConfig))
833
+ const failedCheckedContexts = !matching(pickedResultContexts, pickedExpectedContexts)
834
+
744
835
  const expectedGetObjects = (name) => {
745
836
  if (!name) {
746
837
  name = config.name
747
838
  }
748
- return expected.objects.namespaced[expected.objects.nameToUUID[name]]
839
+ return expected.objects.namespaced[expected.objects.nameToUUID[name]] || {}
749
840
  }
750
- const expected_checked = sortJson(pickEm(expectedGetObjects), { depth: 25 })
841
+ const expected_checked = sortJson(pickObjects(testConfig, expectedGetObjects(testConfigName)), { depth: 25 })
751
842
  const actualGetObjects = (name) => {
752
843
  if (!name) {
753
844
  name = config.name
754
845
  }
755
846
  const km = config.configs.find( (km) => km.name == name )
756
- return config.config.objects.namespaced[km.uuid]
847
+ return config.config.objects.namespaced[km.uuid] || {}
757
848
  }
758
- const actual_checked = sortJson(pickEm(actualGetObjects), { depth: 25 })
849
+ const actual_checked = sortJson(pickObjects(testConfig, actualGetObjects(testConfigName)), { depth: 25 })
759
850
  const failed_checked = !matching(actual_objects, expected_objects)
760
851
 
761
852
  const failed_checks = !matching(actual_objects, expected_objects)
853
+ const failed_checked_objects = !matching(actual_checked, expected_checked)
762
854
  const actual_config = sortJson(convertToStable(getConfigForTest(config, testConfig)), { depth: 25 })
763
855
  const expected_config = sortJson(convertToStable(expected.config), { depth: 25 })
764
856
  const failed_config = !matching(actual_config, expected_config)
765
- let failed = failed_paraphrases || failed_responses || failed_contexts || failed_objects || failed_config || failed_checked
766
- if (!failed) {
767
- if (config.afterTest) {
768
- failed = config.afterTest({ query: test, expected, actual: result, config })
769
- if (failed) {
770
- return {
771
- utterance: test,
772
- errorFromAfterTest: failed,
773
- expected: { responses: expected.responses, paraphrases: expected.paraphrases, results: expected.contexts, checked: expected_checked, objects: expected_objects, config: expected.config },
774
- actual: { responses: result.responses, paraphrases: result.paraphrases, results: result.contexts, checked: actual_checked, objects: actual_objects, config: actual_config }
775
- }
776
- }
777
- }
778
- }
857
+ let failed = failed_checked_objects || failed_paraphrases || failed_paraphrasesParenthesized || failed_generatedParenthesized || failed_responses || failed_contexts || failed_objects || failed_config || failed_checked || failedCheckedContexts
779
858
 
780
859
  if (expected.metadata && result.metadata && failed) {
781
860
  const priorities = analyzeMetaData(expected.metadata, result.metadata)
@@ -787,8 +866,28 @@ const runTest = async (config, expected, { verbose, afterTest, testConfig, debug
787
866
  if (failed) {
788
867
  return {
789
868
  utterance: test,
790
- expected: { responses: expected.responses, paraphrases: expected.paraphrases, results: expected.contexts, checked: expected_checked, objects: expected_objects, config: expected.config },
791
- actual: { responses: result.responses, paraphrases: result.paraphrases, results: result.contexts, checked: actual_checked, objects: actual_objects, config: actual_config }
869
+ expected: {
870
+ responses: expected.responses,
871
+ paraphrases: expected.paraphrases,
872
+ paraphrasesParenthesized: expected.paraphrasesParenthesized,
873
+ generatedParenthesized: expected.generatedParenthesized,
874
+ results: expected.contexts,
875
+ checked: expected_checked,
876
+ checkedContexts: pickedExpectedContexts,
877
+ objects: expected_objects,
878
+ config: expected.config
879
+ },
880
+ actual: {
881
+ responses: result.responses,
882
+ paraphrases: result.paraphrases,
883
+ paraphrasesParenthesized: result.paraphrasesParenthesized,
884
+ generatedParenthesized: result.generatedParenthesized,
885
+ results: result.contexts,
886
+ checked: actual_checked,
887
+ checkedContexts: pickedResultContexts,
888
+ objects: actual_objects,
889
+ config: actual_config
890
+ }
792
891
  }
793
892
  }
794
893
  } catch(error) {
@@ -825,20 +924,16 @@ const runTestsHelper = async (config, tests, failed, juicyBits) => {
825
924
 
826
925
  const runTests = async (config, testFile, juicyBits) => {
827
926
  const tests = JSON.parse(runtime.fs.readFileSync(testFile))
828
- config.beforeTests()
829
927
  if (juicyBits.verbose) {
830
928
  console.log('\n', testFile, '-----------------------------------------------', '\n')
831
929
  }
832
930
  const v = await runTestsHelper(config, [...tests], [], juicyBits)
833
- config.afterTests()
834
931
  return v
835
932
  }
836
933
 
837
934
  const saveTest = async (testFile, config, test, expected, testConfig, saveDeveloper) => {
838
935
  config.rebuild()
839
936
  const objects = getObjects(config.config.objects)(config.uuid)
840
- //config.resetMotivations()
841
- config.beforeQuery({ query: test, isModule: false, objects })
842
937
  console.log(test)
843
938
  const result = await _process(config, test, { isTest: true })
844
939
  // const actualObjects = config.config.objects
@@ -850,7 +945,7 @@ const saveTest = async (testFile, config, test, expected, testConfig, saveDevelo
850
945
  for (let km of config.configs) {
851
946
  saveObjects.nameToUUID[km.name] = km.uuid
852
947
  }
853
- writeTest(testFile, test, saveObjects, result.generated, result.paraphrases, result.responses, result.contexts, result.associations, result.metadata, actualConfig, saveDeveloper)
948
+ writeTest(testFile, test, saveObjects, result.generated, result.paraphrases, result.responses, result.contexts, result.associations, result.metadata, actualConfig, saveDeveloper, result.paraphrasesParenthesized, result.generatedParenthesized)
854
949
  }
855
950
 
856
951
  const saveTestsHelper = async (testFile, config, tests, todo, testConfig, saveDeveloper) => {
@@ -1020,10 +1115,11 @@ const defaultErrorHandler = async (error) => {
1020
1115
  doErrorExit = true
1021
1116
  }
1022
1117
 
1023
- if (doErrorExit) {
1118
+ if (typeof runtime.process.exit == 'function' && doErrorExit) {
1024
1119
  runtime.process.exit(-1)
1025
1120
  }
1026
- // throw error
1121
+
1122
+ throw error
1027
1123
  }
1028
1124
 
1029
1125
  const defaultInnerProcess = (config, errorHandler, responses) => {
@@ -1033,6 +1129,13 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1033
1129
  }
1034
1130
  console.log("KM's loaded", config.configs.map((c) => c.name))
1035
1131
  console.log('This is the global objects from running semantics:\n', config.objects)
1132
+ if (!_.isEmpty(responses.learned_contextual_priorities)) {
1133
+ console.log('\nThe learned contextual priorties are :\n')
1134
+ for (const lcp of responses.learned_contextual_priorities) {
1135
+ console.log(` ${JSON.stringify(lcp)},\n`)
1136
+ }
1137
+ console.log("\n")
1138
+ }
1036
1139
  if (responses.logs) {
1037
1140
  console.log('Logs')
1038
1141
  responses.logs.forEach((log) => console.log(` ${log}`))
@@ -1044,6 +1147,50 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1044
1147
  } else {
1045
1148
  console.log('objects', runtime.util.inspect(config.get('objects'), { depth: Infinity, sorted: true }))
1046
1149
  }
1150
+
1151
+ const pickEm = () => {
1152
+ const picked = {}
1153
+ const namespaced = config.get('objects')['namespaced']
1154
+ for (let prop of getConfig_getObjectCheck(config.testConfig)) {
1155
+ if (prop.km) {
1156
+ /*
1157
+ const objects = namespaced[prop.km]]
1158
+ picked[prop.km] = {}
1159
+ for (let p of c.testConfig.check) {
1160
+ if (p.km) {
1161
+ continue
1162
+ }
1163
+ picked[p] = objects[p]
1164
+ }
1165
+ */
1166
+ console.log('TODO implement this if needed')
1167
+ } else {
1168
+ const objects = namespaced[config.uuid]
1169
+ picked[prop] = objects[prop]
1170
+ }
1171
+ }
1172
+ return picked
1173
+ }
1174
+
1175
+ if (responses.explain_priorities) {
1176
+ console.log("Explain Priorities")
1177
+ for ([inputss, outpus, reason] of responses.explain_priorities) {
1178
+ console.log(` ${JSON.stringify(inputss)} reason: ${reason}`)
1179
+ }
1180
+ }
1181
+ const objects = config.get('objects').namespaced[config.uuid]
1182
+ const picked = sortJson(pickObjects(config.testConfig, objects), { depth: 25 })
1183
+ if (!_.isEmpty(picked)) {
1184
+ console.log('--- Object showing only the checked values ---')
1185
+ console.log(JSON.stringify(picked, null, 2))
1186
+ }
1187
+
1188
+ const pickedResultContexts = responses.contexts.map(pickContext(config.testConfig))
1189
+ if (pickedResultContexts.some( (context) => Object.keys(context).length > 0 )) {
1190
+ console.log('--- Contexts showing only the checked values ---')
1191
+ console.log(JSON.stringify(pickedResultContexts, null, 2))
1192
+ }
1193
+
1047
1194
  console.log('--- The contexts are ----------')
1048
1195
  console.log(JSON.stringify(sortJson(responses.contexts, { depth: 25 }), null, 2))
1049
1196
  console.log('')
@@ -1084,37 +1231,14 @@ const defaultProcess = ({ config, errorHandler }) => async (promise) => {
1084
1231
  }
1085
1232
  }
1086
1233
 
1087
- /*
1088
- const kmFileTemplate = (kmBaseName, kmName) =>
1089
- `const entodicton = require('entodicton')
1090
- const base = require('./${kmBaseName}').copy()
1091
- const ${kmName}_tests = require('./${kmName}.test.json')
1092
- const ${kmName}_instance = require('./${kmBaseName}.${kmName}.instance.json')
1093
-
1094
- const config = new entodicton.Config({ name: '${kmName}' })
1095
- config.add(base)
1096
- kirk_instance.base = '${kmBaseName}'
1097
- config.load(${kmName}_instance)
1098
-
1099
- entodicton.knowledgeModule( {
1100
- module,
1101
- description: '${kmName} related concepts',
1102
- section,
1103
- config,
1104
- test: {
1105
- name: './${kmName}.test.json',
1106
- contents: ${kmName}_tests
1107
- },
1108
- })
1109
- `
1110
- */
1111
-
1112
- const build = async ({ config, target, template, errorHandler = defaultErrorHandler }) => {
1234
+ // builtTemplate saveInstance
1235
+ const rebuildTemplate = async ({ config, target, template, errorHandler = defaultErrorHandler }) => {
1113
1236
  const accumulators = {
1114
1237
  resultss: [],
1115
1238
  fragments: [],
1116
1239
  semantics: [],
1117
1240
  associations: [],
1241
+ learned_contextual_priorities: [],
1118
1242
  }
1119
1243
  const looper = async (queries) => {
1120
1244
  if (queries.length === 0) {
@@ -1133,8 +1257,6 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1133
1257
  if (property == 'fragments') {
1134
1258
  global.transitoryMode = true
1135
1259
  }
1136
- // greg32
1137
- // config.addInternal( query )
1138
1260
  if (hierarchy) {
1139
1261
  for (let edge of hierarchy) {
1140
1262
  if (Array.isArray(edge)) {
@@ -1144,25 +1266,28 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1144
1266
  }
1145
1267
  }
1146
1268
  }
1147
-
1148
1269
  try {
1149
- const results = await _process(config, query.query, {initializer})
1270
+ const results = await _process(config, query.query, {initializer, rebuildingTemplate: true})
1150
1271
  if (config.config.debug) {
1151
1272
  // TODO pass in the error handler like the other ones
1152
1273
  defaultInnerProcess(config, defaultErrorHandler, results)
1153
1274
  }
1154
1275
  if (results.contexts.length > 1) {
1155
- console.log(`query ${query.query}. There is ${results.contexts.length} contexts in the results. Make sure its producing the results that you expect.`)
1276
+ console.log(`query "${query.query}". There is ${results.contexts.length} contexts in the results. Make sure its producing the results that you expect.`)
1277
+ } else if (results.paraphrases[0] != query.query) {
1278
+ console.log(`query "${query.query}". The paraphrase is different from the query "${results.paraphrases[0]}".`)
1156
1279
  } else {
1157
1280
  console.log(`query ${query.query}`)
1158
1281
  }
1159
1282
  global.transitoryMode = transitoryMode
1160
1283
  config.config.skipSemantics = null
1161
1284
  results.query = query.query
1285
+ results.skipSemantics = skipSemantics
1162
1286
  results.development = query.development
1163
1287
  results.key = { query: query.query, hierarchy }
1164
1288
  accumulators[property].push(results)
1165
1289
  accumulators.associations = accumulators.associations.concat(results.associations)
1290
+ accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
1166
1291
  await looper(queries)
1167
1292
  } catch(e) {
1168
1293
  const error = { errors: [e], query: query.query };
@@ -1174,6 +1299,12 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1174
1299
  // it will just get added to the config
1175
1300
  const extraConfig = queryOrExtraConfig
1176
1301
  console.log('config', extraConfig)
1302
+ try {
1303
+ config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true } )
1304
+ } catch ( e ) {
1305
+ const where = extraConfig.where ? ` ${extraConfig.where}` : ''
1306
+ throw new Error(`Error processing extra config${where}: ${e.stack}}`)
1307
+ }
1177
1308
  accumulators[property].push({ extraConfig: true, ...extraConfig })
1178
1309
  await looper(queries)
1179
1310
  }
@@ -1201,6 +1332,7 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1201
1332
  delete result.version
1202
1333
  result.hierarchy.sort()
1203
1334
  stabilizeAssociations(result.associations)
1335
+ result.learned_contextual_priorities = safeNoDups(result.learned_contextual_priorities)
1204
1336
  }
1205
1337
  }
1206
1338
  }
@@ -1221,14 +1353,14 @@ const build = async ({ config, target, template, errorHandler = defaultErrorHand
1221
1353
 
1222
1354
  const toProperties = (queryStringOrProperties) => {
1223
1355
  if (typeof queryStringOrProperties == 'string') {
1224
- return { query: queryStringOrProperties}
1356
+ return { query: queryStringOrProperties }
1225
1357
  } else {
1226
1358
  return queryStringOrProperties
1227
1359
  }
1228
1360
  }
1229
1361
  let todo = []
1230
- todo = todo.concat((template.initializers || []).map((query) => { return { initializer: true, property: 'resultss', query, skipSemantics: false } }))
1231
- todo = todo.concat((template.queries || []).map((query) => { return { property: 'resultss', query, skipSemantics: false } }))
1362
+ todo = todo.concat((template.initializers || []).map((query) => { return { initializer: true, property: 'resultss', query, skipSemantics: false || query.skipSemantics } }))
1363
+ todo = todo.concat((template.queries || []).map((query) => { return { property: 'resultss', query, skipSemantics: false || query.skipSemantics} }))
1232
1364
  todo = todo.concat((template.fragments || []).map((query) => { return Object.assign({}, toProperties(query), { property: 'fragments', skipSemantics: false }) }))
1233
1365
  todo = todo.concat((template.semantics || []).map((definition) => { return { property: 'semantics', query: `${definition.from}\n${definition.to}`, skipSemantics: true } }))
1234
1366
  await looper(Object.assign([], todo))
@@ -1238,114 +1370,86 @@ const knowledgeModule = async ({
1238
1370
  module: moduleFromJSFile,
1239
1371
  description,
1240
1372
  section,
1241
- config,
1373
+ // config, createConfig,
1374
+ createConfig,
1375
+ newWay,
1242
1376
  demo,
1243
1377
  test,
1244
1378
  template,
1245
1379
  errorHandler = defaultErrorHandler,
1246
1380
  process: processResults = defaultProcess,
1247
1381
  stopAtFirstFailure = true,
1248
- beforeQuery = () => {},
1249
- beforeTests = () => {},
1250
- afterTests = () => {},
1251
- beforeTest = () => {},
1252
- afterTest = () => {}
1382
+ ...rest
1253
1383
  } = {}) => {
1254
1384
 
1255
- config.beforeQuery = beforeQuery
1256
- config.beforeTests = beforeTests
1257
- config.afterTests = afterTests
1258
- config.beforeTest = beforeTest
1259
- config.afterTest = afterTest
1385
+ const unknownArgs = Object.keys(rest)
1386
+ if (unknownArgs.length > 0) {
1387
+ throw new Error(`Unknown arguments to knowledgeModule: ${unknownArgs.join()}`)
1388
+ }
1260
1389
 
1261
1390
  const testConfig = test
1262
1391
 
1263
1392
  if (!moduleFromJSFile) {
1264
- throw "'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."
1265
- }
1266
- if (!config) {
1267
- throw "'config' is a required parameter. The value should the config that defines the knowledge module."
1393
+ 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.")
1268
1394
  }
1269
- if (!config.name) {
1270
- throw "config must have 'name' set to the knowledge module name."
1395
+ // if (!config && !createConfig) {
1396
+ if (!createConfig) {
1397
+ throw new Error("'config' or 'createConfig' is a required parameter. The value should the config that defines the knowledge module.")
1271
1398
  }
1272
1399
  if (!description) {
1273
- throw "'description' is a required parameter. The value should the description of the knowledge module."
1400
+ throw new Error("'description' is a required parameter. The value should the description of the knowledge module.")
1274
1401
  }
1275
1402
  if (!test) {
1276
- throw "'test' is a required parameter. The value should the path to the file used to store the tests of the knowledge module and the contents of the file in the form { name: <filePath>, contexts: <json> }."
1403
+ throw new Error("'test' is a required parameter. The value should the path to the file used to store the tests of the knowledge module and the contents of the file in the form { name: <filePath>, contexts: <json> }.")
1277
1404
  }
1278
1405
 
1279
1406
  const isProcess = require.main === moduleFromJSFile
1280
- let loadForTesting = false
1281
- if (global.theprogrammablemind) {
1282
- if (global.theprogrammablemind.loadForTesting[config.name]) {
1283
- loadForTesting = true
1407
+
1408
+ const setupConfig = (config) => {
1409
+ if (!config.name) {
1410
+ throw new Error("config must have 'name' set to the knowledge module name.")
1284
1411
  }
1285
- }
1286
1412
 
1287
- // remove test only stuff
1288
- if (!isProcess && !loadForTesting) {
1289
- config.config.operators = config.config.operators.filter( (operator) => {
1290
- if (operator.development) {
1291
- return false
1292
- } else {
1293
- return true
1294
- }
1295
- })
1296
- config.config.bridges = config.config.bridges.filter( (bridge) => {
1297
- if (bridge.development) {
1298
- return false
1299
- } else {
1300
- return true
1413
+ config.description = description
1414
+ if (typeof test === 'object') {
1415
+ if (test.contents) {
1416
+ config.tests = test.contents
1417
+ test = test.name
1301
1418
  }
1302
- })
1303
- }
1304
-
1305
- let module
1306
- if (_.isFunction(moduleFromJSFile)) {
1307
- module = moduleFromJSFile
1308
- } else {
1309
- module = () => {
1310
- config.rebuild({ isModule: true })
1311
- moduleFromJSFile.exports = config
1312
- }
1313
- }
1314
- processResults = processResults({ config, errorHandler })
1315
- config.description = description
1316
- config.demo = demo
1317
- if (typeof test === 'object') {
1318
- if (test.contents) {
1319
- config.tests = test.contents
1320
- test = test.name
1321
- }
1322
- } else {
1323
- if (runtime.fs && runtime.fs.existsSync(test)) {
1324
- config.tests = JSON.parse(runtime.fs.readFileSync(test))
1325
1419
  } else {
1326
- config.tests = {}
1327
- }
1328
- }
1329
- config.setTestConfig(testConfig)
1330
-
1331
- if (!isProcess) {
1332
- if (template) {
1333
- if (config.needsRebuild(template.template, template.instance)) {
1334
- throw `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.`
1420
+ if (runtime.fs && runtime.fs.existsSync(test)) {
1421
+ config.tests = JSON.parse(runtime.fs.readFileSync(test))
1422
+ } else {
1423
+ config.tests = []
1335
1424
  }
1336
- config.load(template.template, template.instance)
1337
1425
  }
1426
+ config.setTestConfig(testConfig)
1338
1427
  }
1428
+
1429
+
1339
1430
  if (isProcess) {
1431
+ const config = createConfig()
1432
+ setupConfig(config)
1433
+ processResults = processResults({ config, errorHandler })
1340
1434
  // setup();
1341
1435
  const parser = new runtime.ArgumentParser({
1342
1436
  description: 'Entodicton knowledge module'
1343
1437
  })
1344
1438
 
1439
+ 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]]\''
1440
+ 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]]\''
1441
+ 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]]\''
1442
+ 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}\''
1443
+ 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\''
1444
+ 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]))\''
1445
+
1446
+
1345
1447
  parser.add_argument('-tmn', '--testModuleName', { help: 'When running tests instead of using the current modules tests use the specified modules tests' })
1346
1448
  parser.add_argument('-t', '--test', { action: 'store_true', help: 'Run the tests. Create tests by running with the --query + --save flag' })
1347
1449
  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' })
1450
+ // parser.add_argument('-ttr', '--testToRun', { help: 'Only the specified test will be run' })
1348
1451
  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' })
1452
+ parser.add_argument('-tnp', '--testNoParenthesized', { action: 'store_true', help: 'Don\' check parenthesized differences for the tests' })
1349
1453
  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' })
1350
1454
  // 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.' })
1351
1455
  parser.add_argument('-rt', '--rebuildTemplate', { action: 'store_true', help: 'Force a template rebuild' })
@@ -1353,45 +1457,84 @@ const knowledgeModule = async ({
1353
1457
  parser.add_argument('-i', '--info', { action: 'store_true', help: 'Print meta-data for the module' })
1354
1458
  parser.add_argument('-v', '--vimdiff', { action: 'store_true', help: 'For failures run vimdiff' })
1355
1459
  parser.add_argument('-g', '--greg', { action: 'store_true', help: 'Set the server to be localhost so I can debug stuff' })
1356
- parser.add_argument('-cl', '--checkForLoop', { action: 'store_true', help: 'Check for loops in the priorities' })
1460
+ 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]]' })
1357
1461
  parser.add_argument('-r', '--retrain', { action: 'store_true', help: 'Get the server to retrain the neural nets' })
1358
1462
  parser.add_argument('-q', '--query', { help: 'Run the specified query' })
1359
1463
  parser.add_argument('-ip ', '--server', { help: 'Server to run against' })
1360
1464
  parser.add_argument('-qp ', '--queryParams', { help: 'Query params for the server call' })
1361
1465
  parser.add_argument('-dt', '--deleteTest', { help: 'Delete the specified query from the tests file.' })
1466
+ parser.add_argument('--parenthesized', { action: 'store_true', help: 'Show the generated phrases with parenthesis.' })
1362
1467
  parser.add_argument('-c', '--clean', { help: 'Remove data from the test files. a === association' })
1363
1468
  parser.add_argument('-od', '--objectDiff', { action: 'store_true', help: 'When showing the objects use a colour diff' })
1364
1469
  parser.add_argument('-daa', '--dontAddAssociations', { action: 'store_true', help: 'Do not add associations from the tests.' })
1365
1470
  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' })
1366
1471
  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.' })
1367
1472
  parser.add_argument('-sd', '--saveDeveloper', { action: 'store_true', help: 'Same as -s but the query will not show up in the info command.' })
1368
- 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' })
1369
1473
  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 '})
1370
1474
  parser.add_argument('-d', '--debug', { action: 'store_true', help: 'When running with the --debug flag this set the debug flag in the config' })
1371
- parser.add_argument('-da', '--debugAssociation', { help: 'When running with the --debugAssociation flag the debugging will break when the specified association is added to the config' })
1372
- parser.add_argument('-dh', '--debugHierarchy', { help: 'When running with the --debugHierarchy flag the debugging will break when the specified child-parent pair is added to the config for the main config. Set DEBUG_HIERARCHY to debug any config loaded. For example DEBUG_HIERARCHY=\'["cat", "mammel"]\'' })
1373
- parser.add_argument('-db', '--debugBridge', { help: 'When running with the --debugBridge flag the debugging will break when the specified bridge is added to the config for the main config. Set DEBUG_BRIDGE to debug any config loaded. For example DEBUG_BRIDGE=\'id/level\'' })
1374
- parser.add_argument('-do', '--debugOperator', { help: 'When running with the --debugOperator flag the debugging will break when the specified operator is added to the config for the main config. Set DEBUG_OPERATOR to debug any config loaded. For example DEBUG_OPERATOR=\'([operator] ([arg]))\'' })
1475
+ parser.add_argument('-da', '--debugAssociation', { action: 'store_true', help: helpDebugAssociation })
1476
+ parser.add_argument('-dh', '--debugHierarchy', { action: 'store_true', help: helpDebugHierarchy })
1477
+ parser.add_argument('-dp', '--debugPriority', { action: 'store_true', help: helpDebugPriority })
1478
+ parser.add_argument('-dcp', '--debugContextualPriority', { action: 'store_true', help: helpDebugContextualPriority })
1479
+ parser.add_argument('-db', '--debugBridge', { action: 'store_true', help: helpDebugBridge })
1480
+ parser.add_argument('-do', '--debugOperator', { action: 'store_true', help: helpDebugOperator })
1481
+ 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"})
1482
+ 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' })
1375
1483
 
1376
1484
  const args = parser.parse_args()
1377
1485
  args.count = args.count || 1
1378
1486
 
1487
+ if (args.parenthesized) {
1488
+ config.parenthesized = true
1489
+ }
1490
+ if (args.checkForLoop) {
1491
+ try {
1492
+ args.checkForLoop = JSON.parse(args.checkForLoop)
1493
+ const isKey = (what) => {
1494
+ if (!Array.isArray(what)) {
1495
+ return false
1496
+ }
1497
+ if (what.length !== 2) {
1498
+ return false
1499
+ }
1500
+ if (!typeof what[0] == 'string') {
1501
+ return false
1502
+ }
1503
+ if (!typeof what[1] == 'number') {
1504
+ return false
1505
+ }
1506
+ return true
1507
+ }
1508
+ if (!Array.isArray(args.checkForLoop) || args.checkForLoop.some((value) => !isKey(value))) {
1509
+ throw new Error(`Error for the checkForLoop argument. Expected a JSON array of operator keys of the form "[<id>, <level>]"`)
1510
+ }
1511
+ } catch( e ) {
1512
+ throw new Error(`Error parsing JSON of the checkForLoop argument. ${e}`)
1513
+ }
1514
+ } else {
1515
+ if (process.argv.includes('--checkForLoop') || process.argv.includes('-cl')) {
1516
+ args.checkForLoop = true
1517
+ }
1518
+ }
1379
1519
  if (args.debugAssociation) {
1380
- global.entodictonDebugAssociation = JSON.parse(args.debugAssociation)
1520
+ console.log(helpDebugAssociation)
1521
+ runtime.process.exit(-1)
1381
1522
  }
1382
1523
  if (args.debugHierarchy) {
1383
- global.entodictonDebugHierarchy = JSON.parse(args.debugHierarchy)
1524
+ console.log(helpDebugHierarchy)
1525
+ runtime.process.exit(-1)
1526
+ }
1527
+ if (args.debugPriority) {
1528
+ console.log(helpDebugPriority)
1529
+ runtime.process.exit(-1)
1384
1530
  }
1385
1531
  if (args.debugBridge) {
1386
- // id/level
1387
- global.entodictonDebugBridge = args.debugBridge.split('/')
1388
- if (global.entodictonDebugBridge.length !== 2) {
1389
- console.log('Expected DEBUG_BRIDGE to be of the form "id/level"');
1390
- }
1532
+ console.log(helpDebugBridge)
1533
+ runtime.process.exit(-1)
1391
1534
  }
1392
1535
  if (args.debugOperator) {
1393
- // id/level
1394
- global.entodictonDebugOperator = args.debugOperator
1536
+ console.log(helpDebugOperator)
1537
+ runtime.process.exit(-1)
1395
1538
  }
1396
1539
 
1397
1540
  if (args.clean) {
@@ -1430,120 +1573,122 @@ const knowledgeModule = async ({
1430
1573
  if (args.debug) {
1431
1574
  config.config.debug = true
1432
1575
  }
1433
- config.config.debugIncludeConvolutions = args.debugIncludeConvolutions
1434
1576
 
1435
- if (template) {
1436
- const needsRebuild = config.needsRebuild(template.template, template.instance, options)
1437
- if (needsRebuild) {
1438
- console.log(`This module "${config.name}" needs rebuilding all other arguments will be ignored. Try again after the template is rebuilt.`)
1439
-
1440
- }
1441
- config.load(template.template, template.instance, { rebuild: needsRebuild })
1442
- if (needsRebuild) {
1443
- return
1444
- }
1577
+ if (args.explainPriorities) {
1578
+ config.config.explain_priorities = true
1445
1579
  }
1446
1580
 
1447
- if (!args.save && !args.rebuildTemplate && !args.dontAddAssociations) {
1448
- config.addAssociationsFromTests(config.tests);
1449
- //for (let query in config.tests) {
1450
- // config.addAssociations(config.tests[query].associations || []);
1451
- //}
1452
- }
1581
+ config.config.debugIncludeConvolutions = args.debugIncludeConvolutions || process.argv.includes('--debugIncludeConvolutions') || process.argv.includes('-dic')
1453
1582
 
1454
- /*
1455
- if (args.buildTemplate) {
1456
- if (template) {
1457
- config.rebuild()
1458
- config.load(template.template, template.instance, { rebuild: true })
1583
+ let configPrinted = false
1584
+ const printConfig = () => {
1585
+ if (configPrinted) {
1586
+ return
1459
1587
  }
1460
- }
1461
- */
1462
-
1463
- if (args.print) {
1464
- if (args.print.includes('t')) {
1465
- console.log("Test queries")
1466
- let counter = 0
1467
- for (const test of config.tests) {
1468
- console.log(`${counter} - ${test.query}`)
1469
- counter += 1
1588
+ configPrinted = true
1589
+ if (args.print) {
1590
+ if (args.print.includes('t')) {
1591
+ console.log("Test queries")
1592
+ let counter = 0
1593
+ for (const test of config.tests) {
1594
+ console.log(`${counter} - ${test.query}`)
1595
+ counter += 1
1596
+ }
1597
+ }
1598
+ if (args.print.includes('c')) {
1599
+ const { data } = setupProcessB({ config })
1600
+ console.log("Config as sent to server")
1601
+ console.log(JSON.stringify(data, null, 2));
1470
1602
  }
1471
- }
1472
- if (args.print.includes('c')) {
1473
- const { data } = setupProcessB({ config })
1474
- console.log("Config as sent to server")
1475
- console.log(JSON.stringify(data, null, 2));
1476
- }
1477
1603
 
1478
- if (args.print.includes('l')) {
1479
- console.log('Module load ordering')
1480
- for (const km of config.configs) {
1481
- console.log(` ${km.name}`)
1604
+ if (args.print.includes('l')) {
1605
+ console.log('Module load ordering')
1606
+ for (const km of config.configs) {
1607
+ console.log(` ${km.name}`)
1608
+ }
1482
1609
  }
1483
- }
1484
- if (args.print.includes('w')) {
1485
- for (const word in config.config.words) {
1486
- console.log(word.concat(' ', ...config.config.words[word].map((def) => JSON.stringify(def))))
1610
+ if (args.print.includes('w')) {
1611
+ for (const word in config.config.words) {
1612
+ console.log(word.concat(' ', ...config.config.words[word].map((def) => JSON.stringify(def))))
1613
+ }
1487
1614
  }
1488
- }
1489
- if (args.print.includes('b')) {
1490
- for (const bridge of config.config.bridges) {
1491
- console.log(JSON.stringify(bridge))
1615
+ if (args.print.includes('b')) {
1616
+ for (const bridge of config.config.bridges) {
1617
+ console.log(JSON.stringify(bridge))
1618
+ }
1492
1619
  }
1493
- }
1494
- if (args.print.includes('o')) {
1495
- for (const operator of config.config.operators) {
1496
- console.log(JSON.stringify(operator))
1620
+ if (args.print.includes('o')) {
1621
+ for (const operator of config.config.operators) {
1622
+ console.log(JSON.stringify(operator))
1623
+ }
1497
1624
  }
1498
- }
1499
- if (args.print.includes('j')) {
1500
- const { data } = setupProcessB( { config } )
1501
- console.log(JSON.stringify(data, null, 2))
1502
- }
1503
- if (args.print.includes('a')) {
1504
- console.log('associations ================')
1505
- const properties = ['negative', 'positive']
1506
- for (let property of properties) {
1507
- console.log(` ${property} ===============`)
1508
- for (let association of config.config.associations[property]) {
1509
- console.log(` ${JSON.stringify(association)}`)
1625
+ if (args.print.includes('j')) {
1626
+ const { data } = setupProcessB( { config } )
1627
+ console.log(JSON.stringify(data, null, 2))
1628
+ }
1629
+ if (args.print.includes('a')) {
1630
+ console.log('associations ================')
1631
+ const properties = ['negative', 'positive']
1632
+ for (let property of properties) {
1633
+ console.log(` ${property} ===============`)
1634
+ for (let association of config.config.associations[property]) {
1635
+ console.log(` ${JSON.stringify(association)}`)
1636
+ }
1510
1637
  }
1511
1638
  }
1512
- }
1513
- if (args.print.includes('d')) {
1514
- console.log(JSON.stringify(config.config.objects, null, 2))
1515
- }
1516
- if (args.print.includes('p')) {
1517
- for (let priority of config.config.priorities) {
1518
- console.log(JSON.stringify(priority))
1639
+ if (args.print.includes('d')) {
1640
+ console.log(JSON.stringify(config.config.objects, null, 2))
1519
1641
  }
1520
- }
1521
- if (args.print.includes('h')) {
1522
- for (let edge of config.config.hierarchy) {
1523
- console.log(JSON.stringify(edge))
1642
+ if (args.print.includes('p')) {
1643
+ for (let priority of config.config.priorities) {
1644
+ console.log(JSON.stringify(priority))
1645
+ }
1524
1646
  }
1525
- }
1526
- if (args.print.includes('g')) {
1527
- const easyToRead = _.cloneDeep(config.config.generators)
1528
- for (const semantic of easyToRead) {
1529
- semantic.match = semantic.match.toString()
1530
- semantic.apply = semantic.apply.toString()
1531
- if (semantic.applyWrapped) {
1532
- semantic.applyWrapped = semantic.applyWrapped.toString()
1647
+ if (args.print.includes('h')) {
1648
+ for (let edge of config.config.hierarchy) {
1649
+ console.log(JSON.stringify(edge))
1533
1650
  }
1534
1651
  }
1535
- console.dir(easyToRead)
1536
- }
1537
- if (args.print.includes('s')) {
1538
- const easyToRead = _.cloneDeep(config.config.semantics)
1539
- for (const semantic of easyToRead) {
1540
- semantic.match = semantic.match.toString()
1541
- semantic.apply = semantic.apply.toString()
1652
+ if (args.print.includes('g')) {
1653
+ const easyToRead = _.cloneDeep(config.config.generators)
1654
+ for (const semantic of easyToRead) {
1655
+ semantic.match = semantic.match.toString()
1656
+ semantic.apply = semantic.apply.toString()
1657
+ if (semantic.applyWrapped) {
1658
+ semantic.applyWrapped = semantic.applyWrapped.toString()
1659
+ }
1660
+ }
1661
+ console.dir(easyToRead)
1542
1662
  }
1543
- console.dir(easyToRead)
1663
+ if (args.print.includes('s')) {
1664
+ const easyToRead = _.cloneDeep(config.config.semantics)
1665
+ for (const semantic of easyToRead) {
1666
+ semantic.match = semantic.match.toString()
1667
+ semantic.apply = semantic.apply.toString()
1668
+ }
1669
+ console.dir(easyToRead)
1670
+ }
1671
+ }
1672
+ }
1673
+
1674
+ if (template) {
1675
+ const needsRebuild = config.needsRebuild(template.template, template.instance, options)
1676
+ if (needsRebuild) {
1677
+ console.log(`This module "${config.name}" needs rebuilding all other arguments will be ignored. Try again after the template is rebuilt.`)
1678
+ options.rebuild = true
1679
+ config.config.rebuild = true
1680
+ }
1681
+ config.load(template.template, template.instance, { rebuild: needsRebuild })
1682
+ printConfig()
1683
+ if (needsRebuild) {
1684
+ return
1544
1685
  }
1545
1686
  }
1546
1687
 
1688
+ if (!args.save && !args.rebuildTemplate && !args.dontAddAssociations) {
1689
+ config.addAssociationsFromTests(config.tests);
1690
+ }
1691
+
1547
1692
  if (args.retrain) {
1548
1693
  config.config.retrain = true
1549
1694
  }
@@ -1575,12 +1720,7 @@ const knowledgeModule = async ({
1575
1720
  test = useTestConfig.name
1576
1721
 
1577
1722
  }
1578
- runTests(config, test, { debug: args.debug, testConfig: useTestConfig, verbose: args.testVerbose || args.testAllVerbose, stopAtFirstError: !args.testAllVerbose }).then((results) => {
1579
- if (results.length > 0 && args.vimdiff) {
1580
- for (const result of results) {
1581
- vimdiff(result.expected, result.actual)
1582
- }
1583
- }
1723
+ runTests(config, test, { args, debug: args.debug, testConfig: useTestConfig, verbose: args.testVerbose || args.testAllVerbose, stopAtFirstError: !args.testAllVerbose }).then((results) => {
1584
1724
  let newError = false
1585
1725
  if (results.length > 0) {
1586
1726
  let headerShown = false
@@ -1590,18 +1730,49 @@ const knowledgeModule = async ({
1590
1730
  if (JSON.stringify(result.expected.paraphrases) !== JSON.stringify(result.actual.paraphrases)) {
1591
1731
  hasError = true
1592
1732
  }
1733
+ if (!args.testNoParenthesized) {
1734
+ if (JSON.stringify(result.expected.paraphrasesParenthesized) !== JSON.stringify(result.actual.paraphrasesParenthesized)) {
1735
+ hasError = true
1736
+ }
1737
+ if (JSON.stringify(result.expected.generatedParenthesized) !== JSON.stringify(result.actual.generatedParenthesized)) {
1738
+ hasError = true
1739
+ }
1740
+ }
1593
1741
  if (JSON.stringify(result.expected.responses) !== JSON.stringify(result.actual.responses)) {
1594
1742
  hasError = true
1595
1743
  }
1596
1744
  if (JSON.stringify(result.expected.checked) !== JSON.stringify(result.actual.checked)) {
1597
1745
  hasError = true
1598
1746
  }
1747
+ if (!sameJSON(result.expected.checkedContexts, result.actual.checkedContexts)) {
1748
+ hasError = true
1749
+ }
1599
1750
  }
1600
1751
 
1601
1752
  if (hasError) {
1602
1753
  console.log('**************************** ERRORS ************************')
1603
1754
  for (const result of results) {
1604
1755
  console.log('Utterance: ', result.utterance)
1756
+ const show = (label, expected, actual) => {
1757
+ if (JSON.stringify(expected) !== JSON.stringify(actual)) {
1758
+ if (!headerShown) {
1759
+ console.log(' Failure')
1760
+ }
1761
+ console.log(` expected ${label}`, expected)
1762
+ console.log(` actual ${label} `, actual)
1763
+ newError = true
1764
+ headerShown = true
1765
+ }
1766
+ }
1767
+ show('paraphrases', result.expected.paraphrases, result.actual.paraphrases)
1768
+ if (!args.testNoParenthesized) {
1769
+ show('paraphrases parenthesized', result.expected.paraphrasesParenthesized, result.actual.paraphrasesParenthesized)
1770
+ }
1771
+ show('responses', result.expected.responses, result.actual.responses)
1772
+ if (!args.testNoParenthesized) {
1773
+ show('responses parenthesized', result.expected.generatedParenthesized, result.actual.generatedParenthesized)
1774
+ }
1775
+ /*
1605
1776
  if (JSON.stringify(result.expected.paraphrases) !== JSON.stringify(result.actual.paraphrases)) {
1606
1777
  if (!headerShown) {
1607
1778
  console.log(' Failure')
@@ -1620,6 +1791,7 @@ const knowledgeModule = async ({
1620
1791
  newError = true
1621
1792
  headerShown = true
1622
1793
  }
1794
+ */
1623
1795
  if (JSON.stringify(result.expected.checked) !== JSON.stringify(result.actual.checked)) {
1624
1796
  if (!headerShown) {
1625
1797
  console.log(' Failure')
@@ -1632,10 +1804,37 @@ const knowledgeModule = async ({
1632
1804
  lines.setElement(1, 1, 'actual checked')
1633
1805
  lines.setElement(2, 2, JSON.stringify(result.actual.checked, null, 2))
1634
1806
  lines.log()
1807
+ if (args.vimdiff) {
1808
+ vimdiff(result.actual.checked, result.expected.checked)
1809
+ }
1810
+ newError = true
1811
+ headerShown = true
1812
+ }
1813
+ if (!sameJSON(result.expected.checkedContexts, result.actual.checkedContexts)) {
1814
+ if (!headerShown) {
1815
+ console.log(' Failure')
1816
+ }
1817
+ const widths = [4, 18, 72]
1818
+ const lines = new Lines(widths)
1819
+ lines.setElement(1, 1, 'expected checkedContexts', true)
1820
+ lines.setElement(2, 2, JSON.stringify(result.expected.checkedContexts, null, 2))
1821
+ lines.log()
1822
+ lines.setElement(1, 1, 'actual checkedContexts', true)
1823
+ lines.setElement(2, 2, JSON.stringify(result.actual.checkedContexts, null, 2))
1824
+ lines.log()
1825
+ if (args.vimdiff) {
1826
+ vimdiff(result.actual.checkedContexts, result.expected.checkedContexts)
1827
+ }
1635
1828
  newError = true
1636
1829
  headerShown = true
1637
1830
  }
1638
1831
  }
1832
+ } else {
1833
+ if (results.length > 0 && args.vimdiff) {
1834
+ for (const result of results) {
1835
+ vimdiff(result.actual, result.expected)
1836
+ }
1837
+ }
1639
1838
  }
1640
1839
  if (!headerShown) {
1641
1840
  if (!(useTestConfig.check && useTestConfig.check.length > 0)) {
@@ -1667,12 +1866,11 @@ const knowledgeModule = async ({
1667
1866
  if (query.length === 0) {
1668
1867
  return readline.close()
1669
1868
  }
1670
- // const promise = processResults(_process(config, query, { testsFN: test }))
1671
1869
  const promise = _process(config, query, { testsFN: test }).then((results) => {
1672
1870
  console.log(results.responses.join(' '))
1673
1871
  })
1674
1872
  if (!('then' in promise)) {
1675
- throw 'Return a promise from process in the definition of knowledgeModule'
1873
+ throw new Error('Return a promise from process in the definition of knowledgeModule')
1676
1874
  }
1677
1875
  promise
1678
1876
  .then(() => {
@@ -1695,20 +1893,65 @@ const knowledgeModule = async ({
1695
1893
  if (args.objectDiff) {
1696
1894
  global.beforeObjects = _.cloneDeep(objects)
1697
1895
  }
1698
- config.beforeQuery({ query: args.query, isModule: false, objects })
1699
1896
  try {
1700
- processResults(_process(config, args.query, { commandLineArgs: args, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
1897
+ await processResults(_process(config, args.query, { commandLineArgs: args, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
1701
1898
  } catch( error ) {
1702
1899
  console.log('Error', error);
1703
1900
  }
1704
1901
  }
1902
+ printConfig()
1705
1903
  } else {
1706
- config.addAssociationsFromTests(config.tests);
1707
- //for (let query in config.tests) {
1708
- // config.addAssociations(config.tests[query].associations || []);
1709
- //}
1710
- module()
1904
+ const initConfig = (config) => {
1905
+ setupConfig(config)
1906
+
1907
+ let loadForTesting = false
1908
+ if (global.theprogrammablemind) {
1909
+ if (global.theprogrammablemind.loadForTesting[config.name]) {
1910
+ loadForTesting = true
1911
+ }
1912
+ }
1913
+ // remove test only stuff
1914
+ if (!isProcess && !loadForTesting) {
1915
+ config.config.operators = config.config.operators.filter( (operator) => {
1916
+ if (operator.development) {
1917
+ return false
1918
+ } else {
1919
+ return true
1920
+ }
1921
+ })
1922
+ config.config.bridges = config.config.bridges.filter( (bridge) => {
1923
+ if (bridge.development) {
1924
+ return false
1925
+ } else {
1926
+ return true
1927
+ }
1928
+ })
1929
+ }
1930
+
1931
+ if (template) {
1932
+ if (config.needsRebuild(template.template, template.instance, { isModule: !isProcess })) {
1933
+ 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.`
1934
+ throw new Error(error)
1935
+ }
1936
+ try {
1937
+ config.load(template.template, template.instance)
1938
+ } catch( e ) {
1939
+ errorHandler(e)
1940
+ }
1941
+ }
1942
+
1943
+ config.addAssociationsFromTests(config.tests);
1944
+ }
1945
+
1946
+ createConfigExport = () => {
1947
+ const config = createConfig()
1948
+ initConfig(config)
1949
+ config.rebuild({ isModule: true })
1950
+ return config
1951
+ }
1952
+ moduleFromJSFile.exports = createConfigExport
1711
1953
  }
1954
+
1712
1955
  }
1713
1956
 
1714
1957
  /*
@@ -1762,7 +2005,7 @@ module.exports = {
1762
2005
  w,
1763
2006
  // submitBug,
1764
2007
  ensureTestFile,
1765
- build,
2008
+ rebuildTemplate,
1766
2009
  processContext,
1767
2010
  processContexts,
1768
2011
  runTests,
@@ -1774,8 +2017,9 @@ module.exports = {
1774
2017
  Digraph,
1775
2018
  analyzeMetaData,
1776
2019
  processContextsB,
1777
- processInstance,
2020
+ loadInstance,
1778
2021
  gs,
1779
2022
  flattens,
1780
2023
  writeTest
1781
2024
  }
2025
+