theprogrammablemind 7.12.4 → 7.12.5-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
@@ -10,12 +10,47 @@ const _ = require('lodash')
10
10
  const stringify = require('json-stable-stringify')
11
11
  const Lines = require('./lines')
12
12
  const flattens = require('./src/flatten')
13
- const { appendNoDups, InitCalls, updateQueries, safeNoDups } = require('./src/helpers')
13
+ const { appendNoDups, InitCalls, updateQueries, safeNoDups, stableId } = require('./src/helpers')
14
14
  const runtime = require('./runtime')
15
15
  const sortJson = runtime.sortJson
16
16
 
17
- const getConfig_getObjectsCheck = (testConfig) => {
18
- return (testConfig.checks && testConfig.checks.objects) || []
17
+ function where (goUp = 2) {
18
+ const e = new Error()
19
+ const regexForm1 = /\((.*):(\d+):(\d+)\)$/
20
+ const regexForm2 = /at (.*):(\d+):(\d+)$/
21
+ const lines = e.stack.split('\n')
22
+ let line
23
+ let match
24
+ for (line of lines.slice(1)) {
25
+ // if (!(line.includes('config.js:') || line.includes('client.js:') || line.includes('<anonymous>'))) {
26
+ if (!(line.includes('config.js:') || line.includes('client.js:'))) {
27
+ match = regexForm1.exec(line) || regexForm2.exec(line)
28
+ if (!match) {
29
+ continue
30
+ }
31
+ break
32
+ }
33
+ }
34
+ // const line = e.stack.split("\n")[goUp];
35
+ // const match = regexForm1.exec(line) || regexForm2.exec(line)
36
+ if (match) {
37
+ return `${match[1]}:${match[2]}`
38
+ } else {
39
+ return 'running in browser'
40
+ }
41
+ }
42
+
43
+ const getConfig_getObjectsCheck = (config, testConfig) => {
44
+ let testConfigName = config.name
45
+ if (testConfig.testModuleName) {
46
+ testConfigName = testConfig.testModuleName
47
+ }
48
+ const checks = (testConfig.checks && testConfig.checks.objects) || []
49
+ if (Array.isArray(checks)) {
50
+ return { [testConfigName]: checks }
51
+ } else {
52
+ return checks
53
+ }
19
54
  }
20
55
 
21
56
  const getConfig_getContextCheck = (testConfig) => {
@@ -26,61 +61,122 @@ const pickContext = (testConfig) => (context) => {
26
61
  return project(context, getConfig_getContextCheck(testConfig))
27
62
  }
28
63
 
29
- const pickObjects = (testConfig, objects) => {
30
- return project(objects, getConfig_getObjectsCheck(testConfig))
64
+ const pickObjects = (config, testConfig, getObjects) => {
65
+ /*
66
+ let testConfigName = config.name
67
+ if (testConfig.testModuleName) {
68
+ objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
69
+ testConfigName = testConfig.testModuleName
70
+ }
71
+ */
72
+ const checks = getConfig_getObjectsCheck(config, testConfig)
73
+ const projection = {}
74
+ for (let km in checks) {
75
+ const objects = getObjects(km)
76
+ if (!objects) {
77
+ throw new Error(`In the checks for ${config.name} the KM ${km} does not exist`)
78
+ }
79
+ projection[km] = project(objects, checks[km])
80
+ }
81
+ return projection
31
82
  }
32
83
 
33
- // move ask to the KM's since verbatim is called
34
- const getAsk = (config) => (uuid) => (asks) => {
35
- for (const ask of asks) {
36
- let oneShot = true // default
37
- if (ask.oneShot === false) {
38
- oneShot = false
39
- }
40
- config.addSemantic({
41
- uuid,
42
- oneShot,
43
- match: (args) => ask.matchr(args),
44
- apply: (args) => ask.applyr(args)
45
- })
46
- }
47
- let oneShot = true
48
- for (const ask of asks) {
49
- if (ask.oneShot === false) {
50
- oneShot = false
51
- }
52
- }
53
- config.addSemantic({
54
- uuid,
55
- oneShot,
56
- match: ({ context }) => context.marker == 'controlEnd' || context.marker == 'controlBetween',
57
- apply: (args) => {
58
- for (const ask of asks) {
59
- let matchq = ask.matchq
60
- let applyq = ask.applyq
61
- if (!matchq) {
62
- let wasAsked = false
63
- matchq = () => !wasAsked,
64
- applyq = (args) => {
65
- wasAsked = true
66
- applyq(args)
84
+ // move ask to the KM's since verbatim is called probably in dialogues?
85
+ const getAsk = (config) => (uuid) => {
86
+ // if (!uuid) {
87
+ // debugger
88
+ //}
89
+ return (asks) => {
90
+ const ask = (ask) => {
91
+ let oneShot = true // default
92
+ if (ask.oneShot === false) {
93
+ oneShot = false
94
+ }
95
+
96
+ const id_q = stableId('semantic')
97
+ const id_rs = []
98
+ let wasAsked = false
99
+ let wasApplied = false
100
+ const getWasAsked = () => {
101
+ return wasAsked
102
+ }
103
+ const setWasAsked = (value) => {
104
+ wasAsked = value
105
+ }
106
+ const getWasApplied = () => {
107
+ return wasApplied
108
+ }
109
+ const setWasApplied = (value) => {
110
+ wasApplied = value
111
+ }
112
+
113
+ const semanticsr = ask.semanticsr || []
114
+ if (semanticsr.length == 0) {
115
+ semanticsr.push({ match: ask.matchr, apply: ask.applyr })
116
+ }
117
+ for (const semantic of semanticsr) {
118
+ const id_r = stableId('semantic')
119
+ id_rs.push(id_r)
120
+ config.addSemantic({
121
+ uuid,
122
+ id: id_r,
123
+ tied_ids: [id_q],
124
+ oneShot,
125
+ where: semantic.where || ask.where || where(2),
126
+ source: 'response',
127
+ match: (args) => semantic.match(args),
128
+ apply: (args) => {
129
+ setWasApplied(true)
130
+ semantic.apply(args)
131
+ },
132
+ })
133
+ }
134
+
135
+ config.addSemantic({
136
+ uuid,
137
+ oneShot,
138
+ id: id_q,
139
+ tied_ids: id_rs,
140
+ where: ask.where,
141
+ isQuestion: true, // do one question at a time
142
+ getWasAsked,
143
+ getWasApplied,
144
+ onNevermind: ask.onNevermind,
145
+ source: 'question',
146
+ match: ({ context }) => context.marker == 'controlEnd' || context.marker == 'controlBetween',
147
+ apply: (args) => {
148
+ let matchq = ask.matchq
149
+ let applyq = ask.applyq
150
+ if (!matchq) {
151
+ let wasAsked = false
152
+ matchq = () => !wasAsked,
153
+ applyq = (args) => {
154
+ wasAsked = true
155
+ return ask.applyq(args)
156
+ }
67
157
  }
158
+ if (matchq(args)) {
159
+ setWasAsked(true)
160
+ setWasApplied(false)
161
+ // args.context.motivationKeep = true
162
+ args.verbatim(applyq(args))
163
+ /*
164
+ args.context.verbatim = applyq(args)
165
+ args.context.isResponse = true;
166
+ delete args.context.controlRemove;
167
+ */
168
+ args.context.controlKeepMotivation = true
169
+ }
170
+ args.context.cascade = true
68
171
  }
69
- if (matchq(args)) {
70
- // args.context.motivationKeep = true
71
- args.verbatim(applyq(args))
72
- /*
73
- args.context.verbatim = applyq(args)
74
- args.context.isResponse = true;
75
- delete args.context.controlRemove;
76
- */
77
- args.context.controlKeepMotivation = true
78
- break
79
- }
80
- }
81
- args.context.cascade = true
172
+ })
82
173
  }
83
- })
174
+ if (!Array.isArray(asks)) {
175
+ asks = [asks]
176
+ }
177
+
178
+ [...asks].reverse().forEach( (a) => ask(a) )
179
+ }
84
180
  }
85
181
 
86
182
  const sameJSON = (json1, json2) => {
@@ -105,6 +201,9 @@ const vimdiff = (actualJSON, expectedJSON, title) => {
105
201
  }
106
202
 
107
203
  const listable = (hierarchy) => (c, type) => {
204
+ if (!c) {
205
+ return false
206
+ }
108
207
  if (hierarchy.isA(c.marker, type)) {
109
208
  return true
110
209
  }
@@ -119,6 +218,9 @@ const listable = (hierarchy) => (c, type) => {
119
218
  }
120
219
 
121
220
  const isA = (hierarchy) => (child, parent) => {
221
+ if (!child || !parent) {
222
+ return false
223
+ }
122
224
  if (child.marker) {
123
225
  child = child.marker
124
226
  }
@@ -147,7 +249,8 @@ class ErrorReason extends Error {
147
249
  }
148
250
 
149
251
  const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
150
- config.setArgs(args)
252
+
253
+ // callId
151
254
  args.calls = new InitCalls(args.isInstance ? `${args.isInstance}#${config.name}` : config.name)
152
255
  if (global.theprogrammablemind && global.theprogrammablemind.loadForTesting) {
153
256
  args.calls = new InitCalls(Object.keys(global.theprogrammablemind.loadForTesting)[0])
@@ -165,32 +268,11 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
165
268
  args.asList = asList
166
269
  args.retry = () => { throw new RetryError() }
167
270
  args.fragments = (query) => config.fragment(query)
168
- const scopedAsk = getAsk(config)
169
-
170
- const getAPI = (uuid) => {
171
- if (config && config.getAPI) {
172
- return config.getAPI(uuid)
173
- }
174
- }
175
- const getAPIs = (uuid) => {
176
- if (config && config.getAPIs) {
177
- return config.getAPIs(uuid)
178
- }
179
- }
180
- args.getUUIDScoped = (uuid) => {
181
- return {
182
- ask: scopedAsk(uuid),
183
- api: getAPI(uuid),
184
- apis: getAPIs(uuid)
185
- }
186
- }
187
- Object.assign(args, args.getUUIDScoped(uuidForScoping))
188
271
  args.breakOnSemantics = false
189
272
  args.theDebugger = {
190
273
  breakOnSemantics: (value) => args.breakOnSemantics = value
191
274
  }
192
275
  if (!logs) {
193
- debugger
194
276
  }
195
277
  args.log = (message) => logs.push(message)
196
278
 
@@ -219,6 +301,33 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
219
301
  // for semantics
220
302
  args.addAssumedScoped(args, {})
221
303
  config.getAddedArgs(args)
304
+
305
+ const getAPI = (uuid) => {
306
+ if (config && config.getAPI) {
307
+ return config.getAPI(uuid)
308
+ }
309
+ }
310
+ const getAPIs = (uuid) => {
311
+ if (config && config.getAPIs) {
312
+ return config.getAPIs(uuid)
313
+ }
314
+ }
315
+ const scopedAsk = getAsk(config)
316
+ args.getUUIDScoped = (uuid) => {
317
+ return {
318
+ ask: scopedAsk(uuid),
319
+ api: getAPI(uuid),
320
+ apis: getAPIs(uuid)
321
+ }
322
+ }
323
+ Object.assign(args, args.getUUIDScoped(uuidForScoping || config.uuid))
324
+ /*
325
+ if (uuidForScoping) {
326
+ Object.assign(args, args.getUUIDScoped(uuidForScoping))
327
+ }
328
+ */
329
+ // sets args for all the API. that make a copy so the args must be fully setup by here except for scoped
330
+ config.setArgs(args)
222
331
  }
223
332
 
224
333
  const gs = (g) => (contexts, separator, lastSeparator) => {
@@ -657,10 +766,8 @@ const loadInstance = (config, instance) => {
657
766
  config.config.skipSemantics = results.skipSemantics
658
767
  }
659
768
  const args = { config, hierarchy, json: results, commandLineArgs: {} }
660
- if (instance.queries) {
661
- args.isInstance = `instance${i}`
662
- args.instance = instance.queries[i]
663
- }
769
+ args.isInstance = `instance${i}`
770
+ args.instance = ''
664
771
  processContextsB(args)
665
772
  if (results.skipSemantics) {
666
773
  config.config.skipSemantics = null
@@ -777,6 +884,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
777
884
  response.trace = response.trace.concat(json.trace)
778
885
  response.version = json.version
779
886
  response.explain_priorities = json.explain_priorities
887
+ response.contextual_priorities_ambiguities = json.contextual_priorities_ambiguities
780
888
 
781
889
  response.contexts = response.contexts.concat(contextsPrime)
782
890
  response.generated = response.generated.concat(generatedPrime)
@@ -851,11 +959,6 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
851
959
  }
852
960
 
853
961
  let objects = getObjects(config.config.objects)(config.uuid)
854
- let testConfigName = config.name
855
- if (testConfig.testModuleName) {
856
- objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
857
- testConfigName = testConfig.testModuleName
858
- }
859
962
  try {
860
963
  const result = await _process(config, test, { errorHandler, isTest: true })
861
964
  result.query = test
@@ -895,7 +998,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
895
998
  }
896
999
  return expected.objects.namespaced[expected.objects.nameToUUID[name]] || {}
897
1000
  }
898
- const expected_checked = sortJson(pickObjects(testConfig, expectedGetObjects(testConfigName)), { depth: 25 })
1001
+ const expected_checked = sortJson(pickObjects(config, testConfig, expectedGetObjects), { depth: 25 })
899
1002
  const actualGetObjects = (name) => {
900
1003
  if (!name) {
901
1004
  name = config.name
@@ -903,7 +1006,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
903
1006
  const km = config.configs.find((km) => km.name == name)
904
1007
  return config.config.objects.namespaced[km.uuid] || {}
905
1008
  }
906
- const actual_checked = sortJson(pickObjects(testConfig, actualGetObjects(testConfigName)), { depth: 25 })
1009
+ const actual_checked = sortJson(pickObjects(config, testConfig, actualGetObjects), { depth: 25 })
907
1010
  const failed_checked = !matching(actual_objects, expected_objects)
908
1011
 
909
1012
  const failed_checks = !matching(actual_objects, expected_objects)
@@ -1155,6 +1258,24 @@ const defaultErrorHandler = async (error) => {
1155
1258
  throw error
1156
1259
  }
1157
1260
 
1261
+ const printContextualPrioritiesAmbiguities = (cpa) => {
1262
+ console.log('Contextual Priorities Ambiguities')
1263
+ for (const counter in cpa) {
1264
+ console.log(` Counter ${counter}`)
1265
+ for (const choices of cpa[counter]) {
1266
+ console.log(' [')
1267
+ for (const choice of choices) {
1268
+ console.log(' [')
1269
+ for (const element of choice) {
1270
+ console.log(` ${JSON.stringify(element)},`)
1271
+ }
1272
+ console.log(' ],')
1273
+ }
1274
+ console.log(' ],')
1275
+ }
1276
+ }
1277
+ }
1278
+
1158
1279
  const defaultInnerProcess = (config, errorHandler, responses) => {
1159
1280
  if (responses.errors) {
1160
1281
  console.log('Errors')
@@ -1173,6 +1294,9 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1173
1294
  console.log('Logs')
1174
1295
  responses.logs.forEach((log) => console.log(` ${log}`))
1175
1296
  }
1297
+ if (responses.contextual_priorities_ambiguities) {
1298
+ printContextualPrioritiesAmbiguities(responses.contextual_priorities_ambiguities)
1299
+ }
1176
1300
  console.log(responses.trace)
1177
1301
 
1178
1302
  if (global.beforeObjects) {
@@ -1211,8 +1335,15 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1211
1335
  console.log(` inputs: ${JSON.stringify(inputs)} output: ${JSON.stringify(output)} reason: ${reason}`)
1212
1336
  }
1213
1337
  }
1214
- const objects = config.get('objects').namespaced[config.uuid]
1215
- const picked = sortJson(pickObjects(config.testConfig, objects), { depth: 25 })
1338
+ // const objects = config.get('objects').namespaced[config.uuid]
1339
+ const actualGetObjects = (name) => {
1340
+ if (!name) {
1341
+ name = config.name
1342
+ }
1343
+ const km = config.configs.find((km) => km.name == name)
1344
+ return config.config.objects.namespaced[km.uuid] || {}
1345
+ }
1346
+ const picked = sortJson(pickObjects(config, config.testConfig, actualGetObjects), { depth: 25 })
1216
1347
  if (!_.isEmpty(picked)) {
1217
1348
  console.log('--- Object showing only the checked values ---')
1218
1349
  console.log(JSON.stringify(picked, null, 2))
@@ -2024,6 +2155,13 @@ const knowledgeModuleImpl = async ({
2024
2155
  })
2025
2156
  f()
2026
2157
  } else if (args.query) {
2158
+ let useTestConfig = testConfig
2159
+ if (args.testModuleName) {
2160
+ config.testConfig.testModuleName = args.testModuleName
2161
+ config.testConfig.checks = config.getConfigs()[args.testModuleName].getTestConfig().checks
2162
+ // useTestConfig = config.getConfigs()[args.testModuleName].getTestConfig()
2163
+ // useTestConfig.testModuleName = args.testModuleName
2164
+ }
2027
2165
  const objects = getObjects(config.config.objects)(config.uuid)
2028
2166
  // for the compare
2029
2167
  if (args.objectDiff) {
@@ -2118,26 +2256,6 @@ const ensureTestFile = (module, name, type) => {
2118
2256
  }
2119
2257
  }
2120
2258
 
2121
- function where (goUp = 2) {
2122
- const e = new Error()
2123
- const regexForm1 = /\((.*):(\d+):(\d+)\)$/
2124
- const regexForm2 = /at (.*):(\d+):(\d+)$/
2125
- const lines = e.stack.split('\n')
2126
- let line
2127
- for (line of lines.slice(1)) {
2128
- if (!(line.includes('config.js:') || line.includes('client.js:'))) {
2129
- break
2130
- }
2131
- }
2132
- // const line = e.stack.split("\n")[goUp];
2133
- const match = regexForm1.exec(line) || regexForm2.exec(line)
2134
- if (match) {
2135
- return `${match[1]}:${match[2]}`
2136
- } else {
2137
- return 'running in browser'
2138
- }
2139
- }
2140
-
2141
2259
  function w (func) {
2142
2260
  func.where = where(3)
2143
2261
  return func
package/package.json CHANGED
@@ -65,6 +65,6 @@
65
65
  "json-stable-stringify": "^1.0.1",
66
66
  "node-fetch": "^2.6.1"
67
67
  },
68
- "version": "7.12.4",
68
+ "version": "7.12.5-beta.0",
69
69
  "license": "UNLICENSED"
70
70
  }
package/src/config.js CHANGED
@@ -199,7 +199,7 @@ const priority_valid = (cp) => {
199
199
  )
200
200
  }
201
201
 
202
- const handleBridgeProps = (config, bridge, addFirst) => {
202
+ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
203
203
  ecatch(`While processing the bridge for ${bridge.id}#${bridge.level}`,
204
204
  () => {
205
205
  if (!bridge.bridge) {
@@ -260,7 +260,8 @@ const handleBridgeProps = (config, bridge, addFirst) => {
260
260
  }
261
261
  */
262
262
 
263
- const addUUID = (obj) => { return { ...obj, uuid: config.uuid } }
263
+ const addUUID = (obj) => { return { ...obj, uuid: uuid || config.uuid } }
264
+
264
265
  if (bridge.generators) {
265
266
  const generators = [...bridge.generators]
266
267
  generators.reverse()
@@ -343,14 +344,14 @@ const handleBridgeProps = (config, bridge, addFirst) => {
343
344
  )
344
345
  }
345
346
 
346
- const handleCalculatedProps = (baseConfig, moreConfig, addFirst) => {
347
+ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {}) => {
347
348
  if (moreConfig.bridges) {
348
349
  moreConfig.bridges = moreConfig.bridges.map((bridge) => {
349
350
  bridge = { ...bridge }
350
351
  const valid = ['after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
351
352
  'level', 'optional', 'selector', 'semantic', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where', 'uuid']
352
353
  helpers.validProps(valid, bridge, 'bridge')
353
- handleBridgeProps(baseConfig, bridge, addFirst)
354
+ handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
354
355
  return bridge
355
356
  })
356
357
  }
@@ -466,7 +467,7 @@ const normalizeConfig = (config) => {
466
467
  if (config.semantics) {
467
468
  for (const semantic of config.semantics) {
468
469
  if (semantic.oneShot) {
469
- semantic.id = uuid()
470
+ semantic.id = semantic.id || helpers.stableId('semantic')
470
471
  }
471
472
  }
472
473
  }
@@ -901,6 +902,10 @@ class Config {
901
902
  }
902
903
  }
903
904
 
905
+ get semantics() {
906
+ return [...this.config.semantics]
907
+ }
908
+
904
909
  getSemantics (logs = []) {
905
910
  return new Semantics(this.config.semantics, logs, { km: this.name })
906
911
  }
@@ -1314,7 +1319,7 @@ class Config {
1314
1319
  if (global.transitoryMode) {
1315
1320
  def.transitoryMode = true
1316
1321
  }
1317
- handleBridgeProps(this, def)
1322
+ handleBridgeProps(this, def, { uuid })
1318
1323
  bridges.push(def)
1319
1324
  this.checkBridges()
1320
1325
  this._delta.json.bridges.push({ action: 'add', bridge: def })
@@ -1365,9 +1370,28 @@ class Config {
1365
1370
  }
1366
1371
 
1367
1372
  removeSemantic (deleteSemantic) {
1368
- const index = this.config.semantics.findIndex((semantic) => semantic.id === deleteSemantic.id)
1369
- if (index >= 0) {
1370
- this.config.semantics.splice(index, 1)
1373
+ const id = deleteSemantic.id || deleteSemantic
1374
+ const todo = [id]
1375
+ const seen = new Set()
1376
+
1377
+ while (todo.length > 0) {
1378
+ const id = todo.pop()
1379
+ if (seen.has(id)) {
1380
+ continue
1381
+ }
1382
+ seen.add(id)
1383
+ const index = this.config.semantics.findIndex((semantic) => semantic.id === id)
1384
+ if (index == -1) {
1385
+ continue
1386
+ }
1387
+ for (const tied_id of this.config.semantics[index].tied_ids || []) {
1388
+ if (!seen.has(tied_id)) {
1389
+ todo.push(tied_id)
1390
+ }
1391
+ }
1392
+ if (index >= 0) {
1393
+ this.config.semantics.splice(index, 1)
1394
+ }
1371
1395
  }
1372
1396
  }
1373
1397
 
@@ -1555,7 +1579,7 @@ class Config {
1555
1579
  config._api.multiApi[api].args = args
1556
1580
  }
1557
1581
  } else {
1558
- config._api.args = args
1582
+ config._api.args = { ...args, ...args.getUUIDScoped(config.uuid) }
1559
1583
  }
1560
1584
  }
1561
1585
 
@@ -2842,7 +2866,7 @@ class Config {
2842
2866
  debugConfigProps(more)
2843
2867
 
2844
2868
  if (hcps) {
2845
- handleCalculatedProps(this, more, addFirst)
2869
+ handleCalculatedProps(this, more, { addFirst, uuid })
2846
2870
  applyUUID(more, uuid || this._uuid)
2847
2871
  }
2848
2872
  for (const key of Object.keys(more)) {
@@ -3078,5 +3102,5 @@ module.exports = {
3078
3102
  Config,
3079
3103
  config_toServer,
3080
3104
  operatorKey_valid,
3081
- handleBridgeProps
3105
+ handleBridgeProps,
3082
3106
  }
package/src/helpers.js CHANGED
@@ -374,7 +374,15 @@ const subPriority = (sub, sup) => {
374
374
  return true
375
375
  }
376
376
 
377
+ const stableIds = {}
378
+ const stableId = (tag) => {
379
+ const id = stableIds[tag] || 1
380
+ stableIds[tag] = id + 1
381
+ return id
382
+ }
383
+
377
384
  module.exports = {
385
+ stableId,
378
386
  ecatch,
379
387
  functionsToStrings,
380
388
  updateQueries,
package/src/semantics.js CHANGED
@@ -6,7 +6,7 @@ class Semantic {
6
6
  // constructor ({match, apply, uuid, index, km, notes}) {
7
7
  constructor (semantic) {
8
8
  semantic = normalizeSemantic(semantic)
9
- const { match, apply, uuid, index, km, notes, priority, debug, where, applyWrapped, property, oneShot, id } = semantic
9
+ const { match, apply, uuid, index, km, notes, priority, debug, where, source, applyWrapped, property, oneShot, id, tied_ids, isQuestion } = semantic
10
10
  this.matcher = match
11
11
  this._apply = apply
12
12
  this._applyWrapped = applyWrapped
@@ -18,8 +18,11 @@ class Semantic {
18
18
  this.notes = notes
19
19
  this.callId = debug
20
20
  this.where = where
21
+ this.source = source
21
22
  this.oneShot = oneShot
23
+ this.isQuestion = isQuestion
22
24
  this.id = id
25
+ this.tied_ids = tied_ids || []
23
26
  }
24
27
 
25
28
  toLabel () {
@@ -184,11 +187,16 @@ class Semantics {
184
187
  let applied = false
185
188
  const stack = args.calls.push()
186
189
  let counter = 0
190
+ let seenQuestion = false
187
191
  for (const isemantic in this.semantics) {
188
192
  const semantic = this.semantics[isemantic]
189
193
  if (!semantic) {
190
194
  debugger
191
195
  }
196
+ // only one question at a time
197
+ if (semantic.isQuestion && seenQuestion) {
198
+ continue
199
+ }
192
200
  if (semantic.matches(args, context, options)) {
193
201
  if (!this.calls[counter]) {
194
202
  this.calls[counter] = 0
@@ -198,6 +206,7 @@ class Semantics {
198
206
  try {
199
207
  contextPrime = semantic.apply(args, context, s, log, options)
200
208
  if (!contextPrime.controlKeepMotivation && semantic.oneShot) {
209
+ // semantic.tied_ids.forEach((tied_id) => args.config.removeSemantic(tied_id))
201
210
  args.config.removeSemantic(semantic)
202
211
  }
203
212
  } catch (e) {
@@ -274,6 +283,7 @@ class Semantics {
274
283
  this.logs.push(lines.toString())
275
284
  }
276
285
  applied = true
286
+ seenQuestion = seenQuestion || semantic.isQuestion
277
287
  if (contextPrime.cascade) {
278
288
  contextPrime.cascade = false
279
289
  } else {