@openhands/extensions 0.12.0 → 0.14.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/.release-please-manifest.json +1 -1
- package/README.md +3 -2
- package/automations/README.md +56 -7
- package/automations/catalog/github-pr-reviewer/manifest.json +2 -1
- package/automations/catalog/github-repo-monitor/manifest.json +2 -1
- package/automations/catalog/upstream-fork-sync/manifest.json +85 -0
- package/automations/catalog-index.js +3 -1
- package/automations/catalog.schema.json +2 -3
- package/automations/index.d.ts +122 -1
- package/automations/index.js +7 -0
- package/automations/interface.json +70 -0
- package/automations/interface.schema.json +243 -0
- package/index.d.ts +13 -1
- package/index.js +1 -1
- package/marketplaces/openhands-extensions.json +14 -0
- package/package.json +3 -1
- package/pyproject.toml +1 -1
- package/python/openhands_extensions/_version.py +1 -1
- package/skills/index.js +9 -1
- package/skills/openhands-automation/SKILL.md +11 -0
- package/skills/openhands-automation/references/custom-automation.md +2 -0
- package/skills/openhands-automation/references/security.md +84 -0
- package/skills/upstream-fork-sync/.plugin/plugin.json +21 -0
- package/skills/upstream-fork-sync/README.md +38 -0
- package/skills/upstream-fork-sync/SKILL.md +122 -0
- package/skills/upstream-fork-sync/commands/upstream-fork-sync-setup.md +8 -0
- package/tests/fixtures/automations/upstream-fork-sync.json +223 -0
- package/tests/test_interface_manifest.py +107 -0
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ The JS and Python versions are kept in lock-step by `release-please` and guarded
|
|
|
89
89
|
## Extensions Catalog
|
|
90
90
|
|
|
91
91
|
<!-- BEGIN AUTO-GENERATED CATALOG -->
|
|
92
|
-
This repository contains **2 marketplace(s)** with **
|
|
92
|
+
This repository contains **2 marketplace(s)** with **64 extensions** (54 skills, 10 plugins).
|
|
93
93
|
|
|
94
94
|
### large-codebase
|
|
95
95
|
|
|
@@ -108,7 +108,7 @@ OpenHands skills for interacting, improving, and refactoring large codebases
|
|
|
108
108
|
|
|
109
109
|
Official skills and plugins for OpenHands — the open-source AI software engineer.
|
|
110
110
|
|
|
111
|
-
**
|
|
111
|
+
**60 extensions** (52 skills, 8 plugins)
|
|
112
112
|
|
|
113
113
|
| Name | Type | Description | Commands |
|
|
114
114
|
|------|------|-------------|----------|
|
|
@@ -168,6 +168,7 @@ Official skills and plugins for OpenHands — the open-source AI software engine
|
|
|
168
168
|
| swift-linux | skill | Install and configure Swift programming language on Debian Linux for server-side development. Use when building Swift... | — |
|
|
169
169
|
| technical-writing | skill | Write and revise technical explanations in flowing, direct, conversational prose that stays concise without becoming ... | — |
|
|
170
170
|
| theme-factory | skill | Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc.... | — |
|
|
171
|
+
| upstream-fork-sync | skill | Keep a long-lived fork in sync with its upstream. Creates a cron automation that fetches upstream changes, rebases lo... | `/upstream-fork-sync:setup` |
|
|
171
172
|
| uv | skill | Common project, dependency, and environment operations using uv. | — |
|
|
172
173
|
| vercel | skill | Deploy and manage applications on Vercel, including preview deployments and deployment protection. | — |
|
|
173
174
|
| vulnerability-remediation | plugin | Automated security vulnerability scanning and AI-powered remediation. Scans repositories, skips when no issues found,... | — |
|
package/automations/README.md
CHANGED
|
@@ -9,6 +9,8 @@ uploaded to the automations service as a `.tar.gz`, belongs in the same director
|
|
|
9
9
|
catalog/<id>/manifest.json one automation per directory - card metadata plus an optional `setup` block
|
|
10
10
|
catalog.schema.json the contract, JSON Schema draft 2020-12
|
|
11
11
|
catalog-index.js generated from catalog/ - do not edit by hand
|
|
12
|
+
interface.json the production Automation interface manifest - domain-level, not per-entry
|
|
13
|
+
interface.schema.json its contract, JSON Schema draft 2020-12
|
|
12
14
|
index.js the stable API for Node.js and bundlers
|
|
13
15
|
index.d.ts the public TypeScript shape
|
|
14
16
|
```
|
|
@@ -117,6 +119,11 @@ An assisted entry declares no triggers, because the trigger is settled during th
|
|
|
117
119
|
- **`mode: "assisted"`** declares a `message`: setup context handed to an agent conversation that finishes
|
|
118
120
|
the job. The command that opens that conversation comes from the skill, so it is not repeated here.
|
|
119
121
|
|
|
122
|
+
A direct entry may also declare a `message`. It is the seed for the fallback conversation the host offers
|
|
123
|
+
when the deployment cannot run the direct path - a deployment whose capabilities lack the entry's trigger
|
|
124
|
+
kind or required features. The same 2000-character cap applies, and because the fallback fires before the
|
|
125
|
+
form is trustworthy, a direct `message` should not reference `{{form.*}}`.
|
|
126
|
+
|
|
120
127
|
A form field is named after the property it fills. `schedule` and `timezone` under `triggers.cron` become
|
|
121
128
|
`trigger.schedule` and `trigger.timezone`; `on` under `triggers.event` becomes `trigger.on`; a field named
|
|
122
129
|
`ref` becomes `repos[].ref`. Any other field under a trigger kind, such as a phrase to match, is an input
|
|
@@ -162,6 +169,45 @@ a webhook variant is out of scope, while its `setup` block creates the webhook f
|
|
|
162
169
|
supports. Both statements are accurate about their own generation. Retiring the skill path for entries that
|
|
163
170
|
ship a `setup` block belongs to whoever promotes this to production.
|
|
164
171
|
|
|
172
|
+
## The interface manifest (`interface.json`)
|
|
173
|
+
|
|
174
|
+
The catalog states what varies per automation. `interface.json` states the domain-level facts of the
|
|
175
|
+
production Automation interface - the things that vary between *domains* (automations today, another
|
|
176
|
+
extension surface tomorrow) rather than between entries, so each is stated once rather than eight times.
|
|
177
|
+
Agent Canvas keeps its rendering components and reads every automation-specific datum from this file,
|
|
178
|
+
falling back to its built-in defaults when the manifest is absent or fails admission:
|
|
179
|
+
|
|
180
|
+
- **`routes`** - the list, setup, and detail routes. The host must have a registration serving each
|
|
181
|
+
declared shape, so admission verifies they match what it mounted; the manifest is the single source for
|
|
182
|
+
link construction.
|
|
183
|
+
- **`navigation`** - the sidebar entry and the command-menu entry.
|
|
184
|
+
- **`pages`** - page-identity copy: the list title and subtitle, the detail back label, the edit-dialog
|
|
185
|
+
title. Generic chrome - buttons, toasts, empty states, validation sentences - stays host copy, rendered
|
|
186
|
+
through the host's translations.
|
|
187
|
+
- **`docsUrl`** - the automations documentation link, prefix-pinned to docs.openhands.dev by schema.
|
|
188
|
+
- **`attributes`** - the input surface of an existing Automation: which attributes can be set after
|
|
189
|
+
creation, keyed by the runtime-model property the host sends (`name`, `prompt`, `model`, `timeout`,
|
|
190
|
+
`schedule`), with labels, help, and numeric bounds. How a client offers them - Agent Canvas renders an
|
|
191
|
+
edit dialog - is the client's choice, not stated here. `schedule` is a semantic type: the host owns the
|
|
192
|
+
frequency/weekday/time composite it renders, as it owns the setup form's `cron` type.
|
|
193
|
+
- **`importExport`** - the export file envelope (`kind`, `version`, filename suffix) and the two facts an
|
|
194
|
+
import cannot derive from the file: the provider inferred for short repository URLs, and the placeholder
|
|
195
|
+
event source that keeps a half-imported automation inert until its real trigger is applied.
|
|
196
|
+
- **`endpoints`** - service-relative paths the host calls. Relative paths only: the base path, methods,
|
|
197
|
+
headers, and auth remain the host's, so this cannot express a request to anywhere the host did not
|
|
198
|
+
choose. `{id}` marks where the host substitutes the automation id.
|
|
199
|
+
- **`featuredAutomationIds`** / **`responderIntegrationIds`** - the catalog entries the list page surfaces
|
|
200
|
+
as proven, and the integrations whose automations get the responder deployment-choice dialog.
|
|
201
|
+
|
|
202
|
+
`interface.schema.json` is the authoritative contract, under the same trust rules as the catalog: no
|
|
203
|
+
markup in copy, no free-form URLs, closed key sets, no credentials. This narrowly reverses the `routes`
|
|
204
|
+
and `submit` deletions recorded below **at the domain level only** - per-entry data still follows the
|
|
205
|
+
deletion table.
|
|
206
|
+
|
|
207
|
+
Changing a route or endpoint here still requires a host release that serves the declared shape, so the
|
|
208
|
+
Distribution open question applies unchanged. The contract fixtures pin `/v1/preset/prompt` as the create
|
|
209
|
+
endpoint; changing `endpoints.createPrompt` must regenerate them in the same release.
|
|
210
|
+
|
|
165
211
|
## Contract fixtures
|
|
166
212
|
|
|
167
213
|
The fixtures are independent test vectors, not part of the runtime catalog. They live in
|
|
@@ -201,11 +247,12 @@ Two findings came out of that check and are baked into the entries:
|
|
|
201
247
|
| Endpoint | Status |
|
|
202
248
|
| --- | --- |
|
|
203
249
|
| `POST /v1/preset/prompt` | Exists |
|
|
204
|
-
| `GET /v1/capabilities` |
|
|
205
|
-
| `POST /v1/validate` |
|
|
250
|
+
| `GET /v1/capabilities` | Exists (OpenHands/automation#270) |
|
|
251
|
+
| `POST /v1/validate` | Exists (OpenHands/automation#270) |
|
|
206
252
|
|
|
207
|
-
None of these appear in a
|
|
208
|
-
no catalog entry at
|
|
253
|
+
None of these appear in a catalog entry. Their service-relative paths are stated once, in
|
|
254
|
+
`interface.json`'s `endpoints` block, which is why settling on different paths changes no catalog entry at
|
|
255
|
+
all.
|
|
209
256
|
|
|
210
257
|
## Deviations from the project reference document
|
|
211
258
|
|
|
@@ -217,7 +264,7 @@ questions to this work. What changed and why:
|
|
|
217
264
|
| A separate manifest file per automation | Merged into the catalog entry as `setup`, so there is one hand-authored record per automation and nothing to keep in sync. |
|
|
218
265
|
| `prompt` | Removed. It duplicated the slash command already declared in the skill's `triggers:` frontmatter. The entry names the `skill` instead, defaulting to `id`, and the command is looked up from the skills catalog. |
|
|
219
266
|
| `requiredIntegrationIds` | Removed. It duplicated the integration ids in `requires`, which now sits on the entry so every automation carries them once. |
|
|
220
|
-
| `routes` | Removed. The
|
|
267
|
+
| `routes` | Removed from entries. The route table is a domain-level fact, stated once in `interface.json`. |
|
|
221
268
|
| `capabilities` | Removed. The discovery call is the same for every automation, and the block's only entry-specific content was a feature list, now `requires.features`. |
|
|
222
269
|
| `capabilities.bindings` | Removed. The `cron` and `timezone` field types tell the host to resolve the deployment's limits on their own. |
|
|
223
270
|
| `requires.secrets` | Removed. An automation that needs GitHub declares the GitHub integration; the credential comes with the connection rather than being asked for twice. |
|
|
@@ -227,7 +274,7 @@ questions to this work. What changed and why:
|
|
|
227
274
|
| `form.fields` | Split into `form.triggers` and `form.args`, and both keyed by field name so the name is the key rather than a repeated property. |
|
|
228
275
|
| `validation` | Removed. The preflight call has the same shape for every automation, and the payload-path mapping is recovered by walking `payload`. |
|
|
229
276
|
| `review` | Removed. The confirmation screen is the declared fields and their labels. |
|
|
230
|
-
| `submit` | Reduced to the parts that vary: `prompt` and, for an event trigger, `filter` for direct; `message` for assisted. The action,
|
|
277
|
+
| `submit` | Reduced to the parts that vary: `prompt` and, for an event trigger, `filter` for direct; `message` for assisted (and, on direct entries, as the fallback-conversation seed). The action, success navigation, and error handling are identical everywhere; the endpoints are domain-level and live in `interface.json`. |
|
|
231
278
|
| `submit.payload` | Removed. `name`, `repos` and `trigger` all restated the form, so they are rebuilt from it. What is left is the prompt and the event filter. |
|
|
232
279
|
| `analytics` | Removed. The same stages fire for every automation, so they belong in shared host code. |
|
|
233
280
|
| `workflow.steps` | Removed. It restated which keys were present, creating a second source of truth that could contradict the file. |
|
|
@@ -253,6 +300,8 @@ Recorded rather than resolved, because they need an owner outside this contract:
|
|
|
253
300
|
related fields onto one line, which reads better; if that matters, it is a host concern, not an entry's.
|
|
254
301
|
- **Assisted-setup completion.** The assisted flow ends at a conversation, so the host cannot emit a
|
|
255
302
|
completion event. Until something reports back, the ratio of direct to assisted setup is not measurable.
|
|
256
|
-
- **
|
|
303
|
+
- **Delete confirmation and per-run views.** `interface.json` models the list, setup, and detail routes
|
|
304
|
+
and the settable attributes; deletion, run logs, and the dashboard sub-pages remain host-owned surfaces
|
|
305
|
+
with no manifest data of their own yet.
|
|
257
306
|
- **Types from the schema.** `index.d.ts` is hand-written and mirrors `catalog.schema.json`. Generating it
|
|
258
307
|
would remove that second source of truth.
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
|
-
"prompt": "Review pull requests labeled '{{form.triggerLabel}}' in {{form.repository}}. Review tone: {{form.reviewTone}}."
|
|
80
|
+
"prompt": "Review pull requests labeled '{{form.triggerLabel}}' in {{form.repository}}. Review tone: {{form.reviewTone}}.",
|
|
81
|
+
"message": "This deployment cannot run the scheduled review automation directly. Set it up in this conversation instead: confirm the repository to review, the trigger label, the review tone, and the polling schedule, then create the automation."
|
|
81
82
|
}
|
|
82
83
|
}
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
79
|
"prompt": "A comment in {{form.repository}} mentions '{{form.triggerPhrase}}'. Read the surrounding issue or pull request context from the event payload, then post a helpful reply as a comment on the same thread.",
|
|
80
|
-
"filter": "icontains(comment.body, '{{form.triggerPhrase}}') && glob(repository.full_name, '{{form.repository}}')"
|
|
80
|
+
"filter": "icontains(comment.body, '{{form.triggerPhrase}}') && glob(repository.full_name, '{{form.repository}}')",
|
|
81
|
+
"message": "This deployment cannot run the webhook-driven monitor directly. Set it up in this conversation instead: confirm the repository to watch, the comment event, and the trigger phrase, then create the automation. If webhook delivery is unavailable here, build the polling variant this skill supports."
|
|
81
82
|
}
|
|
82
83
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "upstream-fork-sync",
|
|
3
|
+
"name": "Upstream fork sync",
|
|
4
|
+
"category": "Developer tools",
|
|
5
|
+
"description": "Keep a long-lived fork current with its upstream by re-running a nightly job that fetches upstream changes, rebases local customizations on top, verifies the software still works, and replaces the running version when it does.",
|
|
6
|
+
"requires": {
|
|
7
|
+
"integrations": {
|
|
8
|
+
"github": {
|
|
9
|
+
"message": "Used to fetch upstream changes and push the rebased fork."
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"features": [
|
|
13
|
+
"repoClone",
|
|
14
|
+
"presetPrompt"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"popularityRank": 80,
|
|
18
|
+
"estimatedSetupMinutes": 4,
|
|
19
|
+
"exampleImplementation": "Trigger: cron, nightly (configurable)\nRequired secret: GITHUB_PERSONAL_ACCESS_TOKEN\n\n1. Clone the fork repository and fetch the latest from its upstream remote.\n2. Rebase every local customization commit on top of the newest upstream HEAD.\n3. Run the configured verification command to confirm the software works as intended.\n4. If verification passes, force-push the rebased branch and replace the currently deployed version with the freshly built one.\n5. If verification fails, leave the running version untouched and report the conflict.",
|
|
20
|
+
"setup": {
|
|
21
|
+
"version": "1.0",
|
|
22
|
+
"mode": "direct",
|
|
23
|
+
"form": {
|
|
24
|
+
"triggers": {
|
|
25
|
+
"cron": {
|
|
26
|
+
"schedule": {
|
|
27
|
+
"type": "cron",
|
|
28
|
+
"label": "Sync schedule",
|
|
29
|
+
"help": "How often to fetch upstream and rebase local changes. Nightly is the default.",
|
|
30
|
+
"default": "0 3 * * *",
|
|
31
|
+
"required": true
|
|
32
|
+
},
|
|
33
|
+
"timezone": {
|
|
34
|
+
"type": "timezone",
|
|
35
|
+
"label": "Timezone",
|
|
36
|
+
"help": "Timezone the schedule is interpreted in.",
|
|
37
|
+
"default": "UTC",
|
|
38
|
+
"required": true
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"args": {
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "repo-picker",
|
|
45
|
+
"label": "Repository",
|
|
46
|
+
"help": "The long-lived fork to keep synchronized with upstream.",
|
|
47
|
+
"provider": "github",
|
|
48
|
+
"required": true
|
|
49
|
+
},
|
|
50
|
+
"upstreamRemote": {
|
|
51
|
+
"type": "text",
|
|
52
|
+
"label": "Upstream remote",
|
|
53
|
+
"help": "The remote (URL or owner/repo) the fork tracks. Defaults to the repository's parent.",
|
|
54
|
+
"default": "",
|
|
55
|
+
"required": false,
|
|
56
|
+
"constraints": {
|
|
57
|
+
"maxLength": 255
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"localChanges": {
|
|
61
|
+
"type": "text",
|
|
62
|
+
"label": "Local changes",
|
|
63
|
+
"help": "Plain-language description of the customizations to preserve across rebase.",
|
|
64
|
+
"default": "",
|
|
65
|
+
"required": false,
|
|
66
|
+
"constraints": {
|
|
67
|
+
"maxLength": 2000
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"verifyCommand": {
|
|
71
|
+
"type": "text",
|
|
72
|
+
"label": "Verify command",
|
|
73
|
+
"help": "The command that confirms the software works as intended (e.g. `make test`). If blank, the agent infers a sensible check.",
|
|
74
|
+
"default": "",
|
|
75
|
+
"required": false,
|
|
76
|
+
"constraints": {
|
|
77
|
+
"maxLength": 500
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"prompt": "Fetch the latest upstream changes for the fork {{form.repository}} and rebase all local changes on top of upstream. Local changes to preserve: {{form.localChanges}}. Check that the software works as intended; if it does, replace the current version, otherwise leave the running version untouched and report what failed.",
|
|
83
|
+
"message": "This deployment cannot run the scheduled fork-sync automation directly. Set it up in this conversation instead: confirm the fork repository, the upstream remote, the local changes to preserve, the verification command, and the nightly schedule, then create the automation."
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -9,7 +9,8 @@ import entry3 from "./catalog/slack-channel-monitor/manifest.json" with { type:
|
|
|
9
9
|
import entry4 from "./catalog/linear-triage-assistant/manifest.json" with { type: "json" };
|
|
10
10
|
import entry5 from "./catalog/jira-issue-to-pr/manifest.json" with { type: "json" };
|
|
11
11
|
import entry6 from "./catalog/research-brief-writer/manifest.json" with { type: "json" };
|
|
12
|
-
import entry7 from "./catalog/
|
|
12
|
+
import entry7 from "./catalog/upstream-fork-sync/manifest.json" with { type: "json" };
|
|
13
|
+
import entry8 from "./catalog/incident-retrospective-drafter/manifest.json" with { type: "json" };
|
|
13
14
|
|
|
14
15
|
export const AUTOMATION_CATALOG_ENTRIES = [
|
|
15
16
|
entry0,
|
|
@@ -20,4 +21,5 @@ export const AUTOMATION_CATALOG_ENTRIES = [
|
|
|
20
21
|
entry5,
|
|
21
22
|
entry6,
|
|
22
23
|
entry7,
|
|
24
|
+
entry8,
|
|
23
25
|
];
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"$ref": "#/$defs/templateValue"
|
|
69
69
|
},
|
|
70
70
|
"message": {
|
|
71
|
-
"description": "
|
|
71
|
+
"description": "Setup context handed to the agent conversation that finishes setup. Required for assisted mode. Optional for direct mode, where it seeds the fallback conversation the host offers when the deployment cannot run the direct path. The command that opens it comes from the skill, so it is not repeated here. Capped so this never becomes a channel for runtime instructions.",
|
|
72
72
|
"allOf": [{ "$ref": "#/$defs/templateCopy" }, { "maxLength": 2000 }]
|
|
73
73
|
}
|
|
74
74
|
},
|
|
@@ -79,8 +79,7 @@
|
|
|
79
79
|
"required": ["mode"]
|
|
80
80
|
},
|
|
81
81
|
"then": {
|
|
82
|
-
"required": ["prompt"]
|
|
83
|
-
"not": { "required": ["message"] }
|
|
82
|
+
"required": ["prompt"]
|
|
84
83
|
}
|
|
85
84
|
},
|
|
86
85
|
{
|
package/automations/index.d.ts
CHANGED
|
@@ -104,10 +104,131 @@ export interface AutomationSetup {
|
|
|
104
104
|
prompt?: string;
|
|
105
105
|
/** direct only, event trigger only. Which delivered events belong to it. */
|
|
106
106
|
filter?: string;
|
|
107
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Setup context for the conversation that finishes setup. Required for
|
|
109
|
+
* assisted mode. Optional for direct mode, where it seeds the fallback
|
|
110
|
+
* conversation offered when the deployment cannot run the direct path.
|
|
111
|
+
*/
|
|
108
112
|
message?: string;
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
/**
|
|
116
|
+
* The production Automation interface manifest.
|
|
117
|
+
*
|
|
118
|
+
* Mirrors `automations/interface.schema.json`, which is authoritative. The
|
|
119
|
+
* catalog states what varies per automation; this states the domain-level
|
|
120
|
+
* facts of the interface itself: routes, navigation, page-identity copy, the
|
|
121
|
+
* settable attributes of an automation, the import/export envelope, the
|
|
122
|
+
* service-relative endpoints, and the featured and responder id lists. The
|
|
123
|
+
* host validates it at admission and falls back to its built-in defaults when
|
|
124
|
+
* it is absent or rejected.
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
export interface AutomationInterfaceRoutes {
|
|
128
|
+
list: string;
|
|
129
|
+
/** Carries the `:automationId` segment the host substitutes. */
|
|
130
|
+
setup: string;
|
|
131
|
+
/** Carries the `:automationId` segment the host substitutes. */
|
|
132
|
+
detail: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface AutomationInterfaceNavigation {
|
|
136
|
+
sidebar: { label: string };
|
|
137
|
+
commandMenu: { title: string; description: string; keywords: string };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface AutomationInterfacePages {
|
|
141
|
+
list: { title: string; subtitle: string };
|
|
142
|
+
detail: { backLabel: string };
|
|
143
|
+
edit: { title: string };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type AutomationAttributeType =
|
|
147
|
+
| "text"
|
|
148
|
+
| "textarea"
|
|
149
|
+
| "number"
|
|
150
|
+
| "llm-profile"
|
|
151
|
+
| "schedule";
|
|
152
|
+
|
|
153
|
+
/** The closed set of runtime-model properties a client may offer for setting. */
|
|
154
|
+
export type AutomationAttributeName =
|
|
155
|
+
| "name"
|
|
156
|
+
| "prompt"
|
|
157
|
+
| "model"
|
|
158
|
+
| "timeout"
|
|
159
|
+
| "schedule";
|
|
160
|
+
|
|
161
|
+
export interface AutomationAttributeConstraints {
|
|
162
|
+
min?: number;
|
|
163
|
+
max?: number;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** How one settable attribute of an existing Automation is offered. */
|
|
167
|
+
export interface AutomationAttribute {
|
|
168
|
+
type: AutomationAttributeType;
|
|
169
|
+
label: string;
|
|
170
|
+
help?: string;
|
|
171
|
+
required: boolean;
|
|
172
|
+
/** Only a `number` attribute carries constraints. */
|
|
173
|
+
constraints?: AutomationAttributeConstraints;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The input surface of an existing Automation, keyed by the runtime-model
|
|
178
|
+
* property the host sends. How a client offers these - Agent Canvas renders
|
|
179
|
+
* an edit dialog - is the client's choice, not stated here.
|
|
180
|
+
*/
|
|
181
|
+
export type AutomationInterfaceAttributes = Partial<
|
|
182
|
+
Record<AutomationAttributeName, AutomationAttribute>
|
|
183
|
+
>;
|
|
184
|
+
|
|
185
|
+
export interface AutomationImportDefaults {
|
|
186
|
+
/** Provider inferred for short owner/repo repository URLs on import. */
|
|
187
|
+
repoProvider: AutomationGitProvider;
|
|
188
|
+
/** Event source of the placeholder trigger that keeps an import inert. */
|
|
189
|
+
placeholderEventSource: string;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface AutomationInterfaceImportExport {
|
|
193
|
+
fileKind: string;
|
|
194
|
+
fileVersion: 1;
|
|
195
|
+
filenameSuffix: string;
|
|
196
|
+
importDefaults: AutomationImportDefaults;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Service-relative paths the host calls. Relative paths only: the base path,
|
|
201
|
+
* methods, headers, and auth remain the host's. `{id}` marks where the host
|
|
202
|
+
* substitutes the automation id.
|
|
203
|
+
*/
|
|
204
|
+
export interface AutomationInterfaceEndpoints {
|
|
205
|
+
list: string;
|
|
206
|
+
detail: string;
|
|
207
|
+
dispatch: string;
|
|
208
|
+
runs: string;
|
|
209
|
+
tarball: string;
|
|
210
|
+
health: string;
|
|
211
|
+
capabilities: string;
|
|
212
|
+
validate: string;
|
|
213
|
+
createPrompt: string;
|
|
214
|
+
createPlugin: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface AutomationInterfaceManifest {
|
|
218
|
+
version: "1.0";
|
|
219
|
+
routes: AutomationInterfaceRoutes;
|
|
220
|
+
navigation: AutomationInterfaceNavigation;
|
|
221
|
+
pages: AutomationInterfacePages;
|
|
222
|
+
docsUrl: string;
|
|
223
|
+
attributes: AutomationInterfaceAttributes;
|
|
224
|
+
importExport: AutomationInterfaceImportExport;
|
|
225
|
+
endpoints: AutomationInterfaceEndpoints;
|
|
226
|
+
featuredAutomationIds: string[];
|
|
227
|
+
responderIntegrationIds: string[];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export const AUTOMATION_INTERFACE: AutomationInterfaceManifest;
|
|
231
|
+
|
|
111
232
|
export const AUTOMATION_CATALOG: RecommendedAutomation[];
|
|
112
233
|
/**
|
|
113
234
|
* Return the full automation catalog.
|
package/automations/index.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* package can statically import each JSON file without an aggregate JSON asset.
|
|
7
7
|
*/
|
|
8
8
|
import { AUTOMATION_CATALOG_ENTRIES } from "./catalog-index.js";
|
|
9
|
+
import interfaceManifest from "./interface.json" with { type: "json" };
|
|
9
10
|
|
|
10
11
|
const clone = (value) => JSON.parse(JSON.stringify(value));
|
|
11
12
|
const AUTOMATIONS = AUTOMATION_CATALOG_ENTRIES;
|
|
@@ -20,4 +21,10 @@ export const getAutomationCatalogEntry = (id) => {
|
|
|
20
21
|
|
|
21
22
|
export const AUTOMATION_CATALOG = clone(AUTOMATIONS);
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The production Automation interface manifest: the domain-level facts of the
|
|
26
|
+
* interface, hand-authored in `automations/interface.json`.
|
|
27
|
+
*/
|
|
28
|
+
export const AUTOMATION_INTERFACE = clone(interfaceManifest);
|
|
29
|
+
|
|
23
30
|
export default AUTOMATION_CATALOG;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"routes": {
|
|
4
|
+
"list": "/automations",
|
|
5
|
+
"setup": "/automations/new/:automationId",
|
|
6
|
+
"detail": "/automations/:automationId"
|
|
7
|
+
},
|
|
8
|
+
"navigation": {
|
|
9
|
+
"sidebar": { "label": "Automate" },
|
|
10
|
+
"commandMenu": {
|
|
11
|
+
"title": "Automations",
|
|
12
|
+
"description": "Review scheduled and webhook automations.",
|
|
13
|
+
"keywords": "automate cron schedule webhook jobs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"pages": {
|
|
17
|
+
"list": {
|
|
18
|
+
"title": "Automations",
|
|
19
|
+
"subtitle": "View active and inactive automations, search by metadata, and inspect read-only details."
|
|
20
|
+
},
|
|
21
|
+
"detail": { "backLabel": "Back to Automations" },
|
|
22
|
+
"edit": { "title": "Edit automation" }
|
|
23
|
+
},
|
|
24
|
+
"docsUrl": "https://docs.openhands.dev/openhands/usage/automations/overview",
|
|
25
|
+
"attributes": {
|
|
26
|
+
"name": { "type": "text", "label": "Name", "required": true },
|
|
27
|
+
"prompt": {
|
|
28
|
+
"type": "textarea",
|
|
29
|
+
"label": "Prompt",
|
|
30
|
+
"help": "Edits apply to future runs only.",
|
|
31
|
+
"required": false
|
|
32
|
+
},
|
|
33
|
+
"model": { "type": "llm-profile", "label": "LLM profile", "required": false },
|
|
34
|
+
"timeout": {
|
|
35
|
+
"type": "number",
|
|
36
|
+
"label": "Timeout (seconds)",
|
|
37
|
+
"help": "Maximum time a single run may take. Leave empty for the default of 600 seconds (10 minutes); maximum 1800 seconds (30 minutes).",
|
|
38
|
+
"required": false,
|
|
39
|
+
"constraints": { "min": 1, "max": 1800 }
|
|
40
|
+
},
|
|
41
|
+
"schedule": { "type": "schedule", "label": "Frequency", "required": false }
|
|
42
|
+
},
|
|
43
|
+
"importExport": {
|
|
44
|
+
"fileKind": "automation",
|
|
45
|
+
"fileVersion": 1,
|
|
46
|
+
"filenameSuffix": ".automation.json",
|
|
47
|
+
"importDefaults": {
|
|
48
|
+
"repoProvider": "github",
|
|
49
|
+
"placeholderEventSource": "agent-canvas-import"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"endpoints": {
|
|
53
|
+
"list": "/v1",
|
|
54
|
+
"detail": "/v1/{id}",
|
|
55
|
+
"dispatch": "/v1/{id}/dispatch",
|
|
56
|
+
"runs": "/v1/{id}/runs",
|
|
57
|
+
"tarball": "/v1/{id}/tarball",
|
|
58
|
+
"health": "/health",
|
|
59
|
+
"capabilities": "/v1/capabilities",
|
|
60
|
+
"validate": "/v1/validate",
|
|
61
|
+
"createPrompt": "/v1/preset/prompt",
|
|
62
|
+
"createPlugin": "/v1/preset/plugin"
|
|
63
|
+
},
|
|
64
|
+
"featuredAutomationIds": [
|
|
65
|
+
"github-pr-reviewer",
|
|
66
|
+
"github-repo-monitor",
|
|
67
|
+
"slack-channel-monitor"
|
|
68
|
+
],
|
|
69
|
+
"responderIntegrationIds": ["github", "slack"]
|
|
70
|
+
}
|