theprogrammablemind 7.5.8 → 7.6.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -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
+