@gnar-engine/cli 1.0.0 → 1.0.2
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/assets/gnar-engine-logo-white.svg +9 -0
- package/bootstrap/deploy.localdev.yml +51 -0
- package/bootstrap/secrets.localdev.yml +27 -0
- package/bootstrap/services/agent/Dockerfile +23 -0
- package/bootstrap/services/agent/notes.md +28 -0
- package/bootstrap/services/agent/package.json +16 -0
- package/bootstrap/services/agent/src/app.js +52 -0
- package/bootstrap/services/agent/src/commands/agent.handler.js +104 -0
- package/bootstrap/services/agent/src/config.js +52 -0
- package/bootstrap/services/agent/src/controllers/http.controller.js +44 -0
- package/bootstrap/services/agent/src/controllers/message.controller.js +51 -0
- package/bootstrap/services/agent/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/agent/src/db/migrations/02-agent-service-init.js +36 -0
- package/bootstrap/services/agent/src/policies/agent.policy.js +13 -0
- package/bootstrap/services/agent/src/schema/Agent.schema.js +17 -0
- package/bootstrap/services/agent/src/services/agent.service.js +259 -0
- package/bootstrap/services/agent/src/services/chatgpt.service.js +46 -0
- package/bootstrap/services/agent/src/services/manifest.service.js +21 -0
- package/bootstrap/services/control/Dockerfile +23 -0
- package/bootstrap/services/control/Dockerfile.prod +37 -0
- package/bootstrap/services/control/README.md +25 -0
- package/bootstrap/services/control/package.json +16 -0
- package/bootstrap/services/control/src/app.js +45 -0
- package/bootstrap/services/control/src/commands/control.handler.js +231 -0
- package/bootstrap/services/control/src/commands/service.handler.js +81 -0
- package/bootstrap/services/control/src/commands/task.handler.js +247 -0
- package/bootstrap/services/control/src/config.js +55 -0
- package/bootstrap/services/control/src/controllers/http.controller.js +228 -0
- package/bootstrap/services/control/src/controllers/message.controller.js +40 -0
- package/bootstrap/services/control/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/control/src/db/migrations/02-control-service-init.js +60 -0
- package/bootstrap/services/control/src/db/migrations/03-alter-tasks.js +29 -0
- package/bootstrap/services/control/src/policies/task.policy.js +53 -0
- package/bootstrap/services/control/src/schema/control.schema.js +42 -0
- package/bootstrap/services/control/src/services/registry.service.js +83 -0
- package/bootstrap/services/control/src/services/reset.service.js +28 -0
- package/bootstrap/services/control/src/services/task.service.js +153 -0
- package/bootstrap/services/control/src/tests/control.test.js +50 -0
- package/bootstrap/services/notification/Dockerfile +23 -0
- package/bootstrap/services/notification/Dockerfile.prod +37 -0
- package/bootstrap/services/notification/README.md +3 -0
- package/bootstrap/services/notification/package.json +34 -0
- package/bootstrap/services/notification/src/app.js +51 -0
- package/bootstrap/services/notification/src/commands/command-bus.js +20 -0
- package/bootstrap/services/notification/src/commands/handlers/control.handler.js +18 -0
- package/bootstrap/services/notification/src/commands/handlers/notification.handler.js +157 -0
- package/bootstrap/services/notification/src/config.js +15 -0
- package/bootstrap/services/notification/src/controllers/message.controller.js +82 -0
- package/bootstrap/services/notification/src/services/logger.service.js +16 -0
- package/bootstrap/services/notification/src/services/ses.service.js +23 -0
- package/bootstrap/services/notification/src/templates/admin-order-recieved.hbs +136 -0
- package/bootstrap/services/notification/src/templates/admin-subscription-failed.hbs +87 -0
- package/bootstrap/services/notification/src/templates/customer-order-recieved.hbs +132 -0
- package/bootstrap/services/notification/src/templates/customer-subscription-failed.hbs +77 -0
- package/bootstrap/services/notification/src/tests/notification.test.js +0 -0
- package/bootstrap/services/portal/Dockerfile +23 -0
- package/bootstrap/services/portal/Dockerfile.remote +40 -0
- package/bootstrap/services/portal/README.md +22 -0
- package/bootstrap/services/portal/nginx.conf +12 -0
- package/bootstrap/services/portal/package.json +59 -0
- package/bootstrap/services/portal/public/favicon.ico +0 -0
- package/bootstrap/services/portal/public/gnar-white.png +0 -0
- package/bootstrap/services/portal/public/gnarengine-logo-black.png +0 -0
- package/bootstrap/services/portal/public/index.html +43 -0
- package/bootstrap/services/portal/public/logo192.png +0 -0
- package/bootstrap/services/portal/public/logo512.png +0 -0
- package/bootstrap/services/portal/public/manifest.json +25 -0
- package/bootstrap/services/portal/public/robots.txt +3 -0
- package/bootstrap/services/portal/src/App.js +56 -0
- package/bootstrap/services/portal/src/assets/Logo_Anchord_Black.svg +1 -0
- package/bootstrap/services/portal/src/assets/Logo_Anchord_Black_Green.svg +1 -0
- package/bootstrap/services/portal/src/assets/Logo_Anchord_White_Green.svg +1 -0
- package/bootstrap/services/portal/src/assets/activity.svg +3 -0
- package/bootstrap/services/portal/src/assets/arrow.svg +3 -0
- package/bootstrap/services/portal/src/assets/bin-white.svg +3 -0
- package/bootstrap/services/portal/src/assets/bin.svg +3 -0
- package/bootstrap/services/portal/src/assets/check.svg +3 -0
- package/bootstrap/services/portal/src/assets/chevron.svg +3 -0
- package/bootstrap/services/portal/src/assets/contact.svg +3 -0
- package/bootstrap/services/portal/src/assets/dots-vertical.svg +5 -0
- package/bootstrap/services/portal/src/assets/eye-off.svg +3 -0
- package/bootstrap/services/portal/src/assets/eye.svg +4 -0
- package/bootstrap/services/portal/src/assets/gnar-engine-black.svg +47 -0
- package/bootstrap/services/portal/src/assets/gnar-engine-white.svg +47 -0
- package/bootstrap/services/portal/src/assets/gnar_engine.svg +3 -0
- package/bootstrap/services/portal/src/assets/gnarengine-logo-black.png +0 -0
- package/bootstrap/services/portal/src/assets/home.svg +3 -0
- package/bootstrap/services/portal/src/assets/link.svg +3 -0
- package/bootstrap/services/portal/src/assets/lock.svg +3 -0
- package/bootstrap/services/portal/src/assets/package.svg +4 -0
- package/bootstrap/services/portal/src/assets/raffle.svg +3 -0
- package/bootstrap/services/portal/src/assets/settings.svg +4 -0
- package/bootstrap/services/portal/src/assets/shopping-bag.svg +3 -0
- package/bootstrap/services/portal/src/assets/user-black.svg +3 -0
- package/bootstrap/services/portal/src/assets/user.svg +3 -0
- package/bootstrap/services/portal/src/assets/users.svg +3 -0
- package/bootstrap/services/portal/src/assets/wallet.svg +3 -0
- package/bootstrap/services/portal/src/css/style.css +1007 -0
- package/bootstrap/services/portal/src/data/data.js +70 -0
- package/bootstrap/services/portal/src/features/attributeFormRow/AttributeFormRow.jsx +32 -0
- package/bootstrap/services/portal/src/features/billingShipping/BillingShipping.jsx +160 -0
- package/bootstrap/services/portal/src/features/crud/crudEdit.less +230 -0
- package/bootstrap/services/portal/src/features/crud/crudList.less +134 -0
- package/bootstrap/services/portal/src/features/crud/crudPage.less +31 -0
- package/bootstrap/services/portal/src/features/crudContact/CrudContactList.jsx +108 -0
- package/bootstrap/services/portal/src/features/crudContact/CrudContactSingle.jsx +243 -0
- package/bootstrap/services/portal/src/features/crudOrder/CrudOrderList.jsx +109 -0
- package/bootstrap/services/portal/src/features/crudOrder/CrudOrderSingle.jsx +315 -0
- package/bootstrap/services/portal/src/features/crudProducts/CrudProductList.jsx +104 -0
- package/bootstrap/services/portal/src/features/crudProducts/CrudProductSingle.jsx +388 -0
- package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesList.jsx +104 -0
- package/bootstrap/services/portal/src/features/crudRaffles/CrudRafflesSingle.jsx +208 -0
- package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionList.jsx +110 -0
- package/bootstrap/services/portal/src/features/crudSubscription/CrudSubscriptionSingle.jsx +261 -0
- package/bootstrap/services/portal/src/features/crudUser/CrudUserList.jsx +107 -0
- package/bootstrap/services/portal/src/features/crudUser/CrudUserSingle.jsx +402 -0
- package/bootstrap/services/portal/src/features/inventoryFormRow/InventoryFormRow.jsx +30 -0
- package/bootstrap/services/portal/src/features/lineItems/LineItems.jsx +113 -0
- package/bootstrap/services/portal/src/features/loginForm/LoginForm.jsx +56 -0
- package/bootstrap/services/portal/src/features/loginForm/loginForm.less +56 -0
- package/bootstrap/services/portal/src/features/notes/Notes.jsx +18 -0
- package/bootstrap/services/portal/src/features/passwordReset/PasswordResetForm.jsx +96 -0
- package/bootstrap/services/portal/src/features/passwordReset/PasswordResetRequestForm.jsx +74 -0
- package/bootstrap/services/portal/src/features/priceFormRow/PriceFormRow.jsx +102 -0
- package/bootstrap/services/portal/src/features/priceFormRow/priceFormRow.less +24 -0
- package/bootstrap/services/portal/src/features/raffleEntriesList/RaffleEntriesList.jsx +99 -0
- package/bootstrap/services/portal/src/features/raffleProductFormRow/RaffleProductFormRow.jsx +46 -0
- package/bootstrap/services/portal/src/features/sidebar/Sidebar.jsx +64 -0
- package/bootstrap/services/portal/src/features/sidebar/sidebar.less +49 -0
- package/bootstrap/services/portal/src/features/skus/Skus.jsx +109 -0
- package/bootstrap/services/portal/src/features/subscriptionSchedule/SubscriptionSchedule.jsx +44 -0
- package/bootstrap/services/portal/src/features/taxonomyFormRow/TaxonomyFormRow.jsx +32 -0
- package/bootstrap/services/portal/src/features/user/User.jsx +54 -0
- package/bootstrap/services/portal/src/features/user/user.less +57 -0
- package/bootstrap/services/portal/src/includes/utilities.js +259 -0
- package/bootstrap/services/portal/src/index.js +14 -0
- package/bootstrap/services/portal/src/layouts/CrudLayout.jsx +50 -0
- package/bootstrap/services/portal/src/layouts/LoginLayout.jsx +17 -0
- package/bootstrap/services/portal/src/layouts/PortalLayout.jsx +48 -0
- package/bootstrap/services/portal/src/layouts/loginLayout.less +33 -0
- package/bootstrap/services/portal/src/layouts/portalLayout.less +67 -0
- package/bootstrap/services/portal/src/pages/contacts/Contacts.jsx +199 -0
- package/bootstrap/services/portal/src/pages/dashboard/Dashboard.jsx +17 -0
- package/bootstrap/services/portal/src/pages/integrations/Integrations.jsx +10 -0
- package/bootstrap/services/portal/src/pages/login/Login.jsx +15 -0
- package/bootstrap/services/portal/src/pages/login/login.less +10 -0
- package/bootstrap/services/portal/src/pages/orders/Orders.jsx +199 -0
- package/bootstrap/services/portal/src/pages/passwordReset/PasswordResetPage.jsx +15 -0
- package/bootstrap/services/portal/src/pages/passwordResetRequest/PasswordResetRequestPage.jsx +15 -0
- package/bootstrap/services/portal/src/pages/payments/Payments.jsx +10 -0
- package/bootstrap/services/portal/src/pages/portal/Portal.jsx +43 -0
- package/bootstrap/services/portal/src/pages/products/Products.jsx +212 -0
- package/bootstrap/services/portal/src/pages/raffleEntries/RaffleEntries.jsx +124 -0
- package/bootstrap/services/portal/src/pages/raffles/Raffles.jsx +186 -0
- package/bootstrap/services/portal/src/pages/reports/Reports.jsx +10 -0
- package/bootstrap/services/portal/src/pages/settings/Settings.jsx +10 -0
- package/bootstrap/services/portal/src/pages/subscriptions/Subscriptions.jsx +199 -0
- package/bootstrap/services/portal/src/pages/users/Users.jsx +193 -0
- package/bootstrap/services/portal/src/pages/users/users.less +25 -0
- package/bootstrap/services/portal/src/slices/authSlice.js +71 -0
- package/bootstrap/services/portal/src/store/configureStore.js +12 -0
- package/bootstrap/services/portal/src/styles/global.less +159 -0
- package/bootstrap/services/portal/src/styles/inputs.less +157 -0
- package/bootstrap/services/portal/src/styles/main.less +26 -0
- package/bootstrap/services/portal/src/ui/collapsible/Collapsible.jsx +97 -0
- package/bootstrap/services/portal/src/ui/collapsible/collapsible.less +23 -0
- package/bootstrap/services/portal/src/ui/customCheckbox/CustomCheckbox.jsx +17 -0
- package/bootstrap/services/portal/src/ui/customCheckbox/customCheckbox.less +42 -0
- package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelect.jsx +63 -0
- package/bootstrap/services/portal/src/ui/customMultiSelect/CustomMultiSelectPeriod.jsx +63 -0
- package/bootstrap/services/portal/src/ui/customSelect/CustomSelect.jsx +63 -0
- package/bootstrap/services/portal/src/ui/customSelect/customSelect.less +92 -0
- package/bootstrap/services/portal/src/ui/goBack/GoBack.jsx +19 -0
- package/bootstrap/services/portal/src/ui/loader/Loader.jsx +12 -0
- package/bootstrap/services/portal/src/ui/pagination/Pagination.jsx +23 -0
- package/bootstrap/services/portal/src/ui/repeater/Repeater.jsx +29 -0
- package/bootstrap/services/portal/src/ui/saveButton/SaveButton.jsx +69 -0
- package/bootstrap/services/portal/src/ui/saveButton/saveButton.less +0 -0
- package/bootstrap/services/rabbit-mq/Dockerfile.prod +9 -0
- package/bootstrap/services/user/Dockerfile +23 -0
- package/bootstrap/services/user/Dockerfile.prod +37 -0
- package/bootstrap/services/user/README.md +8 -0
- package/bootstrap/services/user/package.json +16 -0
- package/bootstrap/services/user/src/app.js +45 -0
- package/bootstrap/services/user/src/commands/session.handler.js +23 -0
- package/bootstrap/services/user/src/commands/user.handler.js +286 -0
- package/bootstrap/services/user/src/config.js +73 -0
- package/bootstrap/services/user/src/controllers/http.controller.js +156 -0
- package/bootstrap/services/user/src/controllers/message.controller.js +51 -0
- package/bootstrap/services/user/src/db/migrations/01-init.js +50 -0
- package/bootstrap/services/user/src/db/migrations/02-user-service-init.js +63 -0
- package/bootstrap/services/user/src/db/migrations/03-unauth-sessions.js +43 -0
- package/bootstrap/services/user/src/db/seeders/development/01-root-user.js +29 -0
- package/bootstrap/services/user/src/db/seeders/development/02-portal-admin-user.js +27 -0
- package/bootstrap/services/user/src/db/seeders/production/01-root-user.js +29 -0
- package/bootstrap/services/user/src/policies/user.policy.js +81 -0
- package/bootstrap/services/user/src/schema/user.schema.js +69 -0
- package/bootstrap/services/user/src/services/authentication.service.js +127 -0
- package/bootstrap/services/user/src/services/session.service.js +58 -0
- package/bootstrap/services/user/src/services/user.service.js +130 -0
- package/bootstrap/services/user/src/tests/user.test.js +126 -0
- package/package.json +3 -7
- package/src/agent/agent.client.js +28 -0
- package/src/agent/commands.js +48 -0
- package/src/cli.js +30 -0
- package/src/config.js +8 -0
- package/src/control/commands.js +156 -0
- package/src/control/control.client.js +127 -0
- package/src/dev/commands.js +71 -0
- package/src/dev/dev.service.js +320 -0
- package/src/engine/infra.js +142 -0
- package/src/helpers/helpers.js +63 -0
- package/src/profiles/command.js +170 -0
- package/src/profiles/profiles.client.js +101 -0
- package/src/scaffolder/commands.js +123 -0
- package/src/scaffolder/scaffolder.handler.js +252 -0
- package/src/services/client.js +174 -0
- package/templates/service/Dockerfile.hbs +20 -0
- package/templates/service/app.js.hbs +38 -0
- package/templates/service/commands/{{serviceName}}.handler.js.hbs +97 -0
- package/templates/service/config.js.hbs +48 -0
- package/templates/service/controllers/http.controller.js.hbs +87 -0
- package/templates/service/controllers/message.controller.js.hbs +51 -0
- package/templates/service/db/migrations/01-init.js.hbs +50 -0
- package/templates/service/db/migrations/02-{{lowerCase serviceName}}-service-init.js.hbs +23 -0
- package/templates/service/package.json.hbs +18 -0
- package/templates/service/policies/{{serviceName}}.policy.js.hbs +49 -0
- package/templates/service/schema/{{serviceName}}.schema.js.hbs +14 -0
- package/templates/service/services/{{serviceName}}.service.js.hbs +32 -0
- package/dist/cli.js +0 -18
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<svg width="344" height="61" viewBox="0 0 344 61" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
2
|
+
<rect width="344" height="61" fill="url(#pattern0_238_39)"/>
|
|
3
|
+
<defs>
|
|
4
|
+
<pattern id="pattern0_238_39" patternContentUnits="objectBoundingBox" width="1" height="1">
|
|
5
|
+
<use xlink:href="#image0_238_39" transform="matrix(0.001 0 0 0.00563934 0 -0.0103607)"/>
|
|
6
|
+
</pattern>
|
|
7
|
+
<image id="image0_238_39" width="1000" height="181" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAC1CAYAAADMW9VQAAAABHNCSVQICAgIfAhkiAAAIABJREFUeF7tnQn8ddX0/wslmlMpRY/mpEkalQZS0kCSIVFIIcQflX6ojEmUmUiTMSkRDRo10KyZVE+T5jSiNPzfn6d7c5793ffec+89wz7nftbrtV7f791nn7XX+uy9z9lr77X3mWUWkxEwAkbACBgBI2AEjIARMAJGIILAk08+uSZ8Kvxf+FH49/AqkaxOMgJGwAgYASNgBIyAETACRsAIGAEjYATKQABHfD34P3BID5GwehllWqYRMAJGwAgYASNgBIyAETACRsAIGAEjECCAE35p6Jlnfp9twIyAETACRsAIGAEjYASMgBEwAkbACBiBkhHAEV+0j3OuS0/A85SshsUbgYlD4BkTZ7ENNgJGwAgYASNgBIyAETACRmAQArMPyDAr1wflGSDCl42AETACRsAIGAEjYASMgBEwAkbACBiBvgiwOj4rfHOfVfRr+grwRSNgBIyAETACRsAIGAEjYASMgBEwAkagGARwzt/ew0FXePvriynFUoyAETACRsAIGAEjYASMgBEwAkbACBiBgQjgiL8LvivjqN/G/28ZeKMzGAEjMBIC2jtiMgJGwAgYASNgBIyAETACRsAIRBHAIZ+NCyvBT8BXzDrrrI9FMzrRCBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYASMgBEwAkbACBgBI2AEjIARMAJGwAgYASNgBIyAETACRsAIGAEjYARKQ2DW0iTXJPjJJ5+cnaLn7BR/36yzzvpkTaq42JYiQBubC9Nm65j3EG3svy01tfFmUVdzY8SzZAj19M/GG2QDhkaANjB/56YHaQOP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"/>
|
|
8
|
+
</defs>
|
|
9
|
+
</svg>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# deploy.localdev.yml
|
|
2
|
+
|
|
3
|
+
# - This file is used to orchestrate locally running containers for development
|
|
4
|
+
# - environment: localdev is a named convention required for local development
|
|
5
|
+
|
|
6
|
+
config:
|
|
7
|
+
core-version: 1.0
|
|
8
|
+
architecture: microservice
|
|
9
|
+
region: eu-west-2
|
|
10
|
+
environment: localdev
|
|
11
|
+
namespace: my-project
|
|
12
|
+
|
|
13
|
+
services:
|
|
14
|
+
- name: control
|
|
15
|
+
listener_rules:
|
|
16
|
+
paths:
|
|
17
|
+
- /control
|
|
18
|
+
- /tasks
|
|
19
|
+
min-tasks: 1
|
|
20
|
+
max-tasks: 1
|
|
21
|
+
depends_on:
|
|
22
|
+
- control-db
|
|
23
|
+
command: ["npm", "run", "start:dev"]
|
|
24
|
+
ports:
|
|
25
|
+
- "4001:3000"
|
|
26
|
+
|
|
27
|
+
- name: user
|
|
28
|
+
listener_rules:
|
|
29
|
+
paths:
|
|
30
|
+
- /authenticate
|
|
31
|
+
- /users
|
|
32
|
+
min-tasks: 1
|
|
33
|
+
max-tasks: 1
|
|
34
|
+
depends_on:
|
|
35
|
+
- control-db
|
|
36
|
+
command: ["npm", "run", "start:dev"]
|
|
37
|
+
ports:
|
|
38
|
+
- "4002:3000"
|
|
39
|
+
|
|
40
|
+
- name: agent
|
|
41
|
+
listener_rules:
|
|
42
|
+
paths:
|
|
43
|
+
- /agent
|
|
44
|
+
min-tasks: 1
|
|
45
|
+
max-tasks: 1
|
|
46
|
+
depends_on:
|
|
47
|
+
- agent-db
|
|
48
|
+
command: ["npm", "run", "start:dev"]
|
|
49
|
+
ports:
|
|
50
|
+
- "4003:3000"
|
|
51
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
global:
|
|
2
|
+
RABBITMQ_URL: amqp://gnar_engine_rabbit_user:gn4rlyRaB81Tw4sh@rabbitmq:5672
|
|
3
|
+
RABBITMQ_USER: gnar_engine_rabbit_user
|
|
4
|
+
RABBITMQ_PASS: gn4rlyRaB81Tw4sh
|
|
5
|
+
services:
|
|
6
|
+
control:
|
|
7
|
+
MYSQL_HOST: control-db
|
|
8
|
+
MYSQL_DATABASE: ge_control_db
|
|
9
|
+
MYSQL_USER: ge_control_db_user
|
|
10
|
+
MYSQL_PASSWORD: zWF85kfGJNRA9ayp
|
|
11
|
+
MYSQL_RANDOM_ROOT_PASSWORD: wH0Pzkht75NvMd3b
|
|
12
|
+
user:
|
|
13
|
+
MYSQL_HOST: user-db
|
|
14
|
+
MYSQL_DATABASE: ge_user_db
|
|
15
|
+
MYSQL_USER: ge_user_db_user
|
|
16
|
+
MYSQL_PASSWORD: WTEYWqs6wDBX459p
|
|
17
|
+
MYSQL_RANDOM_ROOT_PASSWORD: GXEy5T7Cp2zuOTah
|
|
18
|
+
ROOT_ADMIN_EMAIL: adam@gnar.co.uk
|
|
19
|
+
ROOT_ADMIN_USERNAME: engineadmin
|
|
20
|
+
ROOT_ADMIN_PASSWORD: n0eYk6aoiYAeSur1
|
|
21
|
+
ROOT_ADMIN_API_KEY: qydfeMcyutzIXBvHjrB2qGL9hTdco81X
|
|
22
|
+
agent:
|
|
23
|
+
MYSQL_HOST: agent-db
|
|
24
|
+
MYSQL_DATABASE: ge_agent_db
|
|
25
|
+
MYSQL_USER: ge_agent_db_user
|
|
26
|
+
MYSQL_PASSWORD: 4BARYvygGSv6BRPH
|
|
27
|
+
MYSQL_RANDOM_ROOT_PASSWORD: s27o951anIt8Lqmy
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Dockerfile for Agent Service
|
|
2
|
+
FROM node:20-alpine
|
|
3
|
+
|
|
4
|
+
# Set the working directory
|
|
5
|
+
WORKDIR /usr/gnar_engine/app
|
|
6
|
+
|
|
7
|
+
# Define a global env var
|
|
8
|
+
ENV GLOBAL_SERVICE_BASE_DIR=/usr/gnar_engine/app/src/
|
|
9
|
+
|
|
10
|
+
# Copy package.json and package-lock.json
|
|
11
|
+
COPY ./services/agent/package*.json ./
|
|
12
|
+
|
|
13
|
+
# Install nodemon
|
|
14
|
+
RUN npm install -g nodemon
|
|
15
|
+
|
|
16
|
+
# Install app dependencies
|
|
17
|
+
RUN npm install
|
|
18
|
+
|
|
19
|
+
# Expose the port the service will run on
|
|
20
|
+
EXPOSE 3000
|
|
21
|
+
|
|
22
|
+
# Start the application
|
|
23
|
+
CMD ["nodemon", "--watch", "./gnar_engine", "./gnar_engine/app.js"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Gnar MCP Notes
|
|
2
|
+
|
|
3
|
+
### Aims
|
|
4
|
+
|
|
5
|
+
- We don't want to provide all command implementations (with payload information) until we know what commands are required.
|
|
6
|
+
|
|
7
|
+
Step 1: Gather Facts
|
|
8
|
+
|
|
9
|
+
- All first prompts (no chatId provided) are 'gather facts'.
|
|
10
|
+
- This prompt will be augmented with the all service/model schemas and a list of all available commands e.g. userService.create, userService.update.
|
|
11
|
+
- From the client input the model should generate an action plan with an ordered list of the commands required, and also request the exact data required from the user to carry out the plan (based on the schemas provided in the augmented prompt).
|
|
12
|
+
|
|
13
|
+
Step 2: Confirm plan
|
|
14
|
+
|
|
15
|
+
- All further prompts (chatId provided) that do not have a 'confirmed plan' are 'confirm plan'.
|
|
16
|
+
- This prompt will be augmented with the all service/model schemas, a list of all available commands, a manifest containing the command implementations (including payload information) for each command in the most recently proposed action plan, the most recently proposed action plan itself, and a list of all previous user inputs and response texts.
|
|
17
|
+
- The model should determine from the resources provided if the action plan is accurate and if we have enough information, request conmfirmation from the user to action the request. If not we should request further information from the user until all information is provided. Should reassess the proposed plan based on user input and the command implementations provided in the prompt augmentation. If the plan is suitable, we have all the required information, and the user has confirmed that we can action the request, the model should include - actionPlanGoAhead = true in the response, and also the first command execution payload in the actionPlan.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// should we postback before actioning?
|
|
21
|
+
Step 3: Action plan loop
|
|
22
|
+
- Before returning back to the client - if the agent response has 'actionPlanGoAhead' = true, we should initalise the action plan execution loop
|
|
23
|
+
- Action Plan Execution Loop (foreach action plan command):
|
|
24
|
+
- The command will be triggered with the included payload.
|
|
25
|
+
- The result of the first command will be passed back to the agent with the system prompt, action plan, all messages, schemas, relevant command implementations.
|
|
26
|
+
- This prompt should confirm the payload for the next command in the action Plan.
|
|
27
|
+
|
|
28
|
+
- Upon the last command being executed, the model will be prompted to provide a text output to confirm the result of the action plan.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-service",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "LLM Agent microservice for Gnar Engine",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node ./src/app.js",
|
|
8
|
+
"start:dev": "nodemon --watch ./src ./src/app.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@gnar-engine/core": "^1.0.1",
|
|
12
|
+
"openai": "5.13.1"
|
|
13
|
+
},
|
|
14
|
+
"author": "Gnar Software",
|
|
15
|
+
"license": "MIT"
|
|
16
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { message, http, logger, db, registerService } from '@gnar-engine/core';
|
|
2
|
+
import { config } from './config.js';
|
|
3
|
+
import { messageHandlers } from './controllers/message.controller.js';
|
|
4
|
+
import { httpController as AgentPlatformHttpController } from './controllers/http.controller.js';
|
|
5
|
+
import { manifestService } from './services/manifest.service.js';
|
|
6
|
+
import { Agent } from './services/agent.service.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initialise service
|
|
10
|
+
*/
|
|
11
|
+
export const initService = async () => {
|
|
12
|
+
|
|
13
|
+
// Run migrations
|
|
14
|
+
db.migrations.runMigrations({config});
|
|
15
|
+
db.seeders.runSeeders({config});
|
|
16
|
+
|
|
17
|
+
// Import command handlers after the command bus is initialised
|
|
18
|
+
await import('./commands/agent.handler.js');
|
|
19
|
+
// Add more handlers as needed
|
|
20
|
+
|
|
21
|
+
// Initialise and register message handlers
|
|
22
|
+
await message.init({
|
|
23
|
+
config: config.message,
|
|
24
|
+
handlers: messageHandlers
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Register http routes
|
|
28
|
+
await http.registerRoutes({
|
|
29
|
+
controllers: [
|
|
30
|
+
AgentPlatformHttpController,
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Initialise agent client
|
|
35
|
+
await Agent.init();
|
|
36
|
+
|
|
37
|
+
// Start the HTTP server
|
|
38
|
+
await http.start();
|
|
39
|
+
|
|
40
|
+
// Register service with control service
|
|
41
|
+
await registerService();
|
|
42
|
+
|
|
43
|
+
// Start manifest generation poll
|
|
44
|
+
//setInterval(() => {
|
|
45
|
+
manifestService.generateServiceManifests();
|
|
46
|
+
//}, 3600);
|
|
47
|
+
|
|
48
|
+
logger.info('G n a r E n g i n e | Agent Service initialised successfully.');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
initService();
|
|
52
|
+
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { commands, logger } from '@gnar-engine/core';
|
|
2
|
+
import { Agent } from '../services/agent.service.js';
|
|
3
|
+
import { config } from '../config.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Prompt the LLM agent
|
|
8
|
+
*/
|
|
9
|
+
commands.register('agentService.prompt', async ({input, chatId, authUser}) => {
|
|
10
|
+
try {
|
|
11
|
+
logger.info('recieved input' + JSON.stringify(input));
|
|
12
|
+
let chatContextToStore = {};
|
|
13
|
+
|
|
14
|
+
const [manifests, resolvedChatId, chat] = await Promise.all([
|
|
15
|
+
// Get the manifests
|
|
16
|
+
commands.execute('controlService.getManifests'),
|
|
17
|
+
|
|
18
|
+
// Create a new chat if chatId is not provided
|
|
19
|
+
(async () => {
|
|
20
|
+
if (!chatId) {
|
|
21
|
+
return await Agent.createChat({
|
|
22
|
+
userId: '',
|
|
23
|
+
title: input.substring(0, 50),
|
|
24
|
+
sessionKey: input.sessionKey
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return chatId
|
|
29
|
+
})(),
|
|
30
|
+
|
|
31
|
+
// Retrieve existing chat if chatId is provided
|
|
32
|
+
(async () => {
|
|
33
|
+
if (chatId) {
|
|
34
|
+
return await Agent.getChat({chatId});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return null;
|
|
38
|
+
})()
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
let preparedInput;
|
|
42
|
+
|
|
43
|
+
// Gather facts
|
|
44
|
+
if (!chatId) {
|
|
45
|
+
preparedInput = await Agent.prepareGatherFactsPrompt({inputText: input, manifests: manifests});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Prepare Plan
|
|
49
|
+
else if (chat) {
|
|
50
|
+
await logger.info('GOT HERE WITH CHAT: ' + JSON.stringify(chat));
|
|
51
|
+
preparedInput = await Agent.preparePlanPrompt({inputText: input, manifests: manifests, chat: chat});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Infer
|
|
55
|
+
let agentResponse = await Agent.infer({preparedInput});
|
|
56
|
+
logger.info('Agent response: ' + agentResponse);
|
|
57
|
+
agentResponse = JSON.parse(agentResponse);
|
|
58
|
+
|
|
59
|
+
// Collect context from response
|
|
60
|
+
chatContextToStore.actionPlan = agentResponse.actionPlan || null;
|
|
61
|
+
chatContextToStore.input = input;
|
|
62
|
+
chatContextToStore.responseText = agentResponse.responseText || null;
|
|
63
|
+
|
|
64
|
+
// Collect required command implementations from manifests to store for next time
|
|
65
|
+
if (agentResponse.commandsRequired) {
|
|
66
|
+
chatContextToStore.commandsManifest = [];
|
|
67
|
+
|
|
68
|
+
agentResponse.commandsRequired.forEach((commandRequired) => {
|
|
69
|
+
manifests.manifests.forEach((manifest) => {
|
|
70
|
+
//logger.info('got here ' + commandRequired + ' ' + JSON.stringify(manifest.manifest) );
|
|
71
|
+
if (manifest.manifest?.commandImplementations?.[commandRequired]) {
|
|
72
|
+
chatContextToStore.commandsManifest.push(manifest.manifest.commandImplementations[commandRequired]);
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
logger.info('Chat context to store: ' + JSON.stringify(chatContextToStore));
|
|
79
|
+
|
|
80
|
+
// Store chat messages
|
|
81
|
+
chatId = resolvedChatId;
|
|
82
|
+
Agent.createChatMessage({
|
|
83
|
+
chatId: chatId,
|
|
84
|
+
userName: authUser.username,
|
|
85
|
+
context: chatContextToStore
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Plan execution loop
|
|
89
|
+
if (agentResponse.actionPlan) {
|
|
90
|
+
logger.info('Executing plan: ' + agentResponse.actionPlan);
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let response = {
|
|
95
|
+
structuredResponse: agentResponse,
|
|
96
|
+
chatId: chatId
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return response;
|
|
100
|
+
} catch (err) {
|
|
101
|
+
logger.error("Error handling LLM agent prompt: " + err);
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gnar Engine Service Config
|
|
3
|
+
*/
|
|
4
|
+
export const config = {
|
|
5
|
+
// service name
|
|
6
|
+
serviceName: 'agentService',
|
|
7
|
+
|
|
8
|
+
// microservice | modular-monolith
|
|
9
|
+
architecture: process.env.GLOBAL_ARCHITECTURE || 'microservice',
|
|
10
|
+
|
|
11
|
+
// web server
|
|
12
|
+
http: {
|
|
13
|
+
allowedOrigins: [],
|
|
14
|
+
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
15
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
16
|
+
rateLimiting: {
|
|
17
|
+
max: 3,
|
|
18
|
+
timeWindow: '1 second',
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
// database
|
|
23
|
+
db: {
|
|
24
|
+
// type: mongodb | mysql
|
|
25
|
+
type: 'mysql',
|
|
26
|
+
|
|
27
|
+
// MongoDB
|
|
28
|
+
connectionUrl: process.env.AGENT_MONGO_URL,
|
|
29
|
+
connectionArgs: {},
|
|
30
|
+
|
|
31
|
+
// MySQL
|
|
32
|
+
host: process.env.AGENT_MYSQL_HOST,
|
|
33
|
+
user: process.env.AGENT_MYSQL_USER,
|
|
34
|
+
password: process.env.AGENT_MYSQL_PASSWORD,
|
|
35
|
+
database: process.env.AGENT_MYSQL_DATABASE,
|
|
36
|
+
connectionLimit: 10,
|
|
37
|
+
queueLimit: 20,
|
|
38
|
+
maxRetries: 5
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// message broker
|
|
42
|
+
message: {
|
|
43
|
+
url: process.env.RABBITMQ_URL,
|
|
44
|
+
queueName: 'agentServiceQueue',
|
|
45
|
+
prefetch: 20
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
hashNameSpace: '',
|
|
49
|
+
|
|
50
|
+
// Default agent type
|
|
51
|
+
agent: 'chatgpt'
|
|
52
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { commands, logger } from '@gnar-engine/core';
|
|
2
|
+
import { authorise } from '../policies/agent.policy.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* HTTP controller
|
|
6
|
+
*/
|
|
7
|
+
export const httpController = {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Prompt the agent
|
|
11
|
+
*/
|
|
12
|
+
agentPrompt: {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
url: '/agent/prompt',
|
|
15
|
+
preHandler: async (request, reply) => authorise.agentPrompt(request, reply),
|
|
16
|
+
handler: async (request, reply) => {
|
|
17
|
+
logger.info('Received agent prompt request' + JSON.stringify(request.body));
|
|
18
|
+
const params = {
|
|
19
|
+
input: request.body.textInput,
|
|
20
|
+
chatId: request.body.chatId || '',
|
|
21
|
+
authUser: request.user
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Sanitize input (remove all JSON delimiters)
|
|
25
|
+
params.input = params.input.replace(/[\{\}\[\]\"\'\:\,]/g, '');
|
|
26
|
+
|
|
27
|
+
// execute
|
|
28
|
+
let response;
|
|
29
|
+
logger.info('params' + JSON.stringify(params));
|
|
30
|
+
try {
|
|
31
|
+
response = await commands.execute('prompt', params);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
logger.error(error.message);
|
|
34
|
+
return reply.code(500).send({ error: error.message});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
logger.info('response is: ' + JSON.stringify(response));
|
|
38
|
+
|
|
39
|
+
// handle response
|
|
40
|
+
reply.code(200).send(response);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { commands } from '@gnar-engine/core';
|
|
2
|
+
|
|
3
|
+
export const messageHandlers = {
|
|
4
|
+
|
|
5
|
+
getAgent: async (payload) => {
|
|
6
|
+
let result;
|
|
7
|
+
if (payload.data?.id) {
|
|
8
|
+
result = await commands.execute('getSingleAgent', {
|
|
9
|
+
id: payload.data.id
|
|
10
|
+
});
|
|
11
|
+
} else if (payload.data?.email) {
|
|
12
|
+
result = await commands.execute('getSingleAgent', {
|
|
13
|
+
email: payload.data.email
|
|
14
|
+
});
|
|
15
|
+
} else {
|
|
16
|
+
throw new Error('No Agent ID or email provided');
|
|
17
|
+
}
|
|
18
|
+
if (!result) {
|
|
19
|
+
throw new Error('Agent not found');
|
|
20
|
+
}
|
|
21
|
+
return { Agent: result };
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
getManyAgents: async (payload) => {
|
|
25
|
+
const results = await commands.execute('getManyAgents', {});
|
|
26
|
+
return { agents: results };
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
createAgent: async (payload) => {
|
|
30
|
+
const results = await commands.execute('createAgents', {
|
|
31
|
+
agents: [payload.data.Agent]
|
|
32
|
+
});
|
|
33
|
+
return { agents: results };
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
updateAgent: async (payload) => {
|
|
37
|
+
const result = await commands.execute('updateAgent', {
|
|
38
|
+
id: payload.data.id,
|
|
39
|
+
newAgentData: payload.data
|
|
40
|
+
});
|
|
41
|
+
return { Agent: result };
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
deleteAgent: async (payload) => {
|
|
45
|
+
await commands.execute('deleteAgent', {
|
|
46
|
+
id: payload.data.id
|
|
47
|
+
});
|
|
48
|
+
return { message: 'Agent deleted' };
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { logger, db } from '@gnar-engine/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Up
|
|
5
|
+
*/
|
|
6
|
+
export const up = async () => {
|
|
7
|
+
await initDatabaseTables();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Down
|
|
12
|
+
*/
|
|
13
|
+
export const down = async () => {
|
|
14
|
+
await dropDatabaseTables();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Create all tables
|
|
19
|
+
*/
|
|
20
|
+
export const initDatabaseTables = async () => {
|
|
21
|
+
|
|
22
|
+
// Migrations table
|
|
23
|
+
logger.info("Creating migrations table");
|
|
24
|
+
const createMigrationsTableQuery = `
|
|
25
|
+
CREATE TABLE migrations (
|
|
26
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
27
|
+
name VARCHAR(255) NOT NULL UNIQUE,
|
|
28
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
29
|
+
)`;
|
|
30
|
+
await db.query(createMigrationsTableQuery);
|
|
31
|
+
|
|
32
|
+
// Seeders table
|
|
33
|
+
logger.info("Creating seeders table");
|
|
34
|
+
const createSeedersTableQuery = `
|
|
35
|
+
CREATE TABLE seeders (
|
|
36
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
37
|
+
name VARCHAR(255) NOT NULL UNIQUE,
|
|
38
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
39
|
+
)`;
|
|
40
|
+
await db.query(createSeedersTableQuery);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Drop all tables
|
|
45
|
+
*/
|
|
46
|
+
export const dropDatabaseTables = async () => {
|
|
47
|
+
logger.info('Dropping tables');
|
|
48
|
+
await db.query('DROP TABLE IF EXISTS migrations');
|
|
49
|
+
await db.query('DROP TABLE IF EXISTS seeders');
|
|
50
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { logger, db } from '@gnar-engine/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Up
|
|
5
|
+
*/
|
|
6
|
+
export const up = async () => {
|
|
7
|
+
logger.info('Creating table: agent-chats');
|
|
8
|
+
await db.query(`
|
|
9
|
+
CREATE TABLE agent_chats (
|
|
10
|
+
id CHAR(36) PRIMARY KEY,
|
|
11
|
+
user_id CHAR(36) NOT NULL,
|
|
12
|
+
title VARCHAR(255) NOT NULL,
|
|
13
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
14
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
15
|
+
)
|
|
16
|
+
`);
|
|
17
|
+
|
|
18
|
+
logger.info('Creating table: agent-chat-messages');
|
|
19
|
+
await db.query(`
|
|
20
|
+
CREATE TABLE agent_chat_messages (
|
|
21
|
+
id CHAR(36) PRIMARY KEY,
|
|
22
|
+
chat_id CHAR(36) NOT NULL,
|
|
23
|
+
user_name VARCHAR(255) NOT NULL,
|
|
24
|
+
context MEDIUMTEXT NOT NULL,
|
|
25
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
26
|
+
)
|
|
27
|
+
`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Down
|
|
32
|
+
*/
|
|
33
|
+
export const down = async () => {
|
|
34
|
+
logger.info('Dropping table: agents');
|
|
35
|
+
await db.query('DROP TABLE IF EXISTS agents');
|
|
36
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { config } from '../config.js';
|
|
2
|
+
|
|
3
|
+
export const authorise = {
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Authorise agent prompt
|
|
7
|
+
*/
|
|
8
|
+
agentPrompt: async (request, reply) => {
|
|
9
|
+
if (!request.user || request.user.role !== 'service_admin') {
|
|
10
|
+
reply.code(403).send({error: 'not authorised'});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { schema } from '@gnar-engine/core';
|
|
2
|
+
import { config } from '../config.js';
|
|
3
|
+
|
|
4
|
+
export const AgentSchema = {
|
|
5
|
+
schemaName: 'agentService.AgentSchema',
|
|
6
|
+
schema: {
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {
|
|
9
|
+
// Add your properties here
|
|
10
|
+
|
|
11
|
+
},
|
|
12
|
+
required: [],
|
|
13
|
+
additionalProperties: false
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const validateAgent = schema.compile(AgentSchema);
|