Closed Keyrxng closed 1 month ago
I've extracted the /ask command into a https://github.com/ubq-testing/bot-ai/issues/25 with repo here
This is great to see! I was thinking maybe /research
but we can make adjustments later.
My vision for the slash commands is that we will have some type of special circumstance (perhaps accommodated from within the bot kernel) that will first regex parse on any issues_comment.created
event. It will recognize the command being invoked, and then it will look up from the ubiquibot-config.yml
which plugin to relay the webhook to.
With this approach, partners can easily define any arbitrary commands and then configure what plugin to invoke from that command. We can recommend a "default configuration" to onboard new partners with our favorite plugins.
Originally I was thinking of hosting separate repositories under the @ubiquibot organization as "official plugins" and ping those directly (via GitHub Actions) to host and serve the plugins.
We also need to figure a means for monetization and make it as simple as possible for plugin developers. Ideally if the bot kernel (@ubiquity) can get a cut and then also give a cut to any plugins that charge money.
This should keep plugin development as simple as possible, if they are separate repositories.
I just saw your example in your readme and just to make it very clear, the kernel should have the ability to read from the ubiquibot-config.yml
and then pass along the webhook/event to the separate plugin repository. We should not have to do any custom mounting from within the kernel, for example.
@whilefoo rfc
Okay understood so an example config might look like
plugins:
donate
createComment
logger:
backendUrl: https...
The kernel reads these plugins using the plugin reader module, each plugin needs a plugin-config.yml
stating it's requirements such as regex or additional reqs, the reader extracts the regex from the plugin's config gives the green light and then calls the plugin function, once complete the reader sends the results to pipeOutputTo
? Would be better if the kernel had access to the regex's without looking into the belonging repo but I can't think of how unless the partner reads from the plugin-installation.md
where it states what to add into the ubq-config.yml
as part of the plugin like
donate:
regex: /donate
As for the piping schema, maybe something like this?
const plugin = T.Object({
command: T.String(), // eg research
args: T.Optional(T.Array(T.Any())), // eg always the event & other args
pipeOutputTo: T.Optional(T.String()), // eg createComment, other or null returns data to the invoking function
onError: T.Optional(T.String()), // eg log, comment or null
requirements: [] // anything user provided needed to make it work, URLs, addrs, whatever
});
type Plugin = StaticDecode<typeof plugin>
So as a dev I could build something like
/*
plugin-config.yml:
commentRegex: null // never parses comments, is only piped to
ubq-config.yml:
plugins:
createComment // doesn't require anything to work, just plug and play
*/
type CreateComment extends Plugin {
command: "createComment",
args: string,
pipeOutputTo: null, // returns the output to the invoker
onError: "logger",
requirements: []
}
/*
plugin-config.yml
commentRegex: null // never parses comments, is only piped to
ubq-config.yml
plugins:
logger:
backendUrl: https... // my favourite logging provider/db/analytics/whatever
*/
type Logger extends Plugin {
command: "logger",
args: {...args},
pipeOutputTo: null, // returns data to invoker
onError: "createComment",
requirements: [backendUrl]
}
/*
plugin-config.yml:
commentRegex: "/donate" // only works via comment parsing
ubq-config.yml:
plugins:
donate // doesn't require anything to work, just plug and play
*/
type Donate extends Plugin {
command: "donate",
args: {username: string, amount: string, token: string},
pipeOutputTo: "createComment", // passes all data to createComment and none to invoker
onError: "logger",
requirements: []
}
So Donate
would be an invoked slash command while logger and createComment is only piped-to
. Donate might be invoked by partners to bump a hunter's payout without adjusting price labels, as such it would invoke the permit generation module.
ubq-config.yml
, gather and apply regex'sDonate
calls permitGeneration
with pipeOutputTo
as null
returning the permit string to the Donate
plugin.Donate
would then call it's pipeOutputTo
passing in the permit and any comment stylingTrying to wrap my head around the vision as I intend to catch that juicy bounty for piping schema and logic but it's relevant here too for sure
I spent some time designing a config. I took the existing org config and coerced them into a plugins oriented config:
Wildcard not sure how to handle this better. But the names of the others are based on my deep research/understanding of all of the official GitHub webhook events that are transmitted to GitHub Apps.
I also tried conforming to GitHub Actions syntax with name:
description:
with:
and uses:
I think the most interesting part is the permit generation segment:
uses:
- ubiquibot/conversation-incentives@d2ef733 # the magic is that this will only return a `{ username: string; reward: number }[]`
- ubiquibot/permit-generation@9a16ad0 # this will consume the above output and return only the permit information
- ubiquibot/conversation-incentives-comment@fb32084 # this will consume the above output and return only the conversation rewards
There will be lag time setting up and tearing down each GitHub Actions runner. If this is an issue, we can theoretically consolidate this specific flow to a Cloudflare Action etc which just bundles all three plugins as submodules and runs them in a single runtime. I prefer the separate codebases to optimize for interoperability.
A plugin developer can send any arbitrary rewards request to the permit-generation plugin and parse its output and do something custom with it for example.
The logger is built into GitHub Actions no need to configure.
Why not have a separate property for commands, because any way all commands will be inside issues_comment.created
.
Something like
events:
"*":
- name: "Wildcard"
description: "Runs after every handler."
uses:
- ubiquibot/wildcard@1.0.0
with:
reviewDelayTolerance: 30 days
taskStaleTimeoutDuration: 30 days
taskFollowUpDuration: 3.5 days
taskDisqualifyDuration: 7 days
commands:
- name: "User query"
description: "Check a user's registered DevPool profile information."
command: "^\/query @([a-zA-Z0-9]+)$"
example: "/query @username"
uses:
- ubiquibot/command-query
- name: "start"
description: "Start working on the task."
command: "^\/start$"
example: "/start"
uses:
- ubiquibot/command-start@5ab8115
with:
maxConcurrentTasks: 2
I originally started with that in my design but decided that it doesn't make sense to add custom extra logic to accomodate this. Currently we can ALMOST 1:1 map the config directly on to GitHub webhook events. The only exception is wildcard. The closest thing to running regularly is GitHub's ping
event, which runs every ~15 seconds, but it does not include the authentication details, namely, the installation_id
which was an issue in my earlier research using the kernel and monitoring incoming webhook events. Each organization that adds the bot has a unique installation_id
.
Why not have a separate property for commands, because any way all commands will be inside issues_comment.created.
It does seem redundant if the user can also configure issues_comment.created
The user can configure issues_comment
(for all) issues_comment.created
.edited
and I believe there is one more off hand, possibly .deleted
. It makes more sense to me to try and stay as close as possible with the official webhook event names. I just wish we could have a better solution for "wildcard"
A few notes on this config:
plugin-config.yml
file) from the plugin repo (or even from https://github.com/ubiquibot/conversation-rewards/blob/development/action.yml)/register
or /wallet
). Perhaps it makes sense to force a prefix for all plugin developers. So for ubiquity, for example, the commands would be similar to ubiquibot/kernel /wallet
. For
https://github.com/ubq-testing/ubiquibot-ask-plugin it would be ubq-testing/ubiquibot-ask-plugin /ask
.A few notes on this config:
- Name, description, example usage are up to plugin creators so it makes sense to fetch them dynamically (from some
plugin-config.yml
file) from the plugin repo (or even from https://github.com/ubiquibot/conversation-rewards/blob/development/action.yml)
Agreed
- We're basically going to allow 3rd parties to hook into the bot's execution so we'll have to somehow review the plugins to make sure there is nothing malicious (which takes time)
We just "approve" of the ones we fork into @ubiquibot. The rest is at the risk of projects if they want to use. We should not spend resources on reviewing every plugin.
- Plugin developers may introduce similar commands (like
/register
or/wallet
). Perhaps it makes sense to force a prefix for all plugin developers. So for ubiquity, for example, the commands would be similar toubiquibot/kernel /wallet
. For
No this should be assignable in the ubiquibot-config.yml
, as I have it expressed via the regex. We can consider built in defaults, but I envision that we would essentially generate "starter" configs (ubiquibot-config.yml
) with specific recipes and slash commands.
Advanced users can override defaults with the regex match feature I proposed.
https://github.com/ubq-testing/ubiquibot-ask-plugin it would be
ubq-testing/ubiquibot-ask-plugin /ask
.
To make it clear, this plugin config will be part of the organization wide config set by every partner, right?
Org and repo config needs to be basically the same schema. So the config I proposed should be usable in both contexts, the same way we have it working now.
# Issue was not closed as completed. Skipping.
I've extracted the
/ask
command into a plugin with repo hereI've assumed based on https://github.com/ubiquibot/permit-generation that each plugin should first start with a fork of the
ts-template
repo.So when in developing a plugin will there be a forkable repo either a monorepo of all developed plugins or a repo that PRs can be made against specifically for building plugins?
Maybe the repo should have a branch that has the template within a dir, the user forks from there then copies and renames the dir to the name of their plugin and then prs can be made against the default branch building up a monorepo?
This would make publishing each new plugin as a package from
@ubiquibot
easier if that's the intention and would create a great place for a how-to-build plugins docs and examples areaWhat's the idea with it at the moment?