ekms 9.6.3 → 9.7.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.
Files changed (84) hide show
  1. package/common/actions.instance.json +2771 -15
  2. package/common/actions.js +116 -8
  3. package/common/actions.test.json +79138 -384
  4. package/common/angle.instance.json +138 -834
  5. package/common/angle.test.json +172 -127
  6. package/common/animals.instance.json +260 -0
  7. package/common/articles.js +1 -2
  8. package/common/avatar.test.json +173 -33
  9. package/common/can.instance.json +40 -0
  10. package/common/colors.instance.json +308 -0
  11. package/common/comparable.instance.json +120 -0
  12. package/common/compass.instance.json +63 -18
  13. package/common/concept.js +2 -1
  14. package/common/conjunction.js +11 -17
  15. package/common/control.js +42 -0
  16. package/common/control.test.json +2 -0
  17. package/common/crew.instance.json +520 -0
  18. package/common/dates.instance.json +184 -0
  19. package/common/dialogues.js +3 -3
  20. package/common/dimension.instance.json +264 -69
  21. package/common/dimension.js +5 -5
  22. package/common/dimension.test.json +545 -441
  23. package/common/drone.instance.json +15927 -2638
  24. package/common/drone.js +359 -71
  25. package/common/drone.test.json +587651 -44132
  26. package/common/drone_v1.instance.json +492 -59
  27. package/common/drone_v1.js +9 -9
  28. package/common/edible.instance.json +696 -0
  29. package/common/emotions.instance.json +20 -0
  30. package/common/evaluate.js +1 -1
  31. package/common/fastfood.instance.json +1310 -216
  32. package/common/fastfood.js +1 -1
  33. package/common/formulas.instance.json +20 -5
  34. package/common/formulas.js +1 -1
  35. package/common/gdefaults.js +32 -5
  36. package/common/help.test.json +23 -3
  37. package/common/helpers/conjunction.js +2 -0
  38. package/common/helpers/formulas.js +6 -0
  39. package/common/helpers/properties.js +9 -7
  40. package/common/helpers.js +11 -6
  41. package/common/hierarchy.js +2 -0
  42. package/common/kirk.instance.json +20 -0
  43. package/common/length.instance.json +1117 -5708
  44. package/common/length.test.json +29761 -12488
  45. package/common/logging.js +41 -0
  46. package/common/logging.test.json +2 -0
  47. package/common/math.instance.json +30 -12
  48. package/common/math.js +6 -5
  49. package/common/menus.instance.json +140 -35
  50. package/common/meta.js +1 -1
  51. package/common/nameable.js +7 -9
  52. package/common/nameable.test.json +252 -150
  53. package/common/ordering.instance.json +40 -0
  54. package/common/ordinals.js +51 -5
  55. package/common/people.instance.json +160 -0
  56. package/common/pipboy.instance.json +396 -85
  57. package/common/pipboy.js +1 -1
  58. package/common/pokemon.instance.json +260 -0
  59. package/common/pressure.instance.json +108 -370
  60. package/common/properties.instance.json +20 -0
  61. package/common/properties.js +5 -4
  62. package/common/properties.test.json +2754 -2142
  63. package/common/rates.instance.json +1 -1
  64. package/common/rates.js +3 -3
  65. package/common/rates.test.json +6914 -2428
  66. package/common/reminders.js +1 -1
  67. package/common/reports.instance.json +49 -176
  68. package/common/reports.js +2 -2
  69. package/common/scorekeeper.js +1 -1
  70. package/common/sdefaults.js +18 -5
  71. package/common/spock.instance.json +20 -0
  72. package/common/stm.js +115 -53
  73. package/common/stm.test.json +2670 -54
  74. package/common/temperature.instance.json +709 -2284
  75. package/common/time.instance.json +14333 -2220
  76. package/common/time.js +48 -2
  77. package/common/time.test.json +13239 -0
  78. package/common/tokenize.js +2 -0
  79. package/common/ui.instance.json +20 -5
  80. package/common/ui.js +1 -1
  81. package/common/weight.instance.json +621 -1886
  82. package/common/wp.instance.json +336 -70
  83. package/main.js +4 -0
  84. package/package.json +11 -5
package/common/drone.js CHANGED
@@ -1,4 +1,4 @@
1
- const { knowledgeModule, where } = require('./runtime').theprogrammablemind
1
+ const { knowledgeModule, where, debug } = require('./runtime').theprogrammablemind
2
2
  const { conjugateVerb } = require('./english_helpers')
3
3
  const { OverrideCheck, defaultContextCheckProperties, defaultContextCheck, getValue, setValue } = require('./helpers')
4
4
  const drone_tests = require('./drone.test.json')
@@ -14,6 +14,46 @@ const help = require('./help')
14
14
  const { rotateDelta, degreesToRadians, radiansToDegrees, cartesianToPolar, smallestRotate } = require('./helpers/drone')
15
15
 
