@openhands/extensions 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pr/custom-automation-event-trigger.png +0 -0
- package/.pr/custom-automation-plugin-fields.png +0 -0
- package/.pr/custom-automation-prompt-review.png +0 -0
- package/.pr/custom-automation-prompt-scheduled.png +0 -0
- package/.pr/custom-automation-upload-fields.png +0 -0
- package/.release-please-manifest.json +1 -1
- package/AGENTS.md +1 -1
- package/automations/README.md +52 -36
- package/automations/catalog/custom-automation/manifest.json +229 -0
- package/automations/catalog/github-issue-to-pr/manifest.json +1 -1
- package/automations/catalog/github-pr-reviewer/manifest.json +1 -1
- package/automations/catalog/qa-changes/manifest.json +1 -1
- package/automations/catalog-index.js +19 -17
- package/automations/catalog.schema.json +81 -7
- package/automations/index.d.ts +52 -2
- package/automations/interface.json +2 -1
- package/integrations/catalog/gitlab.json +27 -5
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/python/openhands_extensions/_version.py +1 -1
- package/tests/fixtures/automations/custom-automation.json +398 -0
- package/tests/fixtures/automations/github-pr-reviewer.json +9 -9
- package/tests/test_automation_setup.py +340 -92
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/AGENTS.md
CHANGED
|
@@ -106,7 +106,7 @@ When editing or adding skills in this repo, follow these rules (and add new skil
|
|
|
106
106
|
- If you change a skill’s behavior or scope, update its `README.md` (if present) accordingly.
|
|
107
107
|
- If you change top-level documentation, ensure links still resolve.
|
|
108
108
|
- `integrations/catalog/*.json` is the single hand-authored source of truth consumed by `@openhands/extensions`; adding or editing an integration should require changing exactly one JSON file in that directory. Do not reintroduce `integrations/integration-catalog.json`, separate provider files, per-language catalog duplicates, or provider-specific runtime code. Run `npm run build:integrations` after catalog edits to regenerate `integrations/catalog-index.js`, which statically imports each individual JSON file for the JS package. The Python package includes the same individual JSON files via wheel data and reads them directly. Agent-canvas and integrations-hub import this package directly, so integration marketplace fixes belong here rather than in app-local constants. When upstream MCP projects move repos, verify both `docsUrl` and the connection option (`transport`, `command`/`args`, or URL), not just links. JS exposes `listIntegrationCatalog({ mcp, oauth })` / `getIntegrationCatalogEntry`; Python mirrors with `list_integration_catalog_models(mcp=, oauth=)` / `get_integration_catalog_entry_model`, which return validated Pydantic models (the raw-dict accessors were deprecated in 0.10.0 and removed in 0.12.0). The legacy provider-catalog compatibility layer and `managedConnectorMigration` / `legacyScopeBundles` / `canonicalServerUrl` / `errorHints` mechanisms were removed intentionally; providers declare only standard OAuth config as integration data.
|
|
109
|
-
- `automations/catalog/<id>/` follows the same rule, as a directory per automation so an automation can ship the scripts it uploads to the automations service alongside its metadata. `manifest.json` is the single hand-authored file, carrying both the card metadata and an optional nested `setup` block (the extension-owned configuration experience). Every entry is validated against `automations/catalog.schema.json`. Run `npm run build:automations` after catalog edits to regenerate `automations/catalog-index.js`. JS exposes `listAutomationCatalog()` / `getAutomationCatalogEntry(id)` alongside `AUTOMATION_CATALOG`. The governing rule is that a manifest states only what varies between automations, and states it once; anything derivable is absent and the host generates it. Derived, so never written in a manifest: the command that launches the card (read from the `triggers:` frontmatter of the skill named by `skill`, which defaults to `id` and is stated only where the two differ - editing an automation must never require editing a skill), the setup route (`/automations/new/<id>`), the trigger
|
|
109
|
+
- `automations/catalog/<id>/` follows the same rule, as a directory per automation so an automation can ship the scripts it uploads to the automations service alongside its metadata. `manifest.json` is the single hand-authored file, carrying both the card metadata and an optional nested `setup` block (the extension-owned configuration experience). Every entry is validated against `automations/catalog.schema.json`. Run `npm run build:automations` after catalog edits to regenerate `automations/catalog-index.js`. JS exposes `listAutomationCatalog()` / `getAutomationCatalogEntry(id)` alongside `AUTOMATION_CATALOG`. The governing rule is that a manifest states only what varies between automations, and states it once; anything derivable is absent and the host generates it. Derived, so never written in a manifest: the command that launches the card (read from the `triggers:` frontmatter of the skill named by `skill`, which defaults to `id` and is stated only where the two differ - editing an automation must never require editing a skill), the setup route (`/automations/new/<id>`), the trigger variants a deployment can offer (the keys of `setup.form.triggers`; multiple keys mean any supported selected variant can run), schedule limits, timezone lists, event choices, and model profiles (the `cron`, `timezone`, `event-source`, `event-type`, and `llm-profile` field types), the preflight call, the create request's `name`/`repos`/`model`/`timeout`/`trigger` (rebuilt from same-named form fields when present, the repo-picker field, and the selected key and fields under `setup.form.triggers`, where a field is named after the property it fills), the mapping from a rejected payload path back to the input at fault, the review screen, the create endpoint, the post-success navigation, and the analytics stages. `requires.integrations` is keyed by integration id and lives on the entry, not in `setup`, because a card lists its integrations whether or not it ships a setup flow; there is no key anywhere for a credential, because the credential comes with the connection. `setup.form` splits inputs into `triggers` (keyed by trigger kind - what decides when the automation runs) and `args` (everything else), both keyed by field name. `setup` declares a `prompt` (plus a `filter` for an event trigger) when `mode` is `direct`, and a `message` when it is `assisted`. Contract fixtures are test vectors, not catalog data: they live in `tests/fixtures/automations/`, are optional per automation, and are reachable only through the `@openhands/extensions/testing/automations/*.json` subpath - never from the runtime entry point.
|
|
110
110
|
- For Python test runs, prefer `uv sync --group test` followed by `uv run pytest -q`; the full suite depends on `openhands-sdk`, which is not available in the base environment.
|
|
111
111
|
- Agent-driven plugins (for example `plugins/pr-review` and `plugins/release-notes`) use `uv run --with openhands-sdk --with openhands-tools ...` and require an `LLM_API_KEY` in addition to `GITHUB_TOKEN`.
|
|
112
112
|
- For OpenHands Cloud API guidance, automations, and CLI integration, use `plugins/openhands`. It is the canonical unified OpenHands plugin covering the V1 Cloud API, Automations API, and CLI. The individual skills (`skills/openhands-api`, `skills/openhands-automation`) are also available standalone.
|
package/automations/README.md
CHANGED
|
@@ -42,16 +42,17 @@ two records of the same fact from drifting apart, and it is why the file is as s
|
|
|
42
42
|
| The setup route | `/automations/new/<id>` |
|
|
43
43
|
| The integrations the card lists | `requires.integrations`, which every entry carries |
|
|
44
44
|
| The capabilities endpoint | The host queries it for every automation |
|
|
45
|
-
| The trigger
|
|
46
|
-
| Schedule limits and
|
|
47
|
-
| Local validation rules | The `required` flag and `constraints` on each field |
|
|
45
|
+
| The trigger variants a deployment can offer | The keys of `setup.form.triggers`; an entry with multiple keys is usable when at least one variant is supported |
|
|
46
|
+
| Schedule limits, timezone list, event choices, and model profiles | The `cron`, `timezone`, `event-source`, `event-type`, and `llm-profile` field types |
|
|
47
|
+
| Local validation rules | The `required` flag and `constraints` on each field, applied to the selected trigger variant |
|
|
48
48
|
| The preflight call | `POST /v1/validate` with the entry id, the create endpoint, and the rendered payload |
|
|
49
|
-
| The created automation's name |
|
|
50
|
-
| `repos` in the create request | The repo-picker field, its declared `provider`, and a field named `ref` if there is one |
|
|
51
|
-
| `
|
|
49
|
+
| The created automation's name | A form field named `name`, or the entry's `name` plus the repository that was picked |
|
|
50
|
+
| `repos` in the create request | The repo-picker field, its declared `provider`, and a non-empty field named `ref` if there is one |
|
|
51
|
+
| `model` and `timeout` in the create request | Same-named form fields when they have values |
|
|
52
|
+
| `trigger` in the create request | The selected key under `form.triggers`, and the fields under it named after trigger properties |
|
|
52
53
|
| Which input a rejected payload path belongs to | Rebuilding that body with each field standing in for its own value |
|
|
53
54
|
| The review screen | The fields and their labels |
|
|
54
|
-
| The create endpoint | `POST /v1/preset/prompt`, or `POST /v1` for an
|
|
55
|
+
| The create endpoint | `POST /v1/preset/prompt`, `POST /v1/preset/plugin`, or `POST /v1` for an uploaded or bundled tarball |
|
|
55
56
|
| The files a bundle packs | `setup.bundle.files`, read from this repository at build time |
|
|
56
57
|
| Where a success navigates | The created automation, or the started conversation |
|
|
57
58
|
| The analytics stages | The same stages for every automation |
|
|
@@ -64,7 +65,7 @@ checks them against the recorded fixtures, so these deletions stay honest rather
|
|
|
64
65
|
```jsonc
|
|
65
66
|
{
|
|
66
67
|
"id": "github-pr-reviewer",
|
|
67
|
-
"name": "GitHub
|
|
68
|
+
"name": "GitHub code review",
|
|
68
69
|
"category": "Code review",
|
|
69
70
|
"description": "...",
|
|
70
71
|
"requires": {
|
|
@@ -97,32 +98,40 @@ three entries whose names differ from their skill state it. The command that lau
|
|
|
97
98
|
repeated here: it lives once, in the skill's own `triggers:` frontmatter, and the skills catalog exposes it.
|
|
98
99
|
That way a skill can rename its trigger without leaving a stale copy behind in this catalog.
|
|
99
100
|
|
|
100
|
-
`setup` is optional.
|
|
101
|
-
`
|
|
101
|
+
`setup` is optional. Entries that carry one never repeat `id`, `name`, `category`, or `description`.
|
|
102
|
+
`setup.version` selects how the block is interpreted; a future format ships a new constant.
|
|
102
103
|
|
|
103
104
|
### Triggers and args
|
|
104
105
|
|
|
105
106
|
`form` separates the two things a user is configuring, and both are keyed by field name:
|
|
106
107
|
|
|
107
108
|
- **`form.triggers`** decides *when* the automation runs, keyed by trigger kind (`cron` or `event`).
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
If an entry declares more than one key, the host renders those keys as selectable variants and validates
|
|
110
|
+
only the selected variant's fields before building the payload.
|
|
111
|
+
- **`form.args`** is everything else that is common to every creation path, such as the automation name,
|
|
112
|
+
model profile, or timeout.
|
|
113
|
+
- **`setup.actions`** is optional and declares user-selectable creation paths for one card. The host renders
|
|
114
|
+
the common form plus the selected action's `args`, checks that action's `features`, and creates through
|
|
115
|
+
the endpoint implied by the action key: `prompt` -> `/v1/preset/prompt`, `plugin` -> `/v1/preset/plugin`,
|
|
116
|
+
and `upload` -> `/v1/uploads` followed by `/v1`.
|
|
111
117
|
|
|
112
118
|
An assisted entry declares no triggers, because the trigger is settled during the conversation.
|
|
113
119
|
|
|
114
120
|
### What the form produces
|
|
115
121
|
|
|
116
|
-
- **`mode: "direct"`** declares
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
- **`mode: "direct"`** declares exactly one creation archetype: a `prompt`, a repository-shipped `bundle`,
|
|
123
|
+
or `actions`. A prompt creates through `/v1/preset/prompt`. A bundle is packed and uploaded by the host,
|
|
124
|
+
then creates through `/v1`. An actions block lets the user choose between prompt, plugin, and uploaded
|
|
125
|
+
tarball paths in one card. The rest of the create request restates the form, so it is not written out. A
|
|
126
|
+
form field named `name`, `model`, or `timeout` fills the matching top-level create property. An event
|
|
127
|
+
trigger may also declare a `filter`, because composing form values into a JMESPath expression is the one
|
|
128
|
+
part of an event trigger that cannot always be read off the form.
|
|
120
129
|
- **`mode: "assisted"`** declares a `message`: setup context handed to an agent conversation that finishes
|
|
121
130
|
the job. The command that opens that conversation comes from the skill, so it is not repeated here.
|
|
122
131
|
|
|
123
132
|
A direct entry may also declare a `message`. It is the seed for the fallback conversation the host offers
|
|
124
|
-
when the deployment cannot run the direct path - a deployment whose capabilities lack
|
|
125
|
-
|
|
133
|
+
when the deployment cannot run the direct path - a deployment whose capabilities lack every declared trigger
|
|
134
|
+
variant or required features. The same 2000-character cap applies, and because the fallback fires before the
|
|
126
135
|
form is trustworthy, a direct `message` should not reference `{{form.*}}`.
|
|
127
136
|
|
|
128
137
|
A `repo-picker` may declare `multiple: true`, and then it collects several
|
|
@@ -135,17 +144,17 @@ repository when there is one and after the count when there are several, since a
|
|
|
135
144
|
list of names does not fit a name.
|
|
136
145
|
|
|
137
146
|
A form field is named after the property it fills. `schedule` and `timezone` under `triggers.cron` become
|
|
138
|
-
`trigger.schedule` and `trigger.timezone`; `on` under `triggers.event`
|
|
139
|
-
`ref` becomes `repos[].ref
|
|
140
|
-
to `filter` rather than a trigger property.
|
|
147
|
+
`trigger.schedule` and `trigger.timezone`; `source` and `on` under `triggers.event` become `trigger.source`
|
|
148
|
+
and `trigger.on`; a field named `ref` becomes `repos[].ref` when it has a value. Any other field under a
|
|
149
|
+
trigger kind, such as a phrase to match, is an input to `filter` rather than a trigger property.
|
|
141
150
|
|
|
142
151
|
### Entries that ship a script
|
|
143
152
|
|
|
144
|
-
`mode: "direct"` produces
|
|
145
|
-
is the right shape when the automation *is* the judgement: the agent
|
|
146
|
-
prompt and does the work. A bundle is the right shape when most of
|
|
147
|
-
automation does is deterministic machinery - polling, dedupe, state,
|
|
148
|
-
calls - and the agent is needed only for the part that genuinely needs judgement.
|
|
153
|
+
`mode: "direct"` produces exactly one of `prompt`, `bundle`, or `actions`. A
|
|
154
|
+
prompt is the right shape when the automation *is* the judgement: the agent
|
|
155
|
+
reads the prompt and does the work. A bundle is the right shape when most of
|
|
156
|
+
what the automation does is deterministic machinery - polling, dedupe, state,
|
|
157
|
+
fixed API calls - and the agent is needed only for the part that genuinely needs judgement.
|
|
149
158
|
`github-pr-reviewer` is the first: its script owns discovery, label-event
|
|
150
159
|
dedupe, per-repo state and the review checkout, and starts a conversation only
|
|
151
160
|
once a pull request actually needs reviewing.
|
|
@@ -188,7 +197,10 @@ Two things follow from the archetype rather than being stated:
|
|
|
188
197
|
A bundle declares `requires.features: ["customTarball"]`: a deployment that
|
|
189
198
|
cannot run a client-supplied tarball cannot run the entry, whatever trigger kinds
|
|
190
199
|
it offers. It never declares `repos` - the raw create endpoint has no such field,
|
|
191
|
-
and a bundle fetches what it needs itself.
|
|
200
|
+
and a bundle fetches what it needs itself. In an `actions` entry, creation-path
|
|
201
|
+
features move down to each action (`presetPrompt`, `presetPlugin`, or
|
|
202
|
+
`customTarball`) so a deployment can offer the supported choices without needing
|
|
203
|
+
every creation path.
|
|
192
204
|
|
|
193
205
|
### Format constraints
|
|
194
206
|
|
|
@@ -208,17 +220,19 @@ trust boundary. It enforces:
|
|
|
208
220
|
Placeholders are namespaced and the schema rejects any other namespace: `{{form.*}}` for what the user
|
|
209
221
|
entered and `{{automation.*}}` for the entry itself. There is deliberately no secrets namespace.
|
|
210
222
|
|
|
211
|
-
### The
|
|
223
|
+
### The archetypes
|
|
212
224
|
|
|
213
225
|
| Entry | Archetype | Trigger | Produces |
|
|
214
226
|
| --- | --- | --- | --- |
|
|
215
227
|
| `github-pr-reviewer` | Direct scheduled, script bundle | `cron` | an upload, then a create payload |
|
|
216
228
|
| `github-repo-monitor` | Direct scheduled | `cron` | a create payload |
|
|
229
|
+
| `qa-changes` | Direct event | `event` | a create payload |
|
|
230
|
+
| `custom-automation` | Direct custom action with prompt, plugin, or upload variants | `cron` or `event` | a create payload, or an upload then create payload |
|
|
217
231
|
| `incident-retrospective-drafter` | Assisted conversation | decided during the conversation | a seed message |
|
|
218
232
|
|
|
219
|
-
An
|
|
220
|
-
|
|
221
|
-
|
|
233
|
+
An entry can declare both `cron` and `event` under `setup.form.triggers`. The host treats those keys as
|
|
234
|
+
selectable variants and creates the payload from the selected one; a deployment that only supports one of
|
|
235
|
+
the variants can still offer that supported path.
|
|
222
236
|
|
|
223
237
|
The assisted archetype has no payload and no preflight, because at the end of its flow no automation exists
|
|
224
238
|
yet. The agent creates it during the conversation, and the service validates it there. That is the defining
|
|
@@ -300,9 +314,11 @@ import scenarios from "@openhands/extensions/testing/automations/github-pr-revie
|
|
|
300
314
|
must result. That pairing is the contract: form shape and API shape genuinely differ, the create endpoint
|
|
301
315
|
is declared `extra="forbid"`, and a mapping mistake is a 422 discovered only at creation time.
|
|
302
316
|
|
|
303
|
-
Each scenario carries whichever blocks apply: `formValues`, `
|
|
304
|
-
`preflight`, `create`, `conversation`, `expectedFieldErrors`,
|
|
305
|
-
`
|
|
317
|
+
Each scenario carries whichever blocks apply: `formValues`, `selectedTrigger`, `integrationState`,
|
|
318
|
+
`localValidation`, `preflight`, `create`, `conversation`, `expectedFieldErrors`,
|
|
319
|
+
`expectedPrerequisiteOutcome`. `selectedTrigger` is required when an entry declares multiple trigger
|
|
320
|
+
variants and the scenario records a create or preflight payload. `capabilities.json` holds deployment
|
|
321
|
+
shapes so the unsupported paths have coverage too.
|
|
306
322
|
|
|
307
323
|
Beyond the derivation checks, every request body here has been verified against the live Pydantic models in
|
|
308
324
|
`OpenHands/automation`:
|
|
@@ -359,7 +375,7 @@ questions to this work. What changed and why:
|
|
|
359
375
|
| `analytics` | Removed. The same stages fire for every automation, so they belong in shared host code. |
|
|
360
376
|
| `workflow.steps` | Removed. It restated which keys were present, creating a second source of truth that could contradict the file. |
|
|
361
377
|
| `form.intent: "seed"` | Removed. Derivable from `setup.mode: "assisted"`. |
|
|
362
|
-
| `triggerKindsAnyOf` | Removed. The keys of `form.triggers` are the trigger
|
|
378
|
+
| `triggerKindsAnyOf` | Removed. The keys of `form.triggers` are the available trigger variants, and multiple keys already mean the host can offer any supported one. |
|
|
363
379
|
| `{{form.filledCount}}` | Removed. It overloaded the `form` namespace with a computed value that names no field. |
|
|
364
380
|
| `submit.message` | Kept as `setup.message`, capped at 2000 characters, so seed messages cannot grow back into the giant runtime prompts that recommended automation cards were already fixed to stop sending. |
|
|
365
381
|
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "custom-automation",
|
|
3
|
+
"name": "Custom automation",
|
|
4
|
+
"category": "Custom",
|
|
5
|
+
"icon": "sparkles",
|
|
6
|
+
"description": "Create a custom automation from a prompt, plugin-powered prompt, or uploaded script tarball.",
|
|
7
|
+
"requires": {
|
|
8
|
+
"integrations": {
|
|
9
|
+
"github": {
|
|
10
|
+
"message": "Optional. Used when you choose a GitHub repository to clone or trigger from GitHub events.",
|
|
11
|
+
"required": false
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"popularityRank": 99,
|
|
16
|
+
"estimatedSetupMinutes": 5,
|
|
17
|
+
"skill": "openhands-automation",
|
|
18
|
+
"exampleImplementation": "Action: a user-selected prompt, plugin, or uploaded tarball creation path\nTrigger: a user-selected cron schedule or event source and event type\n\n1. Ask whether the automation should run a prompt, run a prompt with plugins, or upload a tarball.\n2. Render only the fields for the selected creation path.\n3. Create prompt automations through /v1/preset/prompt, plugin automations through /v1/preset/plugin, and uploaded tarball automations by uploading to /v1/uploads then creating through /v1.\n4. The selected trigger and common run settings are shared by all creation paths.",
|
|
19
|
+
"setup": {
|
|
20
|
+
"version": "1.0",
|
|
21
|
+
"mode": "direct",
|
|
22
|
+
"form": {
|
|
23
|
+
"note": "Choose whether this custom automation runs a plain prompt, a prompt with plugins, or your own uploaded tarball. Prompt and plugin runs use the LLM; uploaded tarballs are best for deterministic scripts.",
|
|
24
|
+
"triggers": {
|
|
25
|
+
"cron": {
|
|
26
|
+
"schedule": {
|
|
27
|
+
"type": "cron",
|
|
28
|
+
"label": "Schedule",
|
|
29
|
+
"help": "How often this automation should run.",
|
|
30
|
+
"default": "0 9 * * *",
|
|
31
|
+
"required": true
|
|
32
|
+
},
|
|
33
|
+
"timezone": {
|
|
34
|
+
"type": "timezone",
|
|
35
|
+
"label": "Timezone",
|
|
36
|
+
"help": "Timezone used to evaluate the schedule.",
|
|
37
|
+
"default": "UTC",
|
|
38
|
+
"required": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"event": {
|
|
42
|
+
"source": {
|
|
43
|
+
"type": "event-source",
|
|
44
|
+
"label": "Event source",
|
|
45
|
+
"help": "Webhook source that starts the automation.",
|
|
46
|
+
"default": "github",
|
|
47
|
+
"required": true
|
|
48
|
+
},
|
|
49
|
+
"on": {
|
|
50
|
+
"type": "event-type",
|
|
51
|
+
"label": "Event type",
|
|
52
|
+
"help": "Event key or wildcard pattern that starts the automation.",
|
|
53
|
+
"placeholder": "issue_comment.created",
|
|
54
|
+
"required": true
|
|
55
|
+
},
|
|
56
|
+
"filter": {
|
|
57
|
+
"type": "textarea",
|
|
58
|
+
"label": "Event filter",
|
|
59
|
+
"help": "Optional JMESPath expression evaluated against the event payload.",
|
|
60
|
+
"placeholder": "glob(repository.full_name, 'OpenHands/*')",
|
|
61
|
+
"required": false,
|
|
62
|
+
"constraints": {
|
|
63
|
+
"maxLength": 2000
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"args": {
|
|
69
|
+
"name": {
|
|
70
|
+
"type": "text",
|
|
71
|
+
"label": "Automation name",
|
|
72
|
+
"help": "Name shown in the automations list.",
|
|
73
|
+
"placeholder": "Daily repository summary",
|
|
74
|
+
"required": true,
|
|
75
|
+
"constraints": {
|
|
76
|
+
"minLength": 1,
|
|
77
|
+
"maxLength": 500
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"model": {
|
|
81
|
+
"type": "llm-profile",
|
|
82
|
+
"label": "LLM profile",
|
|
83
|
+
"help": "Optional model profile used for automation runs. Leave blank to use the active profile.",
|
|
84
|
+
"required": false
|
|
85
|
+
},
|
|
86
|
+
"timeout": {
|
|
87
|
+
"type": "number",
|
|
88
|
+
"label": "Timeout (seconds)",
|
|
89
|
+
"help": "Maximum time a single run may take. Leave blank for the service default.",
|
|
90
|
+
"required": false,
|
|
91
|
+
"constraints": {
|
|
92
|
+
"min": 1,
|
|
93
|
+
"max": 1800
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"actions": {
|
|
99
|
+
"prompt": {
|
|
100
|
+
"label": "Prompt",
|
|
101
|
+
"help": "Run a natural-language prompt with the default OpenHands agent.",
|
|
102
|
+
"features": [
|
|
103
|
+
"presetPrompt"
|
|
104
|
+
],
|
|
105
|
+
"args": {
|
|
106
|
+
"prompt": {
|
|
107
|
+
"type": "textarea",
|
|
108
|
+
"label": "Prompt",
|
|
109
|
+
"help": "Instructions the agent follows every time the automation runs.",
|
|
110
|
+
"placeholder": "Summarize recent repository activity and post the result to Slack.",
|
|
111
|
+
"required": true,
|
|
112
|
+
"constraints": {
|
|
113
|
+
"minLength": 1,
|
|
114
|
+
"maxLength": 50000
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"repository": {
|
|
118
|
+
"type": "repo-picker",
|
|
119
|
+
"label": "Repository",
|
|
120
|
+
"help": "Optional GitHub repository to clone before each run.",
|
|
121
|
+
"provider": "github",
|
|
122
|
+
"required": false
|
|
123
|
+
},
|
|
124
|
+
"ref": {
|
|
125
|
+
"type": "text",
|
|
126
|
+
"label": "Branch or ref",
|
|
127
|
+
"help": "Branch, tag, or commit to check out when a repository is selected.",
|
|
128
|
+
"placeholder": "main",
|
|
129
|
+
"required": false,
|
|
130
|
+
"constraints": {
|
|
131
|
+
"minLength": 1,
|
|
132
|
+
"maxLength": 255
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"prompt": "{{form.prompt}}"
|
|
137
|
+
},
|
|
138
|
+
"plugin": {
|
|
139
|
+
"label": "Plugin",
|
|
140
|
+
"help": "Run a prompt with one or more OpenHands plugins loaded.",
|
|
141
|
+
"features": [
|
|
142
|
+
"presetPlugin"
|
|
143
|
+
],
|
|
144
|
+
"args": {
|
|
145
|
+
"plugins": {
|
|
146
|
+
"type": "plugin-sources",
|
|
147
|
+
"label": "Plugins",
|
|
148
|
+
"help": "One or more plugin sources to load. Each source may include an optional ref and repository path.",
|
|
149
|
+
"required": true
|
|
150
|
+
},
|
|
151
|
+
"prompt": {
|
|
152
|
+
"type": "textarea",
|
|
153
|
+
"label": "Prompt",
|
|
154
|
+
"help": "Instructions the agent follows after loading the plugins.",
|
|
155
|
+
"placeholder": "Use the plugin commands to inspect the repository and summarize findings.",
|
|
156
|
+
"required": true,
|
|
157
|
+
"constraints": {
|
|
158
|
+
"minLength": 1,
|
|
159
|
+
"maxLength": 50000
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"repository": {
|
|
163
|
+
"type": "repo-picker",
|
|
164
|
+
"label": "Repository",
|
|
165
|
+
"help": "Optional GitHub repository to clone before each run.",
|
|
166
|
+
"provider": "github",
|
|
167
|
+
"required": false
|
|
168
|
+
},
|
|
169
|
+
"ref": {
|
|
170
|
+
"type": "text",
|
|
171
|
+
"label": "Branch or ref",
|
|
172
|
+
"help": "Branch, tag, or commit to check out when a repository is selected.",
|
|
173
|
+
"placeholder": "main",
|
|
174
|
+
"required": false,
|
|
175
|
+
"constraints": {
|
|
176
|
+
"minLength": 1,
|
|
177
|
+
"maxLength": 255
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"prompt": "{{form.prompt}}",
|
|
182
|
+
"plugins": "{{form.plugins}}"
|
|
183
|
+
},
|
|
184
|
+
"upload": {
|
|
185
|
+
"label": "Upload tarball",
|
|
186
|
+
"help": "Upload a .tar or .tar.gz containing the automation code to run.",
|
|
187
|
+
"features": [
|
|
188
|
+
"customTarball"
|
|
189
|
+
],
|
|
190
|
+
"args": {
|
|
191
|
+
"tarball": {
|
|
192
|
+
"type": "tarball-upload",
|
|
193
|
+
"label": "Tarball",
|
|
194
|
+
"help": "A .tar or .tar.gz archive containing the automation code. Maximum size is enforced by the automation service.",
|
|
195
|
+
"required": true
|
|
196
|
+
},
|
|
197
|
+
"entrypoint": {
|
|
198
|
+
"type": "text",
|
|
199
|
+
"label": "Entrypoint",
|
|
200
|
+
"help": "Command to run after the tarball is extracted.",
|
|
201
|
+
"default": "python3 main.py",
|
|
202
|
+
"placeholder": "python3 main.py",
|
|
203
|
+
"required": true,
|
|
204
|
+
"constraints": {
|
|
205
|
+
"minLength": 1,
|
|
206
|
+
"maxLength": 500
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
"setupScript": {
|
|
210
|
+
"type": "text",
|
|
211
|
+
"label": "Setup script",
|
|
212
|
+
"help": "Optional path inside the tarball to run before the entrypoint.",
|
|
213
|
+
"placeholder": "setup.sh",
|
|
214
|
+
"required": false,
|
|
215
|
+
"constraints": {
|
|
216
|
+
"minLength": 1,
|
|
217
|
+
"maxLength": 255
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"tarballPath": "{{form.tarball}}",
|
|
222
|
+
"entrypoint": "{{form.entrypoint}}",
|
|
223
|
+
"setupScript": "{{form.setupScript}}"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
"filter": "{{form.filter}}",
|
|
227
|
+
"message": "This deployment cannot create custom automations directly. Set it up in this conversation instead: choose prompt, plugin, or uploaded tarball mode; confirm the selected trigger, model profile, timeout, and mode-specific fields; then create the automation."
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "github-issue-to-pr",
|
|
3
|
-
"name": "GitHub
|
|
3
|
+
"name": "GitHub issue to PR",
|
|
4
4
|
"category": "Software development",
|
|
5
5
|
"description": "Watch for a configurable label on GitHub issues, implement the issue in a clone of the default branch, and open a pull request for each label event.",
|
|
6
6
|
"requires": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "github-pr-reviewer",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
-
"name": "GitHub
|
|
4
|
+
"name": "GitHub code review",
|
|
5
5
|
"category": "Code review",
|
|
6
6
|
"description": "Watch for a configurable label on GitHub pull requests, inspect full PR and repository context, and post an AI review comment once per label event.",
|
|
7
7
|
"requires": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "qa-changes",
|
|
3
|
-
"name": "QA
|
|
3
|
+
"name": "QA changes",
|
|
4
4
|
"category": "Code review",
|
|
5
5
|
"description": "When a pull request is opened for review, run the QA changes methodology — set up the environment, exercise the changed behavior as a real user would, and post the outcome by editing the PR description with a QA Agent section.",
|
|
6
6
|
"requires": {
|
|
@@ -3,23 +3,24 @@
|
|
|
3
3
|
// run: npm run build:automations
|
|
4
4
|
|
|
5
5
|
import entry0 from "./catalog/github-pr-reviewer/manifest.json" with { type: "json" };
|
|
6
|
-
import entry1 from "./catalog/
|
|
7
|
-
import entry2 from "./catalog/github-
|
|
8
|
-
import entry3 from "./catalog/
|
|
9
|
-
import entry4 from "./catalog/slack-
|
|
10
|
-
import entry5 from "./catalog/
|
|
11
|
-
import entry6 from "./catalog/linear-
|
|
12
|
-
import entry7 from "./catalog/linear-issue-to-
|
|
13
|
-
import entry8 from "./catalog/linear-issue-to-
|
|
14
|
-
import entry9 from "./catalog/
|
|
15
|
-
import entry10 from "./catalog/
|
|
16
|
-
import entry11 from "./catalog/
|
|
17
|
-
import entry12 from "./catalog/
|
|
18
|
-
import entry13 from "./catalog/
|
|
19
|
-
import entry14 from "./catalog/
|
|
20
|
-
import entry15 from "./catalog/
|
|
21
|
-
import entry16 from "./catalog/
|
|
22
|
-
import entry17 from "./catalog/
|
|
6
|
+
import entry1 from "./catalog/custom-automation/manifest.json" with { type: "json" };
|
|
7
|
+
import entry2 from "./catalog/github-repo-monitor/manifest.json" with { type: "json" };
|
|
8
|
+
import entry3 from "./catalog/github-issue-to-pr/manifest.json" with { type: "json" };
|
|
9
|
+
import entry4 from "./catalog/slack-standup-digest/manifest.json" with { type: "json" };
|
|
10
|
+
import entry5 from "./catalog/slack-channel-monitor/manifest.json" with { type: "json" };
|
|
11
|
+
import entry6 from "./catalog/linear-triage-assistant/manifest.json" with { type: "json" };
|
|
12
|
+
import entry7 from "./catalog/linear-issue-to-github-pr/manifest.json" with { type: "json" };
|
|
13
|
+
import entry8 from "./catalog/linear-issue-to-gitlab-mr/manifest.json" with { type: "json" };
|
|
14
|
+
import entry9 from "./catalog/linear-issue-to-bitbucket-pr/manifest.json" with { type: "json" };
|
|
15
|
+
import entry10 from "./catalog/jira-issue-to-pr/manifest.json" with { type: "json" };
|
|
16
|
+
import entry11 from "./catalog/qa-changes/manifest.json" with { type: "json" };
|
|
17
|
+
import entry12 from "./catalog/jira-issue-to-gitlab-mr/manifest.json" with { type: "json" };
|
|
18
|
+
import entry13 from "./catalog/research-brief-writer/manifest.json" with { type: "json" };
|
|
19
|
+
import entry14 from "./catalog/jira-issue-to-bitbucket-pr/manifest.json" with { type: "json" };
|
|
20
|
+
import entry15 from "./catalog/github-agents-md-maintainer/manifest.json" with { type: "json" };
|
|
21
|
+
import entry16 from "./catalog/upstream-fork-sync/manifest.json" with { type: "json" };
|
|
22
|
+
import entry17 from "./catalog/incident-retrospective-drafter/manifest.json" with { type: "json" };
|
|
23
|
+
import entry18 from "./catalog/news-digest/manifest.json" with { type: "json" };
|
|
23
24
|
|
|
24
25
|
export const AUTOMATION_CATALOG_ENTRIES = [
|
|
25
26
|
entry0,
|
|
@@ -40,4 +41,5 @@ export const AUTOMATION_CATALOG_ENTRIES = [
|
|
|
40
41
|
entry15,
|
|
41
42
|
entry16,
|
|
42
43
|
entry17,
|
|
44
|
+
entry18,
|
|
43
45
|
];
|