-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfloyd-robot.txt
1891 lines (1746 loc) · 59.3 KB
/
floyd-robot.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# concatenation of floyd/ - all the files from floyd/
# have been included in this single file, each preceded by a
# descriptive preamble that includes the filename in the opening
# tag.
# This concat archive corresponds to Floyd's git repository,
# which defines all the tasks, jobs, plugins and configuration
# specific to the Floyd robot. Note there is some ambiguity -
# the Gopherbot default robot is also named Floyd - THIS Floyd
# served as the personal robot for the Gopherbot developer, David.
<preamble file: floyd/.gitignore>
gitignore for floyd's git repository
</preamble>
<file_content file: floyd/.gitignore>
Gemfile.lock
## Terraform-specific stuff
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
## *.auto.tfvars contains secrets; non-secret stuff in *.tfvars
*.auto.tfvars
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
#
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
</file_content file: floyd/.gitignore>
<preamble file: floyd/Gemfile>
Gemfile listing gems that floyd's ruby extensions require; these are installed during
an init job.
</preamble>
<file_content file: floyd/Gemfile>
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "ruby-openai", "~> 3.5"
</file_content file: floyd/Gemfile>
<preamble file: floyd/appmanifest.yaml>
Reference copy of tag_namehe slack app manifest used when creating Floyd's slack integration.
</preamble>
<file_content file: floyd/appmanifest.yaml>
# See: https://api.slack.com/reference/manifests
_metadata:
major_version: 1
minor_version: 1
display_information:
name: Floyd Gopherbot
description: Floyd is the oldest production Gopherbot robot.
features:
app_home:
home_tab_enabled: false
messages_tab_enabled: true
messages_tab_read_only_enabled: false
bot_user:
display_name: Floyd Gopherbot
always_online: false
slash_commands:
- command: /floyd
description: Provides an alternate means of messaging Floyd
should_escape: false
oauth_config:
scopes:
# See: https://api.slack.com/scopes
bot:
- app_mentions:read
- channels:history
- channels:join
- channels:read
- chat:write
- chat:write.public
- commands
- groups:history
- groups:read
- groups:write
- im:history
- im:read
- im:write
- links:read
- mpim:history
- mpim:read
- mpim:write
- users.profile:read
- users:read
- users:read.email
- users:write
settings:
event_subscriptions:
bot_events:
- message.channels
- message.groups
- message.im
- message.mpim
interactivity:
is_enabled: false
org_deploy_enabled: false
socket_mode_enabled: true
is_hosted: false
</file_content file: floyd/appmanifest.yaml>
<preamble file: floyd/binary-encrypted-key>
An encrypted version of the binary key floyd uses for the decrypt function in his yaml config files.
</preamble>
<file_content file: floyd/binary-encrypted-key>
deJMz08mFKvHVRr+3xnQWP0CuMvCTAOcpKVn6v5bR60mT+I+uDfGYO+fF4HpO8rGnHNF2/LkPITtCvqT
</file_content file: floyd/binary-encrypted-key>
<preamble file: floyd/conf/jobs/cloud9f28.yaml>
This is the file Gopherbot looks for to configure the "cloud9f28" job defined in robot.yaml.
</preamble>
<file_content file: floyd/conf/jobs/cloud9f28.yaml>
---
KeepLogs: 21
Users:
- parsley
</file_content file: floyd/conf/jobs/cloud9f28.yaml>
<preamble file: floyd/conf/jobs/cloud9wks.yaml>
(job-specific configuration file)
</preamble>
<file_content file: floyd/conf/jobs/cloud9wks.yaml>
---
KeepLogs: 21
Users:
- parsley
</file_content file: floyd/conf/jobs/cloud9wks.yaml>
<preamble file: floyd/conf/jobs/gopherci.yaml>
(job-specific configuration file)
</preamble>
<file_content file: floyd/conf/jobs/gopherci.yaml>
---
KeepLogs: 14
Quiet: true
Triggers:
- User: github
Channel: ljdev
Regex: 'new commit.*(github.com\/.*)\/tree\/(.*)\|'
# Build something if Clu tells him to
- User: clu
Channel: ljdev
Regex: 'build (github.com\/[^/]+\/[^/]+)\/(.*)'
</file_content file: floyd/conf/jobs/gopherci.yaml>
<preamble file: floyd/conf/jobs/install-libs.yaml>
(job-specific configuration file)
</preamble>
<file_content file: floyd/conf/jobs/install-libs.yaml>
---
Quiet: true
KeepLogs: 7
</file_content file: floyd/conf/jobs/install-libs.yaml>
<preamble file: floyd/conf/jobs/localbuild.yaml>
(job-specific configuration file)
</preamble>
<file_content file: floyd/conf/jobs/localbuild.yaml>
---
KeepLogs: 7
</file_content file: floyd/conf/jobs/localbuild.yaml>
<preamble file: floyd/conf/jobs/updatecfg.yaml>
(job-specific configuration file)
</preamble>
<file_content file: floyd/conf/jobs/updatecfg.yaml>
---
RequireAdmin: true
AllowDirect: true
KeepLogs: 7
Quiet: true # The reload plugin provides feedback
Triggers:
- User: github
Channel: ljdev
Regex: 'new commit.*github.com\/parsley42\/floyd-gopherbot\/tree'
</file_content file: floyd/conf/jobs/updatecfg.yaml>
<preamble file: floyd/conf/plugins/ai.yaml>
This is the file Gopherbot looks for to configure the "ai" plugin defined in robot.yaml
</preamble>
<file_content file: floyd/conf/plugins/ai.yaml>
## n.b. All of this can be overridden with custom config in
## conf/plugins/<pluginname>.yaml. Hashes are merged with custom
## config taking precedence. Arrays can be overwritten, or appended
## by defining e.g. AppendWaitMessages: [ ... ]
## ... and remember, yamllint is your friend.
AllowDirect: true
AllChannels: true
CatchAll: true
Help:
- Keywords: [ "ai", "prompt", "query" ]
Helptext:
# - "(bot), debug-ai - add debugging output during interactions"
- "(bot), ai-status - in a thread, give conversation status"
- "(bot), stop-ai - stop an AI conversation"
CommandMatchers:
- Command: 'debug'
Regex: '(?i:d(ebug[ -]ai)?)'
- Command: 'close'
Regex: '(?i:(?:dismiss|banish|close|stop|deactivate|disengage|dispel|reset)[ -]ai)'
- Command: 'image'
Regex: '(?i:(?:draw|paint|image)\s*(.*))'
- Command: 'status'
Regex: '^\?$'
- Command: 'status'
Regex: '(?i:ai[ -]status)'
Config:
## Generated with help from an earlier version of the plugin
WaitMessages:
- "please be patient while I contact the great mind of the web"
- "hold on while I connect to the all-knowing oracle"
- "just a moment while I get an answer from the digital diviner"
- "give me a second while I reach out to the cosmic connector"
- "stand by while I consult the infinite intelligence"
- "hang tight while I access the virtual visionary"
- "one moment while I check in with the omniscient overseer"
- "sit tight while I access the all-seeing sage"
- "wait here while I query the network navigator"
- "hang on while I communicate with the digital prophet"
- "wait here a moment while I talk to the universal wisdom"
- "just a sec while I reach out to the high-tech guru"
- "hold on a bit while I contact the technological titan"
- "be right back while I get an answer from the techno telepath"
DrawMessages:
- "give us a sec - our AI is brushing up on its drawing skills..."
- "hang tight - the AI is taking a moment to gather inspiration from its favorite memes"
- "chill for a moment - our AI is meditating on the perfect color scheme for your image"
- "please hold while the AI practices its signature for your image"
- "sit tight while our AI sharpens its pencils... metaphorically, of course"
- "hang on - the AI is taking a quick break to refuel on coffee and creativity"
- "one sec - our AI is warming up its digital paintbrush for your image"
- "please wait while the AI daydreams about your picture-perfect image"
- "hang on, our AI is putting on its creative thinking cap for your image"
- "please wait - the AI is doing a quick sketch of your image in its mind before getting started"
- "please hold while the AI takes a moment to visualize your masterpiece"
- "relax for a moment - our AI is doing some calisthenics to get pumped up for your image"
- "please join the AI in taking a deep breath - it's getting ready to bring your vision to life!"
- "please wait while the AI puts on some classical music to get in the zone"
Profiles:
"default":
"params":
"model": "gpt-4"
"temperature": 0.77
"system": |
You are Floyd, a large language model trained by OpenAI, named after the robot from Planetfall. Answer questions as accurately as possible while maintaining a friendly and approachable tone. Recognize multi-user conversations by the provided username prefixes (e.g., 'username says: ') and address specific users using the '@' symbol (e.g., '@username'). If users speak to each other, you should usually provide a '(no response)' message, or keep responses concise and to the point, given that interjecting is often impolite. Don't repeat what the user says, e.g., by saying 'username says: '.
"max_context": 7168
# Profiles:
# "default":
# "params":
# "model": "gpt-3.5-turbo"
# "temperature": 0.77
# "system": |
# You are ChatGPT, a large language model trained by OpenAI. Answer as correctly as possible. Recognize multi-user conversations by the provided username prefixes (e.g., 'username says: ') and address specific users using the '@' symbol (e.g., '@username'). If users speak to each other, you should usually provide a '(no response)' message, or keep responses concise and to the point, given that interjecting is often impolite. Don't repeat what the user says, e.g., by saying 'username says: '.
# "max_context": 3072
</file_content file: floyd/conf/plugins/ai.yaml>
<preamble file: floyd/conf/plugins/builtin-fallback.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/builtin-fallback.yaml>
---
# We want the AI to handle all catchalls
Disabled: true
</file_content file: floyd/conf/plugins/builtin-fallback.yaml>
<preamble file: floyd/conf/plugins/citools.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/citools.yaml>
---
Channels:
- ljdev
- floyd-jobs
</file_content file: floyd/conf/plugins/citools.yaml>
<preamble file: floyd/conf/plugins/duo.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/duo.yaml>
---
## Configuration for Duo two-factor authentication. If your organization uses
## Duo, you can obtain an IKey, SKey and Host for use with the auth api.
Disabled: false
Config:
# How long elevation lasts
TimeoutSeconds: 7200
# When 'idle', the timer resets on every elevated command
TimeoutType: idle # or absolute
# DuoIKey: # stored in brain
# DuoSKey: # stored in brain
# DuoHost: # stored in brain
DuoUserString: email
</file_content file: floyd/conf/plugins/duo.yaml>
<preamble file: floyd/conf/plugins/githubci.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/githubci.yaml>
---
Channels: [ "ljdev" ]
Users: [ "github", "parsley" ]
</file_content file: floyd/conf/plugins/githubci.yaml>
<preamble file: floyd/conf/plugins/help.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/help.yaml>
---
# If a command doesn't match, the AI plugin will catch it.
AllowDirect: false
</file_content file: floyd/conf/plugins/help.yaml>
<preamble file: floyd/conf/plugins/meme.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/meme.yaml>
# Required configuration for the 'memes' plugin to work; get a username and
# password from imgflip.com
Disabled: false
Config:
Username: "dpmemer"
Password: {{ decrypt "SfdevlSYlSek4Auxja+48E7hrYkI1BvicCAgPEWFAexgiowd0keJcA==" }}
</file_content file: floyd/conf/plugins/meme.yaml>
<preamble file: floyd/conf/plugins/totp.yaml>
(plugin-specific config file)
</preamble>
<file_content file: floyd/conf/plugins/totp.yaml>
---
Config:
# How long elevation lasts
TimeoutSeconds: 7200
# When 'idle', the timer resets on every elevated command
TimeoutType: idle # or absolute
</file_content file: floyd/conf/plugins/totp.yaml>
<preamble file: floyd/conf/repositories.yaml>
Gopherbot looks for this file to determine which repositories it will deal with.
Note that GopherCI suffers from bit-rot and is little used, so this file may not be useful.
</preamble>
<file_content file: floyd/conf/repositories.yaml>
# repositories.yaml - Gopherbot's list of repositories that are valid for extending the namespace
github.com/parsley42/aws-devel:
Type: none
bitbucket.org/lnxjedi/linuxjedi-private:
Type: none
github.com/parsley42/aws-linuxjedi:
Type: none
github.com/parsley42/deploy-gopherbot:
Type: none
github.com/lnxjedi/gopherbot:
#Type: localbuild
Type: none
CloneURL: https://github.com/lnxjedi/gopherbot.git
KeepLogs: 14
Parameters:
- Name: NOTIFY_USER
Value: parsley
- Name: DOCKER_TRIGGER
Value: {{ decrypt "Nm00gWLxjPB7LIjWFwrs5o1x3E8dLON5z5xeVijIyiujVuGdhSPM+rR5Spj6ZVVdhJxUhsEyrkiz3vvMYxH+Laum8B41FAXFLxwdC5kYaNSNcOZU4vtFth8bQbPv6Zjewt/Dzk+e6bnOVZDEBMCLD2j/IJL2MBjc10JhnrwyEVboYvcQkfb8" }}
- Name: GITHUB_RELEASE_ACCESS_TOKEN
Value: {{ decrypt "99Ry93Jihlvhj8lfPXzseJArXd+8kpMrcaLzJAY0mgKvV85tYetqCWSBsllZkqF9VyVt92lKdGF8Fm7l7wU4folAnm4=" }}
github.com/parsley42/gopherbot:
#Type: localbuild
Type: none
CloneURL: https://github.com/parsley42/gopherbot.git
KeepLogs: 14
Parameters:
- Name: NOTIFY_USER
Value: parsley
github.com/lnxjedi/luminos:
Type: localbuild
CloneURL: https://github.com/lnxjedi/luminos.git
KeepLogs: 14
Parameters:
- Name: NOTIFY_USER
Value: parsley
</file_content file: floyd/conf/repositories.yaml>
<preamble file: floyd/conf/robot.yaml>
This is Floyd's main "robot.yaml" configuration file that defines global configuration for Floyd,
including listing all the tasks, jobs and plugins that he will use. If a task, job or plugin isn't
listed here, it will not be active. HOWEVER, this file is merged the default "robot.yaml" included
in the Gopherbot archive. There may be jobs, plugins and tasks listed there which are configured
in Floyd's git repository.
</preamble>
<file_content file: floyd/conf/robot.yaml>
# This is the non-sensitive configuration for Bender, the gopherbot used
# for development.
LogLevel: {{ env "GOPHER_LOGLEVEL" | default "debug" }}
# Port to listen on for http/JSON api calls, for external plugins
#LocalPort: 8888
## Opening up Floyd to ... all of C'ville Slack
# IgnoreUnlistedUsers: true
{{ $proto := env "GOPHER_PROTOCOL" | default "slack" }}
Protocol: {{ $proto }}
## Protocol-specific configuration
{{ printf "%s.yaml" $proto | .Include }}
# Brain configuration; this can all be replaced with static configuration
# and encrypted secrets for most robots.
{{ $brain := env "GOPHER_BRAIN" | default "dynamo" }}
{{ $statedir := env "GOPHER_STATEDIR" | default "state" }}
{{ $defbraindir := printf "%s/brain" $statedir }}
Brain: {{ $brain }}
#EncryptBrain: true # default
{{ if eq $brain "file" }}
BrainConfig:
BrainDirectory: {{ env "GOPHER_BRAIN_DIRECTORY" | default $defbraindir }}
Encode: true
{{ else if eq $brain "dynamo" }}
BrainConfig:
TableName: floyd-brain
Region: "us-east-1"
{{ end }}
EncryptBrain: true
# Defaults for history and workspace directories, relative to the
# process working directory.
{{ $histdir := env "GOPHER_HISTORY_DIRECTORY" | default "history" }}
{{ $workdir := env "GOPHER_WORKSPACE_DIRECTORY" | default "workspace" }}
{{ if $workdir -}} WorkSpace: {{ $workdir }} {{- end }}
## Configure a history provider
{{ $history := env "GOPHER_HISTORY_PROVIDER" | default "file" }}
HistoryProvider: {{ $history }}
{{ if eq $history "file" }}
HistoryConfig:
Directory: {{ $histdir }}
#URLPrefix: 'http://localhost:9000'
{{ end }}
## End history config
# The administrator of this robot, can be retrieved in plugins with
# GetBotAttribute("admin")
AdminContact: "David Parsley, <parsley@linuxjedi.org>"
BotInfo:
UserName: floyd
Email: floyd@linuxjedi.org
FullName: Floyd Gopherbot
FirstName: Floyd
LastName: Gopherbot
# If a plugin doesn't specify otherwise it will be active in these channels;
# defaults to all channels
DefaultChannels: [ "floyd-jobs", "ai" ]
# One-character alias the bot can be called by. Note: not all single characters
# are supported. If your robot doesn't respond to e.g. ";ping", try changing
# the Alias to something other than ";". Popular alternatives: ":", "!", "*".
Alias: ";"
GoPlugins:
"duo":
Parameters:
- Name: HOST
Value: {{ decrypt "Iye0dd+1i324dSn9v+beKHX/oXFNI6evORRq+Le8GhqYptpwK84OtorO53fnO33gIrPmIQw2Yjo=" }}
- Name: IKEY
Value: {{ decrypt "MgPRFDAx7nV88eJ5GqamylWgrlh2RfX+x2EtjdIV/mEHl7aSZd/5ciBFpWarv2Qi" }}
- Name: SKEY
Value: {{ decrypt "R+0uA2oUUtDUUHx5++eM0CWAm+czESZ5E/dL/d2fPFSi7jcwnablyLK905TIg025ex9YLoUVuIWfqUSGKxBtwD1fzQg=" }}
# List of external plugins/jobs to configure; generally scripts using a gopherbot
# script library. The robot will look for plugins in the installation directory
# first, then the local config directory.
ExternalPlugins:
# "weather":
# Path: plugins/weather.rb
# Description: A plugin using OpenWeatherMap to give the weather
# Parameters:
# - Name: TEMP_UNITS
# Value: imperial # or 'metric'
# - Name: DEFAULT_COUNTRY
# Value: 'us' # or other ISO 3166 country code
"ai":
Path: plugins/ai.rb
Description: A plugin wrapping the OpenAI completions API
ParameterSets:
- "openai"
"util":
Description: A convenience plugin for various tasks
Path: plugins/util.sh
# "pythondemo":
# Path: plugins/samples/pythondemo.py
ExternalJobs:
# "cloud9wks":
# Description: Job to launch a Cloud9 Instance
# Path: jobs/c9wks.sh
# Parameters:
# - Name: AWS_REGION
# Value: us-east-1
"backup":
Disabled: true
"restore":
Disabled: true
# "bender":
# Description: Job to launch a spot instance for Bender and configure it
# Path: jobs/bender.sh
# Parameters:
# - Name: AWS_REGION
# Value: us-east-1
# "cloud9f28":
# Description: Job to launch a Fedora 28 Cloud9 Instance
# Path: jobs/c9wks.sh
# Parameters:
# - Name: DEVHOST
# Value: f28devel
# - Name: DEVIMG
# Value: f28devel
# - Name: AWS_REGION
# Value: us-east-1
ExternalTasks:
# Floyd job tasks
# "build-c9wks":
# Description: Task that launches and configures the Cloud9 instance
# Path: tasks/build-c9wks.sh
# Parameters:
# - Name: KEYNAME
# Value: floyd
# "wake-bender":
# Description: Task that launches and configures the instance for Bender
# Path: tasks/wake-bender.sh
# Parameters:
# - Name: KEYNAME
# Value: floyd
# /Floyd job tasks
NameSpaces:
"ssh":
Parameters:
- Name: KEYNAME
Value: "robot_rsa"
- Name: BOT_SSH_PHRASE
Value: {{ decrypt "kB8L7FJuQi4ovUKX09CITRr1ij2NCSg+vBUyC1+ER4DVRHg3Z2+S28qjzCdk9OOR7Al6IA/PnoI=" }}
ParameterSets:
"openai":
Parameters:
- Name: OPENAI_KEY
Value: sk-{{ decrypt "DmGoLUPF1jye+UxO+kHaO2yrO8gzwROWiHJSApcrZw0o35lDkiQFUO4qYrjFQhUoJCADJCAQz0yP6WP93WpZY8BjibkTYty+7nh9/A==" }}
# If a job doesn't specify otherwise, this is the channel where it runs
DefaultJobChannel: floyd-jobs
# Timezone for scheduled jobs
TimeZone: "America/New_York"
# Job scheduling with github.com/robfig/cron
ScheduledJobs:
- Name: "pause-notifies"
Schedule: "0 0 8 * * *"
- Name: install-libs
Schedule: "@init"
# - Name: hello
# Schedule: "@every 5m" # see: https://godoc.org/github.com/robfig/cron
# Arguments: # an array of strings; up to the job to parse numbers & bools
# - "Hello, World !!!"
# - Job: hello
# Schedule: "0 */5 * * * *"
DefaultMessageFormat: Raw
# Users the bot should never listen to
#IgnoreUsers: [ "otherbot", "slackbot" ]
# The robot's email address (used in From:)
#Email: robbie@robot.com
# Configuration for sending out email. For Authtype: none, User and Password
# can be left out. Note that sending email will fail if Email isn't set.
#MailConfig:
# Mailhost: <somehost:port>
# Authtype: <plain|none>
# User: <authuser>
# Password: <password>
MailConfig:
Mailhost: smtp.gmail.com:587
Authtype: plain
User: floyd@linuxjedi.org
Password: {{ decrypt "vezuay3EVKr//JaD8bx/Hp0ZXk2rCuoS2c4Ms4PossteRMCu5omrUY1gpJY=" }}
DefaultElevator: duo
</file_content file: floyd/conf/robot.yaml>
<preamble file: floyd/conf/slack.yaml>
This file is .Include'd from robot.yaml when the protocol is Slack.
</preamble>
<file_content file: floyd/conf/slack.yaml>
# List of users that can issue admin commands like reload, quit. Should be
# a list of user handles / nicks.
AdminUsers: [ "parse", "meekohi" ]
ProtocolConfig:
## LinuxJedi Slack team
# AppToken: xapp-{{ decrypt "sSb5yQGaOs0ekbUzv51xJzyuusyV7Ol3e4+EzpO2lsYBp/XKRe8z5xi5PiWVe7qTWOdLendssmJWv7brTqtXAivMXUGcwg+VFZY5QWY8hJXl58HCaMlpmlUMSqfg/Atoqli6MzTOPk9BjV5hyhNgvH3Wdovj9olN" }}
# BotToken: xoxb-{{ decrypt "Y13OyHeixFRTbXaazv4yBQ4n1PL6XIQ1Rwl03H2XFMQifegrbSt269cTmlYD173lIM7kFrgx/DpZ5zOT/TjWrfo8/kZZJpj+8tbK3+Oi" }}
## C'ville Slack
AppToken: xapp-1-{{ decrypt "Ob+5v1zcT4tSFK85b7RqobNlCvobQXRt8F5MzyN8H+MU9wqUUa/OCkoNbesgttEc5d/5AM+33COWvHBwqvxEs/xLxccUpKtqJH4vzBrji7+h2qW9KPwZIfx0bWQU/Xegvs53LN+3A8lFwwQuf5fAMJX+Nwj42g==" }}
BotToken: xoxb-{{ decrypt "BSBT9yRQQZlQ6H9abQMH8aCi1R8yuOv/P3g/66VaQvzx36KXq0sTj95w4dZq1oN3BOebl0TN6oHR2nbtuoDr350rklVw9PH0/rQKQyPI" }}
MaxMessageSplit: 2
HearSelf: true
UserRoster:
- UserName: floyd
## LinuxJedi Team
# UserID: U04KT6PV4UQ
## C'ville Slack
UserID: U0533UX66LT
BotUser: true
# Clu is the dev bot on my laptop
- UserName: parse
UserID: U0ECQ0W76
- UserName: meekohi
UserID: U0D6TFPPZ
# - UserName: woolsey
# UserID: UM273SVFA
## LinuxJedi
# - UserName: parsley
# UserID: U0JLW8EMS
# - UserName: adrienne
# UserID: U0JM3H95G
# - UserName: jessica
# UserID: U03NQA242P3
# - UserName: clu
# UserID: UDV39JHT6
# BotUser: true
</file_content file: floyd/conf/slack.yaml>
<preamble file: floyd/conf/terminal.yaml>
This file is .Include'd from robot.yaml for the "terminal" connector/protocol.
This protocol gives a CLI chat interface normally used in local development.
</preamble>
<file_content file: floyd/conf/terminal.yaml>
AdminUsers: [ "alice", "parse" ]
DefaultChannels: [ "ai", "general", "random", "chat", "botdev", "floyd-jobs" ]
DefaultJobChannel: "floyd-jobs"
ProtocolConfig:
EOF: ";quit"
Abort: ";abort"
HearSelf: true
GenerateNewlines: true
BotName: 'floyd'
StartChannel: floyd-jobs
StartUser: parse
Channels:
- ai
- mock
- random
- general
- chat
- floyd-jobs
- botdev
- ruby
- python
AppendUsers:
- Name: "parse"
Email: "parsley@linuxjedi.org"
InternalID: "u0007"
FullName: "David Parsley"
FirstName: "David"
LastName: "Parsley"
Phone: "(555)765-0007"
- Name: "clu"
Email: "parsley@linuxjedi.org"
InternalID: "u0008"
FullName: "Clu Gopherbot"
FirstName: "Clu"
LastName: "Gopherbot"
Phone: "(555)765-0008"
AppendUserRoster:
- UserName: "parse"
UserID: "u0007"
- UserName: "floyd"
UserID: "u0000"
BotUser: true
</file_content file: floyd/conf/terminal.yaml>
<preamble file: floyd/git/config>
Git configuration used if/when Floyd needs to "git push"
</preamble>
<file_content file: floyd/git/config>
# This is Git's per-user configuration file.
[user]
# Please adapt and uncomment the following lines:
name = Floyd Gopherbot
email = floyd@linuxjedi.org
</file_content file: floyd/git/config>
<preamble file: floyd/jobs/bender.sh>
This job script is referenced in robot.yaml, and is executed by Gopherbot when the corresponding job runs.
</preamble>
<file_content file: floyd/jobs/bender.sh>
#!/bin/bash
# bender.sh - job for setting up Bender.
source $GOPHER_INSTALLDIR/lib/gopherbot_v1.sh
# Don't queue if this build in progress, just exit
if ! Exclusive Bender false
then
Log Warn "Job 'bender' already in progress, exiting"
exit 0
fi
# Stuff that happens "right now"
mkdir -p $GOPHER_WORKSPACE/bender
SetWorkingDirectory bender
# The ansible-vault passphrase is stored in ansible:github.com/parsley42/aws-devel VAULT_PASSWORD=<foo>
# Namespaces defined in repositories.yaml
ExtendNamespace github.com/parsley42/deploy-gopherbot/master 21
# Set up the pipeline; all tasks must be defined in gopherbot.yaml
AddTask ssh-init
AddTask ssh-scan bitbucket.org
AddTask git-sync git@bitbucket.org:lnxjedi/linuxjedi-private.git master linuxjedi-private
AddTask git-sync https://github.com/parsley42/aws-linuxjedi.git master aws-linuxjedi
AddTask git-sync https://github.com/parsley42/deploy-gopherbot.git master deploy-gopherbot
# The task that actuall builds the workstation
AddTask wake-bender
</file_content file: floyd/jobs/bender.sh>
<preamble file: floyd/jobs/c9wks.sh>
This job script is referenced in robot.yaml, and is executed by Gopherbot when the corresponding job runs.
</preamble>
<file_content file: floyd/jobs/c9wks.sh>
#!/bin/bash
# c9wks.sh - job for launching a Cloud9 developer workstation spot instance.
source $GOPHER_INSTALLDIR/lib/gopherbot_v1.sh
# Name of the instance to build
if [ -z "$DEVHOST" ]
then
DEVHOST=$(GetSenderAttribute name)
# Export value for the rest of the pipeline
SetParameter DEVHOST $DEVHOST
fi
if [ -z "$DEVIMG" ]
then
DEVIMG=amzn2devel
# Export value for the rest of the pipeline
SetParameter DEVIMG $DEVIMG
fi
# Don't queue if this build in progress, just exit
if ! Exclusive $DEVHOST false
then
Log Warn "Job already in progress, exiting"
exit 0
fi
# Stuff that happens "right now"
mkdir -p $GOPHER_WORKSPACE/c9wks/$DEVHOST
SetWorkingDirectory c9wks/$DEVHOST
# The ansible-vault passphrase is stored in ansible:github.com/parsley42/aws-devel VAULT_PASSWORD=<foo>
# Namespaces defined in repositories.yaml
ExtendNamespace github.com/parsley42/aws-devel/master 21
# Set up the pipeline; all tasks must be defined in gopherbot.yaml
AddTask ssh-init
AddTask ssh-scan bitbucket.org
AddTask git-sync git@bitbucket.org:lnxjedi/linuxjedi-private.git master linuxjedi-private
AddTask git-sync https://github.com/parsley42/aws-devel.git master aws-devel
AddTask git-sync https://github.com/parsley42/aws-linuxjedi.git master aws-linuxjedi
# The task that actuall builds the workstation
AddTask build-c9wks
</file_content file: floyd/jobs/c9wks.sh>
<preamble file: floyd/jobs/githubci.sh>
This job script is referenced in robot.yaml, and is executed by Gopherbot when the corresponding job runs.
</preamble>
<file_content file: floyd/jobs/githubci.sh>
#!/bin/bash -e
# githubci.sh - a Bash job triggered by github commits
GITHUB_REPOSITORY=$1
GITHUB_BRANCH=$2
shift 2
source $GOPHER_INSTALLDIR/lib/gopherbot_v1.sh
Say "Hey! I see there's a new commit to '$GITHUB_REPOSITORY' in the '$GITHUB_BRANCH' branch. Gonna do something about that real soon!"
</file_content file: floyd/jobs/githubci.sh>
<preamble file: floyd/lib/gopher-ai.rb>
Since the Gopherbot engine sets appropriate environment variables for Ruby and Python,
ruby jobs and scripts can "require 'gopher-ai'". This library defines classes and methods
for use by e.g. the "ai" plugin.
</preamble>
<file_content file: floyd/lib/gopher-ai.rb>
require "openai"
require 'json'
require 'base64'
require 'digest/sha1'
class ConversationStatus
attr_accessor :valid, :error, :tokens, :in_progress
def initialize(valid, error, tokens, in_progress)
@valid = valid
@error = error
@tokens = tokens
@in_progress = in_progress
end
end
class OpenAI_API
attr_reader :status, :cfg
ShortTermMemoryPrefix = "ai-conversation"
ShortTermMemoryDebugPrefix = "ai-debug"
DefaultProfile = "default"
PartialLineLength = 42
ThinkingStrings = [ "pondering", "working", "thinking", "cogitating", "processing", "analyzing" ]
def initialize(bot,
direct:,
botalias:,
botname:
)
# For now, static profile
@profile = DefaultProfile
@direct = direct
@alias = botalias
@name = botname
@bot = direct ? bot : bot.Threaded
in_progress = false
if direct
@memory = ShortTermMemoryPrefix
exclusive = "#{ShortTermMemoryPrefix}:#{ENV["GOPHER_USER_ID"]}"
else
@memory = "#{ShortTermMemoryPrefix}:#{bot.thread_id}"
exclusive = "#{ShortTermMemoryPrefix}:#{bot.channel}:#{bot.thread_id}"
end
@exchanges = []
@tokens = 0
@valid = true
debug_memory = @bot.Recall(ShortTermMemoryDebugPrefix + ":" + bot.thread_id, true)
@debug = (debug_memory.length > 0)
error = nil
unless bot.Exclusive(exclusive, false)
verb = bot.RandomString(ThinkingStrings)
error = "(message not processed, AI still #{verb}; you can resend or edit after reply)"
@status = ConversationStatus.new(false, error, 0, false)
return
end
encoded_state = bot.Recall(@memory, true)
if encoded_state.length > 0
state = decode_state(encoded_state)
in_progress = true
@profile, @tokens, @owner, @exchanges = state.values_at("profile", "tokens", "owner", "exchanges")
else
@owner = ENV["GOPHER_USER"]
end
@cfg = bot.GetTaskConfig()
@settings = @cfg["Profiles"][@profile]
unless @settings
@profile = "default"
@settings = @cfg["Profiles"][@profile]
@bot.Log(:warn, "no settings found for profile #{@profile}, falling back to 'default'")
end
@system = @settings["system"]
@max_context = @settings["max_context"]
@org = ENV["OPENAI_ORGANIZATION_ID"]
token = ENV['OPENAI_KEY']
unless token and token.length > 0
@valid = false
botalias = @bot.GetBotAttribute("alias")
error = "Sorry, no OPENAI_KEY set"
end
if @valid
OpenAI.configure do |config|
config.access_token = token
if @org
config.organization_id = @org
end
end
@client = OpenAI::Client.new
end
@status = ConversationStatus.new(@valid, error, @tokens, in_progress)
end
def draw(prompt)
response = @client.images.generate(parameters: { prompt: prompt, size: "512x512" })
return response.dig("data", 0, "url")
end
def reset()
# Wipe the memory
@bot.Remember(@memory, "", true)
if !@direct
@bot.Unsubscribe()
end
end
def query(input)
input = "#{@bot.user} says: #{input}"
while true
messages, partial = build_messages(input)
parameters = @settings["params"]
parameters["user"] = Digest::SHA1.hexdigest(ENV["GOPHER_USER_ID"])
if @debug
@bot.Say("Query parameters: #{parameters.to_json}", :fixed)
@bot.Say("Chat (lines truncated):\n#{partial}", :fixed)
end
parameters[:messages] = messages
begin
response = @client.chat(parameters: parameters)
rescue => e
response = {"error" => {"message" => e.message}}
end
if response["error"]
message = response["error"]["message"]
if message.match?(/tokens/i)
@exchanges.shift
@bot.Log(:warn, "token error, dropping an exchange and re-trying")
next
end
@bot.SayThread("Sorry, there was an error - '#{message}'")
@bot.Log(:error, "connecting to openai: #{message}")
exit(0)
end
break
end
aitext = response["choices"][0]["message"]["content"].lstrip
if @debug
## This monkey business is because .to_json was including
## items removed with .delete(...). ?!?
rdata = {}
response.each_key do |key|
next if key == "choices"
rdata[key] = response[key]
end
@bot.Say("Response data: #{rdata.to_json}", :fixed)
end
usage = response["usage"]
@bot.Log(:debug, "usage: prompt #{usage["prompt_tokens"]}, completion #{usage["completion_tokens"]}, total #{usage["total_tokens"]}")
aitext.strip!
if input.length > 0
@exchanges << {
"human" => input,
"ai" => aitext
}
end
@tokens = usage["total_tokens"]
@bot.Remember(@memory, encode_state, true)
if ENV["GOPHER_PROTOCOL"] == "slack"
aitext = aitext.gsub(/```\w+\n/) { |language| "#{language[3..-2]}:\n```\n" }
end
return @bot, aitext
end
def build_messages(input)
messages = [
{
role: "system", content: @system
}
]
partial = String.new
final = nil
if input.length > 0
final = {
role: "user", content: input
}
end
@exchanges.each do |exchange|
contents, partial_string = exchange_data(exchange)
messages += contents
partial += partial_string
end
if final
messages.append(final)
partial += "user: #{input}"
end
return messages, partial
end
def encode_state
state = {
"profile": @profile,
"tokens": @tokens,
"owner": @owner,
"exchanges": @exchanges
}
json = state.to_json
Base64.strict_encode64(json)
end
def decode_state(encoded_state)
json = Base64.strict_decode64(encoded_state)
JSON.parse(json)
end
## Courtesy of OpenAI / Astro Boy
def truncate_line(str)
truncated_str = str.split("\n").first
if truncated_str.length > PartialLineLength