16
16
  /*
17
+ NEED TO CHECK ON ACTUAL DRONE
18
+
19
+ again 2 times
20
+ 2 more times
21
+ do that again 3 times
22
+
23
+ do route 1 skipping point 2
24
+
25
+ base <number> is a pattern for base names
26
+ 2 feet north and 1 foot east is called base 1
27
+ 2 feet north 1 foot east is called base 1
28
+ 2 feet north 1 foot east is base 1
29
+ DONE delete route 2 / delete that route / delete that
30
+ DONE maybe have status as the drone moves liek "patrolling route 1" etc
31
+
32
+ patrol back and forth 2 times
33
+
34
+ DONE fix DO so it can do all the stuff partol can do <<<<<<<<<<<<<<<<<<<
35
+ start again. start a new path
36
+ the last 3 points are called path 1
37
+ go forward 1 meter and then turn north
38
+ go forward 1 meter and turn north
39
+
40
+
41
+ stopping 2 seconds at each point
42
+ patrols x do that again
43
+ DONE go to the end of the patrol
44
+ DONE patrol x three times
45
+ patrol x continuously
46
+ patrol x for 5 minutes
47
+ go to the start
48
+ DONE node drone -q 'north 1 meter\neast 1 meter\ncall that route 2\nwhat is the second point of route 2' -g -
49
+
50
+ go to the start along the path / following the path
51
+ pausing 1 second at the first point and 5 at the last
52
+
53
+ DONE go to the second point of route 1
54
+ DONE do route 1 pausing 10 seconds at each point
55
+
56
+ what is the drone's position
17
57
  DONE go back
18
58
  go back another point
19
59
  go back again
@@ -21,12 +61,21 @@ go back to the start
21
61
  go back 2 points along route 1
22
62
  go to the start of route 2
23
63
 
64
+ go forward 1 foot\nturn left\ngo forward again\n
65
+ do it again
66
+
67
+ TODO should there be two hierarchy one as a concept car is a vehicle and one as a word car is a noun
68
+
24
69
  turn left\nturn back
25
70
 
26
- do route 1 pausing 10 seconds at each point
71
+ DONE do route 1 pausing 10 seconds at each point
72
+ do route 1 pausing 1 second at point 1 and 2 seconds for the rest
27
73
 
28
74
  forward 1 foot\nwest 1 foot\ngo back to the start <<<<<<<< turn the longer way not he shorter way
29
75
  forward 1 foot\nwest 1 foot\ncall the path route 1\ngo to the start of route 1\npatrol route 1\npatrol route 1 <<<<< does the patrol more than once
76
+ call that route 1
77
+ what are the paths
78
+ list the paths
30
79
 
31
80
  ?? elipses of the verb go or some kind of conjunction?!?!?
32
81
  go forward 1 meter turn right forward 2 meters stop
@@ -269,6 +318,22 @@ class API {
269
318
  const overrideMethods = Object.getOwnPropertyNames(API.prototype).filter(key => typeof API.prototype[key] === 'function' && key.endsWith('Drone'));
270
319
  this.overrideCheck = new OverrideCheck(API, overrideMethods)
271
320
  this.overriden = this.constructor !== API
321
+ this.startPoint = { x: 0, y: 0 }
322
+ this.startAngle = Math.PI/2
323
+ this.startCompass = 'north'
324
+ }
325
+
326
+ setStartPoint(point) {
327
+ this.startPoint = point
328
+ }
329
+
330
+ setStartAngle(angleInRadians, compass) {
331
+ this.startAngle = angleInRadians
332
+ this.startCompass = compass
333
+ }
334
+
335
+ setSpeed(metersPerSecond) {
336
+ this._objects.current.speed = metersPerSecond
272
337
  }
273
338
 
274
339
  initialize({ objects }) {
@@ -276,11 +341,11 @@ class API {
276
341
  this.overrideCheck.check(this)
277
342
  }
278
343
 
279
- if (!this.minimumSpeedDrone()) {
344
+ if (this.minimumSpeedDrone() == null) {
280
345
  throw new Error(`minimumSpeedDrone is not returning a positive number. Its returning ${this.minimumSpeedDrone()}`)
281
346
  }
282
347
 
283
- if (!this.maximumSpeedDrone()) {
348
+ if (this.maximumSpeedDrone() == null) {
284
349
  throw new Error(`maximumSpeedDrone is not returning a positive number. Its returning ${this.maximumSpeedDrone()}`)
285
350
  }
286
351
 
@@ -289,17 +354,17 @@ class API {
289
354
  delete this.testDate
290
355
 
291
356
  objects.current = {
292
- angleInRadians: Math.PI/2,
357
+ angleInRadians: this.startAngle,
293
358
  path: [],
294
359
  speed: this.minimumSpeedDrone(),
295
360
  ordinal: 0, // ordinal of the current point or the current point that the recent movement started at
296
- compass: 'north', // for now assume the drone start out point north. i will make that part of the conversation later
361
+ compass: this.startCompass,
297
362
  direction: 'forward',
298
363
  }
299
364
  objects.history = []
300
365
  objects.sonicTest = 5
301
366
 
302
- this.args.mentioned({ marker: 'point', ordinal: this.nextOrdinal(), point: { x: 0, y: 0 }, description: "start" })
367
+ this.args.remember({ marker: 'point', ordinal: this.nextOrdinal(), point: this.startPoint, description: "start" })
303
368
  }
304
369
 
305
370
  currentOrdinal() {
@@ -318,7 +383,7 @@ class API {
318
383
  return null // in motion
319
384
  }
320
385
  const ordinal = this.currentOrdinal()
321
- const lastPoint = await this.args.mentions({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
386
+ const lastPoint = await this.args.recall({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
322
387
  if (!current.startTime && !current.endTime && !current.durationInSeconds) {
323
388
  return lastPoint // did not move
324
389
  }
@@ -344,7 +409,7 @@ class API {
344
409
  return
345
410
  }
346
411
  const ordinal = this.nextOrdinal()
347
- this.args.mentioned({ marker: 'point', ordinal, point })
412
+ this.args.remember({ marker: 'point', ordinal, point })
348
413
  this._objects.current.endTime = null
349
414
  this._objects.current.startTime = null
350
415
  }
@@ -378,9 +443,13 @@ class API {
378
443
  const unitsOfUser = objects.current.speedUnitsOfUser
379
444
  const minimumValueInDroneUnits = await fragments("number meters per second", { number: { marker: 'integer', value: minimumSpeed } })
380
445
  // const valueInUsersUnits = await fragments("quantity in meters", { quantity: minimumValueInDroneUnits, meter: unitsOfUser })
381
- const valueInUsersUnits = await quantityInMeters(minimumValueInDroneUnits, unitsOfUser )
382
- const evaluated = await e(valueInUsersUnits)
383
- say(`The drone cannot go that slow. The minimum speed is ${await gr(evaluated.evalue)}`)
446
+ if (unitsOfUser) {
447
+ const valueInUsersUnits = await quantityInMeters(minimumValueInDroneUnits, unitsOfUser )
448
+ const evaluated = await e(valueInUsersUnits)
449
+ say(`The drone cannot go that slow. The minimum speed is ${await gr(evaluated.evalue)}`)
450
+ } else {
451
+ say(`The drone cannot go that fast. The minimum speed is ${await gr(minimumValueInDroneUnits)}`)
452
+ }
384
453
  objects.runCommand = false
385
454
  objects.current.speed = minimumSpeed
386
455
  return
@@ -392,9 +461,13 @@ class API {
392
461
  const unitsOfUser = objects.current.speedUnitsOfUser
393
462
  const maximumValueInDroneUnits = await fragments("number meters per second", { number: { marker: 'integer', value: maximumSpeed } })
394
463
  // const valueInUsersUnits = await fragments("quantity in meters", { quantity: maximumValueInDroneUnits, meter: unitsOfUser })
395
- const valueInUsersUnits = await quantityInMeters(maximumValueInDroneUnits, unitsOfUser )
396
- const evaluated = await e(valueInUsersUnits)
397
- say(`The drone cannot go that fast. The maximum speed is ${await gr(evaluated.evalue)}`)
464
+ if (unitsOfUser) {
465
+ const valueInUsersUnits = await quantityInMeters(maximumValueInDroneUnits, unitsOfUser)
466
+ const evaluated = await e(valueInUsersUnits)
467
+ say(`The drone cannot go that fast. The maximum speed is ${await gr(evaluated.evalue)}`)
468
+ } else {
469
+ say(`The drone cannot go that fast. The maximum speed is ${await gr(maximumValueInDroneUnits)}`)
470
+ }
398
471
  objects.runCommand = false
399
472
  objects.current.speed = minimumSpeed
400
473
  return
@@ -409,16 +482,21 @@ class API {
409
482
  }
410
483
 
411
484
  if (objects.current.path.length > 0) {
412
- if (objects.current.timeRepeats) {
413
- this.startRepeats(objects.current.timeRepeats)
414
- }
415
- let currentPoint = (await this.args.mentions({ context: { marker: 'point' } })).point
485
+ let currentPoint = (await this.args.recall({ context: { marker: 'point' } })).point
416
486
  this._objects.history.push({ marker: 'history', debug: 'doing path' })
417
- for (const pathComponent of objects.current.path) {
418
- if (pathComponent.marker == 'pause') {
487
+ for (const [pathIndex, pathComponent] of objects.current.path.entries()) {
488
+ if (pathComponent.message) {
489
+ this.messageDrone(pathComponent.message)
490
+ } else if (pathComponent.repeatStart) {
491
+ if (objects.current.timeRepeats) {
492
+ this.startRepeats(objects.current.timeRepeats)
493
+ }
494
+ } else if (pathComponent.marker == 'pause') {
419
495
  this.pause(pathComponent.pauseSeconds, { batched: true })
420
496
  } else {
421
- const destinationPoint = pathComponent.point
497
+ const points = this.args.toArray(pathComponent)
498
+ // const destinationPoint = pathComponent.point
499
+ const destinationPoint = points[0].point || points[0]
422
500
  if (currentPoint.x == destinationPoint.x && currentPoint.y == destinationPoint.y) {
423
501
  // already there
424
502
  } else {
@@ -427,12 +505,12 @@ class API {
427
505
  // const angleDelta = (destinationAngleInRadians - objects.current.angleInRadians)
428
506
  const angleDelta = rotateDelta(objects.current.angleInRadians, destinationAngleInRadians)
429
507
  await this.rotate(angleDelta, { batched: true })
430
- if (!pathComponent .aimOnly) {
508
+ if (!pathComponent.aimOnly) {
431
509
  await this.forward(objects.current.speed, { batched: true })
432
510
  await stopAtDistance("forward", polar.radius)
511
+ currentPoint = destinationPoint
433
512
  }
434
513
  }
435
- currentPoint = destinationPoint
436
514
  }
437
515
  }
438
516
  if (objects.current.timeRepeats) {
@@ -544,7 +622,7 @@ class API {
544
622
  } else {
545
623
  ordinal = this.currentOrdinal() - 1
546
624
  }
547
- const lastPoint = await this.args.mentions({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
625
+ const lastPoint = await this.args.recall({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
548
626
  if (!lastPoint) {
549
627
  this.args.say(`There is no previous point to go back to`)
550
628
  return
@@ -558,8 +636,9 @@ class API {
558
636
  const current = objects.current
559
637
  current.backAndForth = true
560
638
  const ordinal = this.currentOrdinal()
561
- const currentPoint = await this.args.mentions({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
562
- const lastPoint = await this.args.mentions({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal-1 })
639
+ const currentPoint = await this.args.recall({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
640
+ const lastPoint = await this.args.recall({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal-1 })
641
+ current.path.push({ repeatStart: true })
563
642
  current.path.push(lastPoint)
564
643
  current.path.push(currentPoint)
565
644
  objects.runCommand = true
@@ -602,6 +681,10 @@ class API {
602
681
  await this.pauseDrone(durationInSeconds, options)
603
682
  }
604
683
 
684
+ async messageDrone(message) {
685
+ this._objects.history.push({ marker: 'message', message })
686
+ }
687
+
605
688
  // subclass and override the remaining to call the drone
606
689
 
607
690
  async armActionDrone(action) {
@@ -626,7 +709,11 @@ class API {
626
709
 
627
710
  async pauseDrone(durationInSeconds, options) {
628
711
  this._objects.history.push({ marker: 'history', pause: durationInSeconds, time: this.now(true, durationInSeconds*1000), ...options })
629
- this.testDate = new Date(this.testDate.getTime() + (durationInSeconds-1)*1000)
712
+ if (false) {
713
+ this.testDate = new Date(this.testDate.getTime() + (durationInSeconds-1)*1000)
714
+ } else {
715
+ this.testDate = new Date(this.now(false, 0).getTime() + (durationInSeconds-1)*1000)
716
+ }
630
717
  }
631
718
 
632
719
  // meters per second
@@ -752,6 +839,7 @@ const template = {
752
839
  "number radians",
753
840
  "40 degrees in radians",
754
841
  "path",
842
+ "forward",
755
843
  ],
756
844
  configs: [
757
845
  "arm, claw and drone are concepts",
@@ -759,9 +847,25 @@ const template = {
759
847
  "around, forward, left, right, back, forth and backward are directions",
760
848
  "paths are nameable and memorable",
761
849
  "start and end are properties of path",
850
+ ({apis}) => {
851
+ apis('properties').addHierarchyWatcher({
852
+ match: ({childId}) => childId == 'point',
853
+ apply: ({config, childId}) => {
854
+ config.updateBridge(childId, ({ bridge }) => {
855
+ if (!bridge.init) {
856
+ bridge.init = {}
857
+ }
858
+ bridge.init['notConjunctableWith'] = ['quantity']
859
+ })
860
+ }
861
+ })
862
+ },
863
+
762
864
  "start and end are points",
865
+ "rest and remaining are concepts",
763
866
  {
764
867
  hierarchy: [
868
+ ['point', 'distributable'],
765
869
  ['thisitthat', 'path'],
766
870
  ['path', 'action'],
767
871
  ],
@@ -815,14 +919,71 @@ const template = {
815
919
  "([lower] (@<= arm || @<=claw))",
816
920
  "([open] (claw))",
817
921
  "([close] (claw))",
922
+ "([startPath|start] (path))",
818
923
  "([pathComponent])",
924
+ "([skipPoint|] (point))",
819
925
  "(<another> (point))",
820
926
  // "([turn] (direction))",
821
927
  // "([pause] ([number]))",
822
928
  "([stop] ([drone|])?)",
823
929
  "([toPoint|to] (point))",
930
+ "([atPoint|at] (point))",
931
+ // "([forRest|for] (rest/* || remaining/*))",
932
+ "((context.unit.dimension == 'time') [timeAtPoint|] (atPoint))",
933
+ // "((context.unit.dimension == 'time') [timeForRest|] (forRest))",
824
934
  ],
825
935
  bridges: [
936
+ {
937
+ id: 'skipPoint',
938
+ words: ['skip', 'skipping'],
939
+ isA: ['verb'],
940
+ bridge: "{ ...next(operator), points: after[0], operator: operator, interpolate: [{ property: 'operator' }, { property: 'points' }] }",
941
+ check: defaultContextCheckProperties(['points']),
942
+ },
943
+ {
944
+ id: 'skipPoint',
945
+ level: 1,
946
+ bridge: `{
947
+ ...repeatable,
948
+ skip: operator,
949
+ checks: append(repeatable.checks, ['skip']),
950
+ repeatable: repeatable,
951
+ interpolate: [{ property: 'repeatable' }, { property: 'skip', byPosition: true }]
952
+ }`,
953
+ selector: {
954
+ loose: "repeatable",
955
+ arguments: {
956
+ repeatable: "(@<= 'repeatable')",
957
+ },
958
+ },
959
+ check: defaultContextCheckProperties(['repeatable', 'repeats'])
960
+ },
961
+ {
962
+ id: 'startPath',
963
+ isA: ['verb'],
964
+ bridge: "{ ...next(operator), path: after[0], operator: operator, interpolate: [{ property: 'operator' }, { property: 'path' }] }",
965
+ check: defaultContextCheckProperties(['path']),
966
+ semantic: async ({context, remember, recall, verbatim, g}) => {
967
+ const point = await recall({ context: { marker: 'point' } })
968
+ remember(context)
969
+ remember(point) // put the last point before the startPath so when the new path is generated this is the start point
970
+ verbatim(`New path started from ${await g(point)}`)
971
+ },
972
+ },
973
+ {
974
+ id: 'timeAtPoint',
975
+ before: ['verb'],
976
+ after: ['preposition'],
977
+ convolution: true,
978
+ bridge: "{ ...next(operator), time: before[0], point: after[0], operator: operator, interpolate: [{ property: 'time' }, { property: 'point' }] }",
979
+ check: defaultContextCheckProperties(['time', 'point']),
980
+ },
981
+ {
982
+ id: 'atPoint',
983
+ isA: ['preposition'],
984
+ bridge: "{ ...next(operator), point: after[0], operator: operator, interpolate: [{ property: 'operator' }, { property: 'point' }] }",
985
+ check: defaultContextCheckProperties(['point']),
986
+ },
826
987
  {
827
988
  id: 'another',
828
989
  bridge: `{
@@ -831,6 +992,7 @@ const template = {
831
992
  after: after[0],
832
993
  interpolate: [ { property: 'another' }, { property: 'after' } ]
833
994
  }`,
995
+ check: defaultContextCheckProperties(['another', 'after']),
834
996
  },
835
997
  {
836
998
  id: 'pathComponent',
@@ -838,21 +1000,83 @@ const template = {
838
1000
  },
839
1001
  {
840
1002
  id: 'patrol',
841
- isA: ['verb'],
1003
+ isA: ['verb', 'repeatable', 'action'],
842
1004
  bridge: `{
843
- ...next(operator), operator: operator, path: after[0], interpolate: [{ property: 'operator'}, { property: 'path' }]
1005
+ ...next(operator),
1006
+ operator: operator,
1007
+ path: after[0],
1008
+ interpolate: append(default(operator.interpolate, [{ property: 'operator'}]), [{ property: 'path' }])
844
1009
  }`,
845
- semantic: async ({context, e, toEValue, objects}) => {
846
- const evaluated = await(e(context.path))
847
- const path = toEValue(evaluated)
848
- for (const point of path.points) {
849
- objects.current.path.push(point)
850
- }
851
- // if the patrol does not start and end at the same spot then
852
- // go back to the start along the same path
853
- if (JSON.stringify(path.points[0].point) !== JSON.stringify(path.points[path.points.length-1].point)) {
854
- for (const point of [...path.points].reverse()) {
1010
+ check: defaultContextCheckProperties(['path']),
1011
+ semantic: async ({context, g, e, toArray, fragments, toEValue, toFinalValue, recall, objects, verbatim}) => {
1012
+ const paths = toArray(context.path)
1013
+ for (const context_path of paths) {
1014
+ const evaluated = await(e(context_path))
1015
+ const path = toEValue(evaluated)
1016
+ if (path.marker == 'answerNotKnown') {
1017
+ verbatim(`${await g(context_path)} is not a known path`)
1018
+ continue
1019
+ }
1020
+
1021
+ objects.current.path.push({ message: await g(context) })
1022
+
1023
+ // TODO put this in a common place for use by do+patrol
1024
+
1025
+ // ordinal to pause time in seconds
1026
+ const pauseTimeInSeconds = {}
1027
+ if (context.pause) {
1028
+ const timeAtPoints = toArray(context.pause.timeAtPoint)
1029
+ for (const timeAtPoint of timeAtPoints) {
1030
+ const instantiation = await fragments("quantity in seconds", { quantity: timeAtPoint.time })
1031
+ const result = await e(instantiation)
1032
+ const seconds = toFinalValue(toFinalValue(result).amount)
1033
+
1034
+ const points = await recall({ context: timeAtPoint.point.point, frameOfReference: path })
1035
+ for (const point of toArray(points)) {
1036
+ pauseTimeInSeconds[point.ordinal] = seconds
1037
+ }
1038
+ }
1039
+ }
1040
+
1041
+ let skipPoints = []
1042
+ if (context.skip) {
1043
+ skipPoints = toArray(await recall({ context: context.skip.points, frameOfReference: path }))
1044
+ }
1045
+
1046
+ // get to the start of the patrol
1047
+ objects.current.path.push(path.points[0])
1048
+ objects.current.path.push({ aimOnly: true, ...path.points[1] })
1049
+ objects.current.path.push({ repeatStart: true })
1050
+ for (const point of path.points) {
1051
+ if (skipPoints.find((skipPoint) => skipPoint.ordinal == point.ordinal)) {
1052
+ continue
1053
+ }
855
1054
  objects.current.path.push(point)
1055
+ if (pauseTimeInSeconds[point.ordinal]) {
1056
+ objects.current.path.push({ marker: 'pause', pauseSeconds: pauseTimeInSeconds[point.ordinal] })
1057
+ }
1058
+ }
1059
+ if (context.repeats) {
1060
+ objects.current.timeRepeats = toFinalValue(context.repeats.repeats)
1061
+ }
1062
+ // if the patrol does not start and end at the same spot then
1063
+ // go back to the start along the same path
1064
+
1065
+
1066
+ // if the start is not the end of the patrol then go backwards along the patrol
1067
+ if (JSON.stringify(path.points[0].point) !== JSON.stringify(path.points[path.points.length-1].point)) {
1068
+ for (const point of [...path.points].reverse().slice(1)) {
1069
+ if (skipPoints.find((skipPoint) => skipPoint.ordinal == point.ordinal)) {
1070
+ continue
1071
+ }
1072
+ objects.current.path.push(point)
1073
+ if (pauseTimeInSeconds[point.ordinal]) {
1074
+ objects.current.path.push({ marker: 'pause', pauseSeconds: pauseTimeInSeconds[point.ordinal] })
1075
+ }
1076
+ }
1077
+
1078
+ const secondPoint = path.points[1]
1079
+ objects.current.path.push({ ...secondPoint, aimOnly: true })
856
1080
  }
857
1081
  }
858
1082
  objects.runCommand = true
@@ -881,6 +1105,7 @@ const template = {
881
1105
  bridge: `{
882
1106
  ...next(operator), operator: operator, object: after[0], interpolate: [{ property: 'operator'}, { property: 'object' }]
883
1107
  }`,
1108
+ check: defaultContextCheckProperties(['object']),
884
1109
  semantic: ({api}) => {
885
1110
  api.armAction('up')
886
1111
  }
@@ -891,6 +1116,7 @@ const template = {
891
1116
  bridge: `{
892
1117
  ...next(operator), operator: operator, object: after[0], interpolate: [{ property: 'operator'}, { property: 'object' }]
893
1118
  }`,
1119
+ check: defaultContextCheckProperties(['object']),
894
1120
  semantic: ({api}) => {
895
1121
  api.armAction('down')
896
1122
  }
@@ -901,6 +1127,7 @@ const template = {
901
1127
  bridge: `{
902
1128
  ...next(operator), operator: operator, object: after[0], interpolate: [{ property: 'operator'}, { property: 'object' }]
903
1129
  }`,
1130
+ check: defaultContextCheckProperties(['object']),
904
1131
  semantic: ({api}) => {
905
1132
  api.clawAction('open')
906
1133
  }
@@ -911,6 +1138,7 @@ const template = {
911
1138
  bridge: `{
912
1139
  ...next(operator), operator: operator, object: after[0], interpolate: [{ property: 'operator'}, { property: 'object' }]
913
1140
  }`,
1141
+ check: defaultContextCheckProperties(['object']),
914
1142
  semantic: ({api}) => {
915
1143
  api.clawAction('close')
916
1144
  }
@@ -918,7 +1146,7 @@ const template = {
918
1146
  {
919
1147
  id: 'back',
920
1148
  isA: ['noun'],
921
- semantic: async ({objects, mentions, api, e, context, say}) => {
1149
+ semantic: async ({objects, api, e, context, say}) => {
922
1150
  await api.back()
923
1151
  }
924
1152
  },
@@ -931,6 +1159,7 @@ const template = {
931
1159
  isA: ['preposition'],
932
1160
  after: [['propertyOf', 1]],
933
1161
  bridge: "{ ...next(operator), operator: operator, point: after[0], interpolate: [{ property: 'operator' }, { property: 'point' }] }",
1162
+ check: defaultContextCheckProperties(['point']),
934
1163
  semantic: async ({objects, api, e, context}) => {
935
1164
  objects.runCommand = true
936
1165
  const point = await e(context.point)
@@ -941,11 +1170,11 @@ const template = {
941
1170
  id: "go",
942
1171
  level: 0,
943
1172
  // convolution: true,
944
- isA: ['verb', 'action'],
1173
+ isA: ['verb', 'repeatable', 'doAction'],
945
1174
  words: [
946
1175
  ...conjugateVerb('go'),
947
1176
  ],
948
- check: defaultContextCheckProperties(['direction', 'distance', 'to']),
1177
+ check: defaultContextCheckProperties(['direction', 'distance', 'to', 'points']),
949
1178
  bridge: `{
950
1179
  ...next(operator),
951
1180
  distance: distance?,
@@ -953,7 +1182,7 @@ const template = {
953
1182
  points: points?,
954
1183
  to: to?,
955
1184
  operator: operator,
956
- interpolate: [{ property: 'operator' }, { property: 'direction' }, { property: 'points' }, { property: 'to' }, { property: 'distance' }]
1185
+ interpolate: append(default(operator.interpolate, [{ property: 'operator' }]), [{ property: 'direction' }, { property: 'points' }, { property: 'to' }, { property: 'distance' }])
957
1186
  }`,
958
1187
  selector: {
959
1188
  arguments: {
@@ -964,7 +1193,7 @@ const template = {
964
1193
  },
965
1194
  },
966
1195
  semantic: async (args) => {
967
- const {context, objects, e, toArray, toEValue} = args
1196
+ const {api, toFinalValue, context, objects, e, toArray, toEValue} = args
968
1197
  if (context.distance) {
969
1198
  await handleDistance(args, context.distance)
970
1199
  }
@@ -978,25 +1207,32 @@ const template = {
978
1207
  objects.current.direction = context.direction.marker
979
1208
  }
980
1209
  }
1210
+ if (context.repeats) {
1211
+ objects.current.timeRepeats = toFinalValue(context.repeats.repeats)
1212
+ }
981
1213
  if (context.to) {
982
1214
  const evaluation = await e(context.to.point)
983
1215
  const point = toEValue(evaluation)
984
1216
  objects.current.path.push(point)
985
1217
  }
986
1218
  objects.runCommand = true
1219
+ await api.sendCommand()
987
1220
  },
988
1221
  },
989
1222
  {
990
1223
  id: 'turn',
991
- isA: ['verb'],
1224
+ isA: ['verb', 'action', 'repeatable'],
1225
+ before: ['thenAction'],
992
1226
  words: ['turn'],
993
1227
  bridge: `{
994
1228
  ...next(operator),
995
1229
  direction: direction,
996
- repeats: repeats?,
1230
+ operator: operator,
997
1231
  angle: angle?,
998
- interpolate: [{ context: operator }, { property: 'direction' }, { property: 'angle' }, { property: 'repeats' }] }
1232
+ interpolate: append(default(operator.interpolate, [{ property: 'operator'}]), [{ property: 'direction' }, { property: 'angle' }])
1233
+ }
999
1234
  `,
1235
+ check: defaultContextCheckProperties(['direction', 'angle']),
1000
1236
  selector: {
1001
1237
  arguments: {
1002
1238
  direction: "(@<= 'direction')",
@@ -1032,6 +1268,9 @@ const template = {
1032
1268
  return
1033
1269
  }
1034
1270
  }
1271
+ if (context.repeats) {
1272
+ objects.current.timeRepeats = toFinalValue(context.repeats.repeats)
1273
+ }
1035
1274
  current.justTurn = true
1036
1275
  objects.runCommand = true
1037
1276
  await api.sendCommand()
@@ -1041,17 +1280,24 @@ const template = {
1041
1280
  {
1042
1281
  id: 'pause',
1043
1282
  isA: ['verb'],
1044
- words: ['pause'],
1045
- bridge: "{ ...operator, time: or(time?, forTime), interpolate: [{ context: operator }, { property: 'time' }] }",
1046
- check: defaultContextCheckProperties(['time']),
1283
+ words: [
1284
+ ...conjugateVerb('pause'),
1285
+ ],
1286
+ bridge: "{ ...next(operator), timeAtPoint: timeAtPoint?, time: or(time?, forTime?), operator: operator, atPoint: atPoint?, interpolate: [{ property: 'operator' }, { property: 'time' }, { property: 'forTime' }, { property: 'atPoint' }, { property: 'timeAtPoint' } ] }",
1287
+ check: defaultContextCheckProperties(['timeAtPoint']),
1047
1288
  selector: {
1048
1289
  arguments: {
1049
1290
  forTime: "(@<= 'forQuantity' && context.quantity.unit.dimension == 'time')",
1050
1291
  time: "(@<= 'quantity' && context.unit.dimension == 'time')",
1292
+ atPoint: "(@<= 'atPoint')",
1293
+ timeAtPoint: "(@<= 'timeAtPoint')",
1051
1294
  },
1052
1295
  },
1053
- semantic: async ({context, mentioned, api, e, fragments, toFinalValue}) => {
1296
+ semantic: async ({context, remember, api, e, fragments, toFinalValue}) => {
1054
1297
  let time = context.time
1298
+ if (!time) {
1299
+ return
1300
+ }
1055
1301
  if (time.marker == 'forQuantity') {
1056
1302
  time = time.quantity
1057
1303
  }
@@ -1059,10 +1305,22 @@ const template = {
1059
1305
  const result = await e(instantiation)
1060
1306
  const seconds = toFinalValue(toFinalValue(result).amount)
1061
1307
  context.pauseSeconds = seconds
1062
- mentioned(context)
1308
+ remember(context)
1063
1309
  api.pause(seconds)
1064
1310
  }
1065
1311
  },
1312
+ {
1313
+ id: 'pause',
1314
+ level: 1,
1315
+ bridge: "{ ...repeatable, pause: operator, checks: append(repeatable.checks, ['pause']), repeatable: repeatable, interpolate: [{ property: 'repeatable' }, { property: 'pause', byPosition: true }] }",
1316
+ selector: {
1317
+ loose: "repeatable",
1318
+ arguments: {
1319
+ repeatable: "(@<= 'repeatable')",
1320
+ },
1321
+ },
1322
+ check: defaultContextCheckProperties(['repeatable', 'repeats'])
1323
+ },
1066
1324
  {
1067
1325
  id: 'stop',
1068
1326
  isA: ['verb'],
@@ -1070,7 +1328,7 @@ const template = {
1070
1328
  1: "{ marker: 'drone' }",
1071
1329
  },
1072
1330
  bridge: "{ ...next(operator), object: after[0], interpolate: [{ context: operator }, { property: 'object' }] }",
1073
- semantic: async ({mentioned, context, objects, api, say}) => {
1331
+ semantic: async ({context, objects, api, say}) => {
1074
1332
  await api.stop()
1075
1333
  await api.markCurrentPoint()
1076
1334
  }
@@ -1089,18 +1347,13 @@ const template = {
1089
1347
  semantics: [
1090
1348
  {
1091
1349
  match: ({context}) => context.marker == 'doAction',
1092
- apply: async ({context, e, toEValue, objects}) => {
1093
- const evaluated = await(e(context.action))
1094
- const path = toEValue(evaluated)
1095
- for (const point of path.points) {
1096
- objects.current.path.push(point)
1097
- }
1098
- objects.runCommand = true
1350
+ apply: async ({context, fragments, e, s, toEValue, toFinalValue, objects}) => {
1351
+ await s({ ...context, marker: 'patrol', path: context.action})
1099
1352
  }
1100
1353
  },
1101
1354
  {
1102
1355
  match: ({context, contextHierarchy}) => {
1103
- if (!context.pullFromContext || !context.evaluate || contextHierarchy.under(['doAction', 'evaluate'])) {
1356
+ if (!context.pullFromContext || !context.evaluate || contextHierarchy.under(['doAction', 'evaluate', 'patrol']) || context.instance) {
1104
1357
  return false
1105
1358
  }
1106
1359
 
@@ -1108,13 +1361,18 @@ const template = {
1108
1361
  return true
1109
1362
  }
1110
1363
  },
1111
- apply: async ({context, frameOfReference, toArray, fragments, stm, objects, mentioned, mentions, resolveEvaluate, _continue, contextHierarchy}) => {
1112
- const pathComponents = toArray(await mentions({ context: { marker: 'pathComponent' }, all: true }))
1364
+ apply: async ({context, frameOfReference, toArray, fragments, objects, remember, recall, resolveEvaluate, _continue, contextHierarchy}) => {
1365
+ const pathComponents = toArray(await recall({
1366
+ context: { marker: 'pathComponent' },
1367
+ all: true,
1368
+ stopCondition: (context) => context.marker == 'startPath',
1369
+ }))
1113
1370
  const path = (await fragments('path')).contexts()[0]
1114
1371
  delete path.value
1372
+ path.instance = true
1115
1373
  path.points = pathComponents.reverse()
1116
1374
  frameOfReference(path, { mentioned: 'points', reversed: true })
1117
- await mentioned(path)
1375
+ await remember(path)
1118
1376
 
1119
1377
  _continue() // let the call pick the object out from the stm
1120
1378
  },
@@ -1129,18 +1387,21 @@ const template = {
1129
1387
  return true
1130
1388
  }
1131
1389
  },
1132
- apply: async ({context, e, fragments, stm, toEValue, toArray, objects, mentioned, mentions, resolveEvaluate, _continue, contextHierarchy}) => {
1390
+ apply: async ({frameOfReference, context, e, fragments, stm, toEValue, toArray, objects, remember, recall, resolveEvaluate, _continue, contextHierarchy}) => {
1133
1391
  const evaluated = await e({...context, notUnderCall: true})
1134
1392
  const pointsContext = toEValue(evaluated)
1135
1393
  const pathComponents = toArray(pointsContext)
1136
1394
 
1137
1395
  const path = (await fragments('path')).contexts()[0]
1138
1396
  delete path.value
1139
- path.points = pathComponents.reverse()
1140
- await mentioned(path)
1397
+ path.instance = true
1398
+ path.points = [...pathComponents]
1399
+ frameOfReference(path, { mentioned: 'points', reversed: true })
1400
+ await remember(path)
1141
1401
  resolveEvaluate(context, path)
1142
1402
  },
1143
1403
  },
1404
+ /*
1144
1405
  {
1145
1406
  match: ({context}) => context.marker == 'thenTime',
1146
1407
  apply: async ({objects, api}) => {
@@ -1149,10 +1410,11 @@ const template = {
1149
1410
  }
1150
1411
  },
1151
1412
  },
1413
+ */
1152
1414
  {
1153
1415
  match: ({context}) => context.evaluate && ['start', 'end'].includes(context.marker) && context.objects && context.objects[1].marker == 'path',
1154
- apply: async ({gp, s, context, objects, fragments, resolveEvaluate, api, mentions}) => {
1155
- const path = await mentions({ context: context.objects[1] })
1416
+ apply: async ({gp, s, context, objects, fragments, resolveEvaluate, api, recall}) => {
1417
+ const path = await recall({ context: context.objects[1] })
1156
1418
  if (!path?.points) {
1157
1419
  return
1158
1420
  }
@@ -1163,6 +1425,29 @@ const template = {
1163
1425
  }
1164
1426
  }
1165
1427
  },
1428
+ {
1429
+ match: ({context, contextHierarchy}) =>
1430
+ context.evaluate &&
1431
+ ['start', 'end', 'point'].includes(context.marker) &&
1432
+ !context.propertyOf &&
1433
+ contextHierarchy.under('go') &&
1434
+ !contextHierarchy.under('call'),
1435
+ apply: async ({gp, s, toArray, context, objects, fragments, resolveEvaluate, api, recall}) => {
1436
+ const path = await recall({ context: { marker: 'path' } })
1437
+ if (!path?.points) {
1438
+ return
1439
+ }
1440
+
1441
+ if (context.marker == 'start') {
1442
+ resolveEvaluate(context, path?.points[0])
1443
+ } else if (context.marker == 'end') {
1444
+ resolveEvaluate(context, path?.points[path?.points.length-1])
1445
+ } else {
1446
+ const points = await recall({ context, frameOfReference: path })
1447
+ resolveEvaluate(context, toArray(points)[0])
1448
+ }
1449
+ }
1450
+ },
1166
1451
  {
1167
1452
  match: ({context}) => context.marker == 'speed' && context.evaluate,
1168
1453
  apply: async ({gp, s, context, objects, fragments, resolveEvaluate, api}) => {
@@ -1238,6 +1523,7 @@ knowledgeModule( {
1238
1523
  defaultContextCheck({ marker: 'path', exported: true,
1239
1524
  extra: [
1240
1525
  'points',
1526
+ 'instance',
1241
1527
  {
1242
1528
  property: 'namespaced',
1243
1529
  check: [
@@ -1262,11 +1548,13 @@ knowledgeModule( {
1262
1548
  ]
1263
1549
  }),
1264
1550
  defaultContextCheck({ marker: 'turn', exported: true, extra: ['direction', 'repeats'] }),
1551
+ defaultContextCheck({ marker: 'message', exported: true, extra: ['message'] }),
1265
1552
  defaultContextCheck({ marker: 'history', exported: true, extra: ['debug', 'pause', 'direction', 'speed', 'turn', 'time', 'sonic', 'batched', 'repeats', 'armAction', 'clawAction'] }),
1266
- defaultContextCheck(),
1553
+ // defaultContextCheck(),
1267
1554
  ],
1268
1555
  objects: [
1269
1556
  { km: 'stm' },
1557
+ { km: 'logging' },
1270
1558
  { path: ['history'] },
1271
1559
  { path: ['current'] },
1272
1560
  { path: ['runCommand'] },