Repository navigation
feat(plugins): add prompt-task, the stock plugin for prompt automations #799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
simonrosenberg
wants to merge
2
commits into
main
Choose a base branch
from
automation-prompt-plugin
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| .plugin |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| .plugin |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| { | ||
| "name": "prompt-task", | ||
| "version": "1.0.0", | ||
| "description": "Run a typed prompt as an OpenHands automation, launched from the agent profile chosen for it", | ||
| "author": { | ||
| "name": "OpenHands", | ||
| "email": "contact@all-hands.dev" | ||
| }, | ||
| "homepage": "https://github.com/OpenHands/extensions/tree/main/plugins/prompt-task", | ||
| "repository": "https://github.com/OpenHands/extensions", | ||
| "license": "MIT", | ||
| "keywords": [ | ||
| "automation", | ||
| "prompt", | ||
| "agent-profile" | ||
| ], | ||
| "automation": { | ||
| "schema_version": "openhands.automation.plugin.v1", | ||
| "entrypoint": { | ||
| "runner": "conversation", | ||
| "command": "run", | ||
| "arguments": "{{ config.prompt }}" | ||
| }, | ||
| "runtime": { | ||
| "agent_profile": { | ||
| "required": true | ||
| } | ||
| }, | ||
| "config_schema": { | ||
| "type": "object", | ||
| "additionalProperties": false, | ||
| "required": [ | ||
| "prompt" | ||
| ], | ||
| "properties": { | ||
| "prompt": { | ||
| "type": "string", | ||
| "title": "Prompt", | ||
| "description": "What the agent does on every run.", | ||
| "minLength": 1, | ||
| "maxLength": 50000 | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # prompt-task | ||
|
|
||
| The stock plugin behind prompt automations. It turns a typed prompt into a | ||
| plugin-spec automation, so the run is launched from the agent profile chosen | ||
| for the automation: its tools (including sub-agents), MCP servers, skills and | ||
| model. | ||
|
|
||
| ## Usage | ||
|
|
||
| Create the automation through the Automation Service's `POST /v1/plugin-spec`: | ||
|
|
||
| ```json | ||
| { | ||
| "name": "Weekly issue triage", | ||
| "plugin": { | ||
| "source": "github:OpenHands/extensions", | ||
| "repo_path": "plugins/prompt-task" | ||
| }, | ||
| "config": {"prompt": "Label every unlabeled issue opened this week"}, | ||
| "agent_profile_id": "<agent profile id>", | ||
| "trigger": {"type": "cron", "schedule": "0 9 * * 1", "timezone": "UTC"} | ||
| } | ||
| ``` | ||
|
|
||
| Each run sends `/prompt-task:run <prompt>`, where `<prompt>` is the | ||
| `config.prompt` value, to a conversation the service starts from the agent | ||
| profile. The manifest names no default profile, so `agent_profile_id` is | ||
| required; a client normally defaults it to the user's active profile. | ||
|
|
||
| `agent_profile_id` requires an Automation Service that advertises | ||
| `pluginSpecAgentProfiles` in `GET /v1/capabilities`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| --- | ||
| description: Carry out the task an automation was set up with | ||
| argument-hint: <task> | ||
| --- | ||
|
|
||
| # Automation task | ||
|
|
||
| An automation started this conversation. Your task is the text that follows | ||
| `/prompt-task:run` in the message. | ||
|
|
||
| - Nobody is watching the conversation live, so complete the task end to end | ||
| without waiting for a reply. | ||
| - If the message includes an event payload or follow-up messages, treat them | ||
| as the context the task refers to. | ||
| - End with a short summary of what you did and anything left undone. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """The prompt-task plugin backs prompt automations created as plugin specs.""" | ||
|
|
||
| import json | ||
| import re | ||
| from pathlib import Path | ||
|
|
||
| import yaml | ||
|
|
||
|
|
||
| REPO_ROOT = Path(__file__).parent.parent | ||
| PLUGIN = REPO_ROOT / "plugins" / "prompt-task" | ||
|
|
||
|
|
||
| def _automation() -> dict: | ||
| return json.loads((PLUGIN / ".plugin" / "plugin.json").read_text())["automation"] | ||
|
|
||
|
|
||
| def test_runs_the_configured_prompt_on_a_chosen_agent_profile(): | ||
| automation = _automation() | ||
| entrypoint = automation["entrypoint"] | ||
|
|
||
| assert automation["schema_version"] == "openhands.automation.plugin.v1" | ||
| assert entrypoint["runner"] == "conversation" | ||
| assert (PLUGIN / "commands" / f"{entrypoint['command']}.md").is_file() | ||
| assert entrypoint["arguments"] == "{{ config.prompt }}" | ||
| assert automation["config_schema"]["required"] == ["prompt"] | ||
| assert automation["runtime"]["agent_profile"] == {"required": True} | ||
|
|
||
|
|
||
| def test_command_triggers_no_public_skill(): | ||
| message = "/prompt-task:run " | ||
| matches = [] | ||
| for skill in [ | ||
| *REPO_ROOT.glob("skills/*/SKILL.md"), | ||
| *REPO_ROOT.glob("plugins/*/SKILL.md"), | ||
| *REPO_ROOT.glob("plugins/*/skills/*/SKILL.md"), | ||
| ]: | ||
| frontmatter = re.match(r"^---\n(.*?)\n---", skill.read_text(), re.S) | ||
| if not frontmatter: | ||
| continue | ||
| for trigger in (yaml.safe_load(frontmatter.group(1)) or {}).get( | ||
| "triggers" | ||
| ) or []: | ||
| if str(trigger).lower() in message: | ||
| matches.append(f"{skill.parent.name}: {trigger}") | ||
| assert matches == [] | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The glob list here covers
skills/*/SKILL.mdandplugins/*/skills/*/SKILL.mdbut omits top-levelplugins/*/SKILL.md, which the SDK also loads as keyword-triggered skills.plugins/runtime-api-configs/SKILL.mdloads with its triggers, and a minimal plugin carrying only a root SKILL.md loads its triggers too (verified withopenhands.sdk.plugin.Plugin.loadand_keyword_matches). A future top-level plugin SKILL.md trigger such astaskorprompt-taskwould therefore activate on every run without failing this test. No file currently collides, so this is not blocking: add*REPO_ROOT.glob("plugins/*/SKILL.md")to close the gap the test is meant to guard.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
plugins/*/SKILL.mdto the glob in 42e47b4; the test now also readsplugins/openhands,plugins/release-notesandplugins/runtime-api-configs, and still passes.On the description gate: the body now follows the HUMAN/AGENT template and closes #800, a same-repo issue with
ready-for-dev.check_pr_description.pypasses against it.I'm an AI agent (Claude Code) helping @simonrosenberg.