@openhands/extensions 0.11.0 → 0.12.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/AGENTS.md +2 -1
- package/MIGRATION.md +31 -0
- package/README.md +9 -7
- package/automations/README.md +251 -8
- package/automations/catalog/github-pr-reviewer/manifest.json +82 -0
- package/automations/catalog/github-repo-monitor/manifest.json +82 -0
- package/automations/catalog/incident-retrospective-drafter/manifest.json +100 -0
- package/automations/catalog/{jira-issue-to-pr.json → jira-issue-to-pr/manifest.json} +10 -5
- package/automations/catalog/{linear-triage-assistant.json → linear-triage-assistant/manifest.json} +8 -4
- package/automations/catalog/{research-brief-writer.json → research-brief-writer/manifest.json} +11 -5
- package/automations/catalog/{slack-channel-monitor.json → slack-channel-monitor/manifest.json} +7 -2
- package/automations/catalog/{slack-standup-digest.json → slack-standup-digest/manifest.json} +8 -5
- package/automations/catalog-index.js +23 -0
- package/automations/catalog.schema.json +273 -0
- package/automations/index.d.ts +111 -3
- package/automations/index.js +21 -18
- package/index.d.ts +16 -1
- package/integrations/catalog/datadog.json +3 -3
- package/integrations/index.d.ts +1 -1
- package/package.json +6 -3
- package/pyproject.toml +1 -1
- package/python/openhands_extensions/__init__.py +0 -4
- package/python/openhands_extensions/_version.py +3 -2
- package/python/openhands_extensions/integrations.py +8 -30
- package/scripts/build-automation-catalog.mjs +51 -0
- package/skills/bitbucket/SKILL.md +0 -1
- package/skills/github/SKILL.md +0 -1
- package/skills/gitlab/SKILL.md +0 -1
- package/skills/index.js +4 -7
- package/skills/openhands-sdk/SKILL.md +2 -0
- package/tests/fixtures/automations/capabilities.json +92 -0
- package/tests/fixtures/automations/github-pr-reviewer.json +251 -0
- package/tests/fixtures/automations/github-repo-monitor.json +180 -0
- package/tests/fixtures/automations/incident-retrospective-drafter.json +91 -0
- package/tests/test_automation_setup.py +526 -0
- package/tests/test_catalogs.py +37 -12
- package/tests/test_deprecations.py +39 -4
- package/tests/test_integration_catalog_in_sync.py +50 -60
- package/automations/catalog/github-pr-reviewer.json +0 -13
- package/automations/catalog/github-repo-monitor.json +0 -11
- package/automations/catalog/incident-retrospective-drafter.json +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openhands/extensions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Public OpenHands extension catalogs for skills, plugins, integrations, and automation templates.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build:skills": "node scripts/build-skills-catalog.mjs",
|
|
13
13
|
"build:integrations": "node scripts/build-integration-catalog.mjs",
|
|
14
|
-
"build": "
|
|
14
|
+
"build:automations": "node scripts/build-automation-catalog.mjs",
|
|
15
|
+
"build": "npm run build:skills && npm run build:integrations && npm run build:automations"
|
|
15
16
|
},
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": ">=18.20.0"
|
|
@@ -35,7 +36,8 @@
|
|
|
35
36
|
"import": "./automations/index.js",
|
|
36
37
|
"default": "./automations/index.js"
|
|
37
38
|
},
|
|
38
|
-
"./automations/catalog
|
|
39
|
+
"./automations/catalog/*": "./automations/catalog/*",
|
|
40
|
+
"./automations/catalog.schema.json": "./automations/catalog.schema.json",
|
|
39
41
|
"./integrations": {
|
|
40
42
|
"types": "./integrations/index.d.ts",
|
|
41
43
|
"import": "./integrations/index.js",
|
|
@@ -50,6 +52,7 @@
|
|
|
50
52
|
"./skills/*": "./skills/*",
|
|
51
53
|
"./plugins/*": "./plugins/*",
|
|
52
54
|
"./marketplaces/*.json": "./marketplaces/*.json",
|
|
55
|
+
"./testing/automations/*.json": "./tests/fixtures/automations/*.json",
|
|
53
56
|
"./package.json": "./package.json"
|
|
54
57
|
}
|
|
55
58
|
}
|
package/pyproject.toml
CHANGED
|
@@ -12,9 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
from ._version import __version__
|
|
13
13
|
from .integrations import (
|
|
14
14
|
INTEGRATION_CATALOG_SNAPSHOT,
|
|
15
|
-
get_integration_catalog_entry,
|
|
16
15
|
get_integration_catalog_entry_model,
|
|
17
|
-
list_integration_catalog,
|
|
18
16
|
list_integration_catalog_models,
|
|
19
17
|
)
|
|
20
18
|
from .integration_models import (
|
|
@@ -55,8 +53,6 @@ __all__ = [
|
|
|
55
53
|
"StdioTransport",
|
|
56
54
|
"StreamableHttpTransport",
|
|
57
55
|
"__version__",
|
|
58
|
-
"get_integration_catalog_entry",
|
|
59
56
|
"get_integration_catalog_entry_model",
|
|
60
|
-
"list_integration_catalog",
|
|
61
57
|
"list_integration_catalog_models",
|
|
62
58
|
]
|
|
@@ -16,8 +16,9 @@ from importlib.metadata import PackageNotFoundError, version
|
|
|
16
16
|
|
|
17
17
|
#: Fallback used only when the package is not installed (no dist metadata).
|
|
18
18
|
#: Kept in lock-step with pyproject.toml/package.json by the version test.
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
#: release-please only rewrites a semver found on the annotated line itself, so
|
|
20
|
+
#: the annotation must stay on the assignment; on its own line it is a no-op.
|
|
21
|
+
_FALLBACK_VERSION = "0.12.0" # x-release-please-version
|
|
21
22
|
|
|
22
23
|
try:
|
|
23
24
|
__version__: str = version("openhands-extensions")
|
|
@@ -14,15 +14,12 @@ from importlib import resources
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, Iterable
|
|
16
16
|
|
|
17
|
-
from .deprecation import deprecated
|
|
18
17
|
from .integration_models import IntegrationCatalogEntry
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
__all__ = [
|
|
22
21
|
"INTEGRATION_CATALOG_SNAPSHOT",
|
|
23
|
-
"get_integration_catalog_entry",
|
|
24
22
|
"get_integration_catalog_entry_model",
|
|
25
|
-
"list_integration_catalog",
|
|
26
23
|
"list_integration_catalog_models",
|
|
27
24
|
]
|
|
28
25
|
|
|
@@ -81,20 +78,11 @@ def _entry_supports_oauth(entry: dict[str, Any]) -> bool:
|
|
|
81
78
|
)
|
|
82
79
|
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
deprecated_in="0.10.0",
|
|
86
|
-
removed_in="0.12.0",
|
|
87
|
-
details="Use list_integration_catalog_models() for validated Pydantic models.",
|
|
88
|
-
)
|
|
89
|
-
def list_integration_catalog(
|
|
81
|
+
def _list_catalog_entries(
|
|
90
82
|
mcp: bool | None = None,
|
|
91
83
|
oauth: bool | None = None,
|
|
92
84
|
) -> list[dict[str, Any]]:
|
|
93
|
-
"""Return raw catalog dictionaries, optionally filtered by connector type.
|
|
94
|
-
|
|
95
|
-
Deprecated since v0.10.0 and scheduled for removal in v0.12.0.
|
|
96
|
-
Use :func:`list_integration_catalog_models` instead.
|
|
97
|
-
"""
|
|
85
|
+
"""Return raw catalog dictionaries, optionally filtered by connector type."""
|
|
98
86
|
result = []
|
|
99
87
|
for entry in _integrations():
|
|
100
88
|
if mcp is not None and _entry_supports_mcp(entry) != mcp:
|
|
@@ -111,34 +99,24 @@ def list_integration_catalog_models(
|
|
|
111
99
|
) -> list[IntegrationCatalogEntry]:
|
|
112
100
|
"""Return typed, validated integration catalog entries.
|
|
113
101
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this function for a stable, validated contract.
|
|
102
|
+
This is the supported Python contract for reading the catalog. The raw
|
|
103
|
+
dictionary accessors it replaced were removed in v0.12.0.
|
|
117
104
|
"""
|
|
118
105
|
return [
|
|
119
106
|
IntegrationCatalogEntry.model_validate(entry)
|
|
120
|
-
for entry in
|
|
107
|
+
for entry in _list_catalog_entries(mcp=mcp, oauth=oauth)
|
|
121
108
|
]
|
|
122
109
|
|
|
123
110
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
removed_in="0.12.0",
|
|
127
|
-
details="Use get_integration_catalog_entry_model() for a validated Pydantic model.",
|
|
128
|
-
)
|
|
129
|
-
def get_integration_catalog_entry(id: str) -> dict[str, Any] | None:
|
|
130
|
-
"""Return one raw catalog dictionary by id, or ``None``.
|
|
131
|
-
|
|
132
|
-
Deprecated since v0.10.0 and scheduled for removal in v0.12.0.
|
|
133
|
-
Use :func:`get_integration_catalog_entry_model` instead.
|
|
134
|
-
"""
|
|
111
|
+
def _get_catalog_entry(id: str) -> dict[str, Any] | None:
|
|
112
|
+
"""Return one raw catalog dictionary by id, or ``None``."""
|
|
135
113
|
entry = _integration_by_id().get(id)
|
|
136
114
|
return copy.deepcopy(entry) if entry is not None else None
|
|
137
115
|
|
|
138
116
|
|
|
139
117
|
def get_integration_catalog_entry_model(id: str) -> IntegrationCatalogEntry | None:
|
|
140
118
|
"""Return one typed catalog entry, or ``None`` when it does not exist."""
|
|
141
|
-
entry =
|
|
119
|
+
entry = _get_catalog_entry(id)
|
|
142
120
|
return IntegrationCatalogEntry.model_validate(entry) if entry is not None else None
|
|
143
121
|
|
|
144
122
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const root = process.cwd();
|
|
5
|
+
const catalogDir = path.join(root, "automations", "catalog");
|
|
6
|
+
const outputPath = path.join(root, "automations", "catalog-index.js");
|
|
7
|
+
|
|
8
|
+
const directories = (await readdir(catalogDir, { withFileTypes: true }))
|
|
9
|
+
.filter((entry) => entry.isDirectory())
|
|
10
|
+
.map((entry) => entry.name)
|
|
11
|
+
.sort((left, right) => left.localeCompare(right));
|
|
12
|
+
|
|
13
|
+
const automations = await Promise.all(
|
|
14
|
+
directories.map(async (directory) => ({
|
|
15
|
+
directory,
|
|
16
|
+
entry: JSON.parse(
|
|
17
|
+
await readFile(path.join(catalogDir, directory, "manifest.json"), "utf8"),
|
|
18
|
+
),
|
|
19
|
+
})),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
automations.sort((left, right) => {
|
|
23
|
+
const rank = (right.entry.popularityRank ?? -1) - (left.entry.popularityRank ?? -1);
|
|
24
|
+
return rank || left.entry.id.localeCompare(right.entry.id);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const indexedAutomations = automations.map((automation, index) => ({
|
|
28
|
+
...automation,
|
|
29
|
+
importName: `entry${index}`,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const imports = indexedAutomations
|
|
33
|
+
.map(
|
|
34
|
+
({ directory, importName }) =>
|
|
35
|
+
`import ${importName} from "./catalog/${directory}/manifest.json" with { type: "json" };`,
|
|
36
|
+
)
|
|
37
|
+
.join("\n");
|
|
38
|
+
const entries = indexedAutomations.map(({ importName }) => ` ${importName},`).join("\n");
|
|
39
|
+
|
|
40
|
+
const header = `// This file is auto-generated by scripts/build-automation-catalog.mjs.
|
|
41
|
+
// Do not edit it manually. To update it after changing automations/catalog/*/manifest.json,
|
|
42
|
+
// run: npm run build:automations
|
|
43
|
+
|
|
44
|
+
`;
|
|
45
|
+
const body = `${header}${imports}
|
|
46
|
+
|
|
47
|
+
export const AUTOMATION_CATALOG_ENTRIES = [
|
|
48
|
+
${entries}
|
|
49
|
+
];
|
|
50
|
+
`;
|
|
51
|
+
await writeFile(outputPath, body);
|
|
@@ -3,7 +3,6 @@ name: bitbucket
|
|
|
3
3
|
description: Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.
|
|
4
4
|
triggers:
|
|
5
5
|
- bitbucket
|
|
6
|
-
- git
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
You are working with **Bitbucket**, which ships as two distinct products that behave
|
package/skills/github/SKILL.md
CHANGED
|
@@ -3,7 +3,6 @@ name: github
|
|
|
3
3
|
description: Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable and GitHub CLI. Use when working with code hosted on GitHub or managing GitHub resources.
|
|
4
4
|
triggers:
|
|
5
5
|
- github
|
|
6
|
-
- git
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
You have access to an environment variable, `GITHUB_TOKEN`, which allows you to interact with
|
package/skills/gitlab/SKILL.md
CHANGED
|
@@ -3,7 +3,6 @@ name: gitlab
|
|
|
3
3
|
description: Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.
|
|
4
4
|
triggers:
|
|
5
5
|
- gitlab
|
|
6
|
-
- git
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
You have access to an environment variable, `GITLAB_TOKEN`, which allows you to interact with
|
package/skills/index.js
CHANGED
|
@@ -70,8 +70,7 @@ export const SKILLS_CATALOG = [
|
|
|
70
70
|
"name": "bitbucket",
|
|
71
71
|
"description": "Bitbucket integration hub. Detects whether the repository is on Bitbucket Cloud or Bitbucket Data Center and directs you to the matching detailed skill (bitbucket-cloud or bitbucket-data-center). Use for any Bitbucket repository or pull request task.",
|
|
72
72
|
"triggers": [
|
|
73
|
-
"bitbucket"
|
|
74
|
-
"git"
|
|
73
|
+
"bitbucket"
|
|
75
74
|
],
|
|
76
75
|
"content": "You are working with **Bitbucket**, which ships as two distinct products that behave\ndifferently:\n\n- **Bitbucket Cloud** (`bitbucket.org`) — authenticates with the `BITBUCKET_TOKEN`\n environment variable.\n- **Bitbucket Data Center** (self-hosted Bitbucket Server) — authenticates with the\n `BITBUCKET_DATA_CENTER_TOKEN` environment variable.\n\nThey use different REST APIs, repository identifiers, git remote URL formats, and pull\nrequest tools, so you must first determine which one you are on, then load the matching\ndetailed skill for full instructions.\n\n## Step 1 — Detect which Bitbucket you are on\n\nCheck which token environment variable is present. Environment variable names are\ncase-sensitive, so look for it case-insensitively:\n\n```bash\nenv | grep -i 'bitbucket' || echo \"no bitbucket token found\"\n```\n\n- If a **`BITBUCKET_DATA_CENTER_TOKEN`** variable is set (in any letter case) → you are on\n **Bitbucket Data Center**.\n- Otherwise, if a **`BITBUCKET_TOKEN`** variable is set → you are on **Bitbucket Cloud**.\n- If neither is set, ask the user how they authenticate to Bitbucket before proceeding.\n\nWhen you reference the token later, use the exact variable name (and letter case) that\nactually exists in the environment.\n\n## Step 2 — Load the detailed skill\n\nOnce you know the environment, use the `invoke_skill` tool to load the matching skill for\nfull instructions on API calls, authenticated git remotes, and opening pull requests:\n\n- Bitbucket Cloud → invoke the **`bitbucket-cloud`** skill.\n- Bitbucket Data Center → invoke the **`bitbucket-data-center`** skill.\n\n## Quick reference (fallback)\n\nIf you are unable to load the detailed skill, these are the essentials. Always use the\nBitbucket API (not a web browser) and always use the listed PR tool to open a pull request.\n\n| | Bitbucket Cloud | Bitbucket Data Center |\n|---|---|---|\n| Token env var | `BITBUCKET_TOKEN` | `BITBUCKET_DATA_CENTER_TOKEN` |\n| Host | `bitbucket.org` | self-hosted domain |\n| REST API base | `https://api.bitbucket.org/2.0` | `https://<host>/rest/api/1.0` |\n| Repository identifier | `workspace/repo_slug` | `PROJECT/repo_slug` (project key) |\n| Pull request tool | `create_bitbucket_pr` | `create_bitbucket_data_center_pr` |"
|
|
77
76
|
},
|
|
@@ -180,8 +179,7 @@ export const SKILLS_CATALOG = [
|
|
|
180
179
|
"name": "github",
|
|
181
180
|
"description": "Interact with GitHub repositories, pull requests, issues, and workflows using the GITHUB_TOKEN environment variable and GitHub CLI. Use when working with code hosted on GitHub or managing GitHub resources.",
|
|
182
181
|
"triggers": [
|
|
183
|
-
"github"
|
|
184
|
-
"git"
|
|
182
|
+
"github"
|
|
185
183
|
],
|
|
186
184
|
"content": "You have access to an environment variable, `GITHUB_TOKEN`, which allows you to interact with\nthe GitHub API.\n\n<IMPORTANT>\nYou can use `curl` with the `GITHUB_TOKEN` to interact with GitHub's API.\nALWAYS use the GitHub API for operations instead of a web browser.\nALWAYS use the `create_pr` tool to open a pull request\nIf the user asks you to check GitHub Actions status, first try to use `gh` to work with workflows, and only fallback to basic API calls if that fails.\nExamples:\n- `gh run watch` (https://cli.github.com/manual/gh_run_watch) to monitor workflow runs\n- `gh pr checks 200 --watch --interval 10` to check until completed.\n</IMPORTANT>\n\nWindows PowerShell equivalents for the multi-line shell snippets below are in `references/windows.md`.\n\nIf you encounter authentication issues when pushing to GitHub (such as password prompts or permission errors), the old token may have expired. In such case, update the remote URL to include the current token: `git remote set-url origin https://${GITHUB_TOKEN}@github.com/username/repo.git`\n\nHere are some instructions for pushing, but ONLY do this if the user asks you to:\n* NEVER push directly to the `main` or `master` branch\n* Git config (username and email) is pre-set. Do not modify.\n* You may already be on a branch starting with `openhands-workspace`. Create a new branch with a better name before pushing.\n* Use the `create_pr` tool to create a pull request, if you haven't already\n* Once you've created your own branch or a pull request, continue to update it. Do NOT create a new one unless you are explicitly asked to. Update the PR title and description as necessary, but don't change the branch name.\n* Use the main branch as the base branch, unless the user requests otherwise\n* After opening or updating a pull request, send the user a short message with a link to the pull request.\n* Do NOT mark a pull request as ready to review unless the user explicitly says so\n* Do all of the above in as few steps as possible. E.g. you could push changes with one step by running the following bash commands:\n```bash\ngit remote -v && git branch # to find the current org, repo and branch\ngit checkout -b create-widget && git add . && git commit -m \"Create widget\" && git push -u origin create-widget\n```\n\n## Handling Review Comments\n\n- Critically evaluate each review comment before acting on it. Not all feedback is worth implementing:\n - Does it fix a real bug or improve clarity significantly?\n - Does it align with the project's engineering principles (simplicity, maintainability)?\n - Is the suggested change proportional to the benefit, or does it add unnecessary complexity?\n- It's acceptable to respectfully decline suggestions that add verbosity without clear benefit, over-engineer for hypothetical edge cases, or contradict the project's pragmatic approach.\n- After addressing (or deciding not to address) inline review comments, mark the corresponding review threads as resolved.\n- Before resolving a thread, leave a reply comment that either explains the reason for dismissing the feedback or references the specific commit (e.g., commit SHA) that addressed the issue.\n- Prefer resolving threads only once fixes are pushed or a clear decision is documented.\n- Use the GitHub GraphQL API to reply to and resolve review threads (see below).\n- After making changes to a PR, verify the title and description still match the content. Update them if the scope, features, or intent changed.\n\n## Resolving Review Threads via GraphQL\n\nTo resolve existing review threads programmatically:\n\n1. Get the thread IDs (replace `<OWNER>`, `<REPO>`, `<PR_NUMBER>`):\n```bash\ngh api graphql -f query='\n{\n repository(owner: \"<OWNER>\", name: \"<REPO>\") {\n pullRequest(number: <PR_NUMBER>) {\n reviewThreads(first: 20) {\n nodes {\n id\n isResolved\n comments(first: 1) {\n nodes { body }\n }\n }\n }\n }\n }\n}'\n```\n\n2. Reply to the thread explaining how the feedback was addressed:\n```bash\ngh api graphql -f query='\nmutation {\n addPullRequestReviewThreadReply(input: {\n pullRequestReviewThreadId: \"<THREAD_ID>\"\n body: \"Fixed in <COMMIT_SHA>\"\n }) {\n comment { id }\n }\n}'\n```\n\n3. Resolve the thread:\n```bash\ngh api graphql -f query='\nmutation {\n resolveReviewThread(input: {threadId: \"<THREAD_ID>\"}) {\n thread { isResolved }\n }\n}'\n```\n\n4. Get the failed workflow run ID and rerun it:\n```bash\n# Find the run ID from the failed check URL, or use:\ngh run list --repo <OWNER>/<REPO> --branch <BRANCH> --limit 5\n\n# Rerun failed jobs\ngh run rerun <RUN_ID> --repo <OWNER>/<REPO> --failed\n```"
|
|
187
185
|
},
|
|
@@ -225,8 +223,7 @@ export const SKILLS_CATALOG = [
|
|
|
225
223
|
"name": "gitlab",
|
|
226
224
|
"description": "Interact with GitLab repositories, merge requests, and APIs using the GITLAB_TOKEN environment variable. Use when working with code hosted on GitLab or managing GitLab resources.",
|
|
227
225
|
"triggers": [
|
|
228
|
-
"gitlab"
|
|
229
|
-
"git"
|
|
226
|
+
"gitlab"
|
|
230
227
|
],
|
|
231
228
|
"content": "You have access to an environment variable, `GITLAB_TOKEN`, which allows you to interact with\nthe GitLab API.\n\n<IMPORTANT>\nYou can use `curl` with the `GITLAB_TOKEN` to interact with GitLab's API.\nALWAYS use the GitLab API for operations instead of a web browser.\nALWAYS use the `create_mr` tool to open a merge request\n</IMPORTANT>\n\nIf you encounter authentication issues when pushing to GitLab (such as password prompts or permission errors), the old token may have expired. In such case, update the remote URL to include the current token: `git remote set-url origin https://oauth2:${GITLAB_TOKEN}@gitlab.com/username/repo.git`\n\nHere are some instructions for pushing, but ONLY do this if the user asks you to:\n* NEVER push directly to the `main` or `master` branch\n* Git config (username and email) is pre-set. Do not modify.\n* You may already be on a branch starting with `openhands-workspace`. Create a new branch with a better name before pushing.\n* Use the `create_mr` tool to create a merge request, if you haven't already\n* Once you've created your own branch or a merge request, continue to update it. Do NOT create a new one unless you are explicitly asked to. Update the PR title and description as necessary, but don't change the branch name.\n* Use the main branch as the base branch, unless the user requests otherwise\n* After opening or updating a merge request, send the user a short message with a link to the merge request.\n* Do all of the above in as few steps as possible. E.g. you could push changes with one step by running the following bash commands:\n```bash\ngit remote -v && git branch # to find the current org, repo and branch\ngit checkout -b create-widget && git add . && git commit -m \"Create widget\" && git push -u origin create-widget\n```\n\nOn Windows PowerShell, use `$env:GITLAB_TOKEN` in remote URLs and run the `git` commands as separate commands if `&&` is not supported by the installed shell."
|
|
232
229
|
},
|
|
@@ -359,7 +356,7 @@ export const SKILLS_CATALOG = [
|
|
|
359
356
|
"agent-sdk",
|
|
360
357
|
"/sdk"
|
|
361
358
|
],
|
|
362
|
-
"content": "# OpenHands Software Agent SDK\n\nAll SDK documentation lives at <https://docs.openhands.dev/sdk>.\n\nFor the full topic index, fetch <https://docs.openhands.dev/llms.txt> and read\nthe \"OpenHands Software Agent SDK\" section.\n\n## Quick reference\n\nInstall: `pip install openhands-sdk openhands-tools`\n\n```python\nimport os\n\nfrom openhands.sdk import LLM, Agent, Conversation, Tool\nfrom openhands.tools.file_editor import FileEditorTool\nfrom openhands.tools.task_tracker import TaskTrackerTool\nfrom openhands.tools.terminal import TerminalTool\n\n\nllm = LLM(\n model=os.getenv(\"LLM_MODEL\", \"gpt-5.5\"),\n api_key=os.getenv(\"LLM_API_KEY\"),\n base_url=os.getenv(\"LLM_BASE_URL\", None),\n)\n\nagent = Agent(\n llm=llm,\n tools=[\n Tool(name=TerminalTool.name),\n Tool(name=FileEditorTool.name),\n Tool(name=TaskTrackerTool.name),\n ],\n)\n\ncwd = os.getcwd()\nconversation = Conversation(agent=agent, workspace=cwd)\n\nconversation.send_message(\"Write 3 facts about the current project into FACTS.txt.\")\nconversation.run()\nprint(\"All done!\")\n```\n\n## Core classes (`openhands.sdk`)\n\n| Class | Purpose |\n|---|---|\n| [`Agent`](https://docs.openhands.dev/sdk/arch/agent.md) | Reasoning-action loop |\n| [`Condenser`](https://docs.openhands.dev/sdk/arch/condenser.md) | Conversation history compression system |\n| [`Conversation`](https://docs.openhands.dev/sdk/arch/conversation.md) | Conversation orchestration system |\n| [`Event`](https://docs.openhands.dev/sdk/arch/events.md) | Typed event framework |\n| [`LLM`](https://docs.openhands.dev/sdk/arch/llm.md) | Provider-agnostic language model interface |\n| [`SecurityAnalyzer`](https://docs.openhands.dev/sdk/arch/security.md) | Action security analysis and validation |\n| [`Skill`](https://docs.openhands.dev/sdk/arch/skill.md) | Reusable prompt system |\n| [`Tool / ToolDefinition`](https://docs.openhands.dev/sdk/arch/tool-system.md) | Action-observation tool framework |\n| [`Workspace`](https://docs.openhands.dev/sdk/arch/workspace.md) | Execution environment abstraction |\n\n## API reference\n\n[`openhands.sdk.agent`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.agent.md), [`openhands.sdk.conversation`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.conversation.md), [`openhands.sdk.event`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.event.md), [`openhands.sdk.llm`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.llm.md), [`openhands.sdk.security`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.security.md), [`openhands.sdk.tool`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.tool.md), [`openhands.sdk.utils`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.utils.md), [`openhands.sdk.workspace`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.workspace.md)\n\n## Guides\n\n- [ACP Agent](https://docs.openhands.dev/sdk/guides/agent-acp.md): Delegate to an ACP-compatible server (Claude Code, Gemini CLI, etc.) instead of calling an LLM directly.\n- [Agent Settings](https://docs.openhands.dev/sdk/guides/agent-settings.md): Configure, serialize, and recreate agents from structured settings.\n- [Agent Skills & Context](https://docs.openhands.dev/sdk/guides/skill.md): Skills add specialized behaviors, domain knowledge, and context-aware triggers to your agent through structured prompts.\n- [API-based Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/api-sandbox.md): Connect to hosted API-based agent server for fully managed infrastructure.\n- [Apptainer Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/apptainer-sandbox.md): Run agent server in rootless Apptainer containers for HPC and shared computing environments.\n- [Ask Agent Questions](https://docs.openhands.dev/sdk/guides/convo-ask-agent.md): Get sidebar replies from the agent during conversation execution without interrupting the main flow.\n- [Assign Reviews](https://docs.openhands.dev/sdk/guides/github-workflows/assign-reviews.md): Automate PR management with intelligent reviewer assignment and workflow notifications using OpenHands Agent\n- [Browser Session Recording](https://docs.openhands.dev/sdk/guides/browser-session-recording.md): Record and replay your agent's browser sessions using rrweb.\n- [Browser Use](https://docs.openhands.dev/sdk/guides/agent-browser-use.md): Enable web browsing and interaction capabilities for your agent.\n- [Context Condenser](https://docs.openhands.dev/sdk/guides/context-condenser.md): Manage agent memory by condensing conversation history to save tokens.\n- [Conversation Goals](https://docs.openhands.dev/sdk/guides/agent-server/conversation-goals.md): Add a resumable goal strategy to a normal agent-server conversation.\n- [Conversation with Async](https://docs.openhands.dev/sdk/guides/convo-async.md): Use async/await for concurrent agent operations and non-blocking execution.\n- [Creating Custom Agent](https://docs.openhands.dev/sdk/guides/agent-custom.md): Learn how to design specialized agents with custom tool sets\n- [Critic (Experimental)](https://docs.openhands.dev/sdk/guides/critic.md): Real-time evaluation of agent actions using an LLM-based critic model, with built-in iterative refinement.\n- [Custom Tools](https://docs.openhands.dev/sdk/guides/custom-tools.md): Tools define what agents can do. The SDK includes built-in tools for common operations and supports creating custom tools for specialized needs.\n- [Custom Tools with Remote Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/custom-tools.md): Learn how to use custom tools with a remote agent server by building a custom base image that includes your tool implementations.\n- [Custom Visualizer](https://docs.openhands.dev/sdk/guides/convo-custom-visualizer.md): Customize conversation visualization by creating custom visualizers or configuring the default visualizer.\n- [Deferred Init (Warm-Pool)](https://docs.openhands.dev/sdk/guides/agent-server/deferred-init.md): Pre-warm agent-server pods before a user is matched, then activate them at runtime with POST /api/init.\n- [Docker Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/docker-sandbox.md): Run agent server in isolated Docker containers for security and reproducibility.\n- [Exception Handling](https://docs.openhands.dev/sdk/guides/llm-error-handling.md): Provider‑agnostic exceptions raised by the SDK and recommended patterns for handling them.\n- [FAQ](https://docs.openhands.dev/sdk/faq.md): Frequently asked questions about the OpenHands SDK\n- [File-Based Agents](https://docs.openhands.dev/sdk/guides/agent-file-based.md): Define specialized sub-agents as simple Markdown files with YAML frontmatter — no Python code required.\n- [Fork a Conversation](https://docs.openhands.dev/sdk/guides/convo-fork.md): Branch off an existing conversation for follow-up exploration without contaminating the original.\n- [Getting Started](https://docs.openhands.dev/sdk/getting-started.md): Install the OpenHands SDK and build AI agents that write software.\n- [Goal Completion Loop](https://docs.openhands.dev/sdk/guides/convo-goal.md): Drive a conversation toward a verifiable objective with a judge-driven, self-continuing completion loop.\n- [GPT-5 Preset (ApplyPatchTool)](https://docs.openhands.dev/sdk/guides/llm-gpt5-preset.md): Use the GPT-5 preset to build an agent that swaps the standard FileEditorTool for ApplyPatchTool.\n- [Hello World](https://docs.openhands.dev/sdk/guides/hello-world.md): The simplest possible OpenHands agent - configure an LLM, create an agent, and complete a task.\n- [Hooks](https://docs.openhands.dev/sdk/guides/hooks.md): Use lifecycle hooks to observe, log, and customize agent execution.\n- [Image Input](https://docs.openhands.dev/sdk/guides/llm-image-input.md): Send images to multimodal agents for vision-based tasks and analysis.\n- [Interactive Terminal](https://docs.openhands.dev/sdk/guides/agent-interactive-terminal.md): Enable agents to interact with terminal applications like ipython, python REPL, and other interactive CLI tools.\n- [Iterative Refinement](https://docs.openhands.dev/sdk/guides/iterative-refinement.md): Implement iterative refinement workflows where agents refine their work based on critique feedback until quality thresholds are met.\n- [LLM Fallback Strategy](https://docs.openhands.dev/sdk/guides/llm-fallback.md): Automatically try alternate LLMs when the primary model fails with a transient error.\n- [LLM Profile Store](https://docs.openhands.dev/sdk/guides/llm-profile-store.md): Save, load, and manage reusable LLM configurations so you never repeat setup code again.\n- [LLM Registry](https://docs.openhands.dev/sdk/guides/llm-registry.md): Dynamically select and configure language models using the LLM registry.\n- [LLM Streaming](https://docs.openhands.dev/sdk/guides/llm-streaming.md): Stream LLM responses token-by-token for real-time display and interactive user experiences.\n- [LLM Subscriptions](https://docs.openhands.dev/sdk/guides/llm-subscriptions.md): Use your ChatGPT Plus/Pro subscription to access Codex models without consuming API credits.\n- [Local Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/local-server.md): Install and run an OpenHands Agent Server on your machine, then connect to it from the SDK.\n- [Metrics Tracking](https://docs.openhands.dev/sdk/guides/metrics.md): Track token usage, costs, and latency metrics for your agents.\n- [Model Context Protocol](https://docs.openhands.dev/sdk/guides/mcp.md): Model Context Protocol (MCP) enables dynamic tool integration from external servers. Agents can discover and use MCP-provided tools automatically.\n- [Model Routing](https://docs.openhands.dev/sdk/guides/llm-routing.md): Route agent's LLM requests to different models.\n- [Observability & Tracing](https://docs.openhands.dev/sdk/guides/observability.md): Enable OpenTelemetry tracing to monitor and debug your agent's execution with tools like Laminar, MLflow, Honeycomb, or any OTLP-compatible backend.\n- [OpenAI-Compatible Endpoint](https://docs.openhands.dev/sdk/guides/agent-server/openai-gateway.md): Call an OpenHands agent-server through the OpenAI Chat Completions protocol.\n- [OpenHands Cloud Workspace](https://docs.openhands.dev/sdk/guides/agent-server/cloud-workspace.md): Connect to OpenHands Cloud for fully managed sandbox environments with optional SaaS credential inheritance.\n- [Overview](https://docs.openhands.dev/sdk/guides/agent-server/overview.md): Run agents on remote servers with isolated workspaces for production deployments.\n- [Parallel Tool Execution](https://docs.openhands.dev/sdk/guides/parallel-tool-execution.md): Execute multiple tools concurrently within a single LLM response to improve throughput for independent operations.\n- [Pause and Resume](https://docs.openhands.dev/sdk/guides/convo-pause-and-resume.md): Pause agent execution, perform operations, and resume without losing state.\n- [Persistence](https://docs.openhands.dev/sdk/guides/convo-persistence.md): Save and restore conversation state for multi-session workflows.\n- [Plugins](https://docs.openhands.dev/sdk/guides/plugins.md): Plugins bundle skills, hooks, MCP servers, agents, and commands into reusable packages that extend agent capabilities.\n- [PR Review](https://docs.openhands.dev/sdk/guides/github-workflows/pr-review.md): Use OpenHands Agent to generate meaningful pull request review\n- [Reasoning](https://docs.openhands.dev/sdk/guides/llm-reasoning.md): Access model reasoning traces from Anthropic extended thinking and OpenAI responses API.\n- [Secret Registry](https://docs.openhands.dev/sdk/guides/secrets.md): Provide environment variables and secrets to agent workspace securely.\n- [Security & Action Confirmation](https://docs.openhands.dev/sdk/guides/security.md): Control agent action execution through confirmation policy and security analyzer.\n- [Send Message While Running](https://docs.openhands.dev/sdk/guides/convo-send-message-while-running.md): Interrupt running agents to provide additional context or corrections.\n- [Software Agent SDK](https://docs.openhands.dev/sdk.md): Build AI agents that write software. A clean, modular SDK with production-ready tools.\n- [Stuck Detector](https://docs.openhands.dev/sdk/guides/agent-stuck-detector.md): Detect and handle stuck agents automatically with timeout mechanisms.\n- [Task Tool Set](https://docs.openhands.dev/sdk/guides/task-tool-set.md): Delegate complex work to specialized sub-agents that run synchronously and return results to the parent agent.\n- [Theory of Mind (TOM) Agent](https://docs.openhands.dev/sdk/guides/agent-tom-agent.md): Enable your agent to understand user intent and preferences through Theory of Mind capabilities, providing personalized guidance based on user modeling.\n- [TODO Management](https://docs.openhands.dev/sdk/guides/github-workflows/todo-management.md): Implement TODOs using OpenHands Agent\n\n## Examples\n\nSource: [`examples/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples)\n\n### [`01_standalone_sdk/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk)\n\n- [`01_hello_world.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/01_hello_world.py)\n- [`02_custom_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/02_custom_tools.py)\n- [`03_activate_skill.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/03_activate_skill.py)\n- [`04_confirmation_mode_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/04_confirmation_mode_example.py)\n- [`05_use_llm_registry.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/05_use_llm_registry.py)\n- [`06_interactive_terminal_w_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/06_interactive_terminal_w_reasoning.py)\n- [`07_mcp_integration.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/07_mcp_integration.py)\n- [`08_mcp_with_oauth.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/08_mcp_with_oauth.py)\n- [`09_pause_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/09_pause_example.py)\n- [`10_persistence.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/10_persistence.py)\n- [`11_async.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/11_async.py)\n- [`12_custom_secrets.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/12_custom_secrets.py)\n- [`13_get_llm_metrics.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/13_get_llm_metrics.py)\n- [`14_context_condenser.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/14_context_condenser.py)\n- [`15_browser_use.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/15_browser_use.py)\n- [`16_llm_security_analyzer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/16_llm_security_analyzer.py)\n- [`17_image_input.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/17_image_input.py)\n- [`18_send_message_while_processing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/18_send_message_while_processing.py)\n- [`19_llm_routing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/19_llm_routing.py)\n- [`20_stuck_detector.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/20_stuck_detector.py)\n- [`21_generate_extraneous_conversation_costs.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/21_generate_extraneous_conversation_costs.py)\n- [`22_anthropic_thinking.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/22_anthropic_thinking.py)\n- [`23_responses_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/23_responses_reasoning.py)\n- [`24_planning_agent_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/24_planning_agent_workflow.py)\n- [`25_agent_delegation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/25_agent_delegation.py)\n- [`26_custom_visualizer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/26_custom_visualizer.py)\n- [`27_observability_laminar.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/27_observability_laminar.py)\n- [`28_ask_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/28_ask_agent_example.py)\n- [`29_llm_streaming.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/29_llm_streaming.py)\n- [`30_tom_agent.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/30_tom_agent.py)\n- [`31_iterative_refinement.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/31_iterative_refinement.py)\n- [`32_configurable_security_policy.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/32_configurable_security_policy.py)\n- [`33_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/33_hooks)\n- [`34_critic_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/34_critic_example.py)\n- [`35_subscription_login.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/35_subscription_login.py)\n- [`36_event_json_to_openai_messages.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/36_event_json_to_openai_messages.py)\n- [`37_llm_profile_store`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/37_llm_profile_store)\n- [`38_browser_session_recording.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/38_browser_session_recording.py)\n- [`39_llm_fallback.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/39_llm_fallback.py)\n- [`40_acp_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/40_acp_agent_example.py)\n- [`41_task_tool_set.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/41_task_tool_set.py)\n- [`42_file_based_subagents.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/42_file_based_subagents.py)\n- [`44_model_switching_in_convo.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/44_model_switching_in_convo.py)\n- [`45_parallel_tool_execution.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/45_parallel_tool_execution.py)\n- [`46_agent_settings.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/46_agent_settings.py)\n- [`47_defense_in_depth_security.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/47_defense_in_depth_security.py)\n- [`48_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/48_conversation_fork.py)\n- [`49_switch_llm_tool.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/49_switch_llm_tool.py)\n- [`50_async_cancellation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/50_async_cancellation.py)\n- [`51_agent_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/51_agent_hooks)\n- [`52_dynamic_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/52_dynamic_workflow.py)\n- [`53_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/53_client_defined_tools.py)\n- [`54_goal_completion_loop.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/54_goal_completion_loop.py)\n\n### [`02_remote_agent_server/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server)\n\n- [`01_convo_with_local_agent_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/01_convo_with_local_agent_server.py)\n- [`02_convo_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/02_convo_with_docker_sandboxed_server.py)\n- [`03_browser_use_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/03_browser_use_with_docker_sandboxed_server.py)\n- [`04_convo_with_api_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/04_convo_with_api_sandboxed_server.py)\n- [`05_vscode_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/05_vscode_with_docker_sandboxed_server.py)\n- [`06_custom_tool`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/06_custom_tool)\n- [`07_convo_with_cloud_workspace.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/07_convo_with_cloud_workspace.py)\n- [`08_convo_with_apptainer_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/08_convo_with_apptainer_sandboxed_server.py)\n- [`09_acp_agent_with_remote_runtime.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/09_acp_agent_with_remote_runtime.py)\n- [`10_cloud_workspace_share_credentials.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/10_cloud_workspace_share_credentials.py)\n- [`11_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/11_conversation_fork.py)\n- [`12_settings_and_secrets_api.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/12_settings_and_secrets_api.py)\n- [`13_workspace_get_llm.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/13_workspace_get_llm.py)\n- [`14_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/14_client_defined_tools.py)\n- [`15_openai_compatible_gateway.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/15_openai_compatible_gateway.py)\n- [`16_deferred_init.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/16_deferred_init.py)\n- [`hook_scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/hook_scripts)\n- [`scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/scripts)\n\n### [`03_github_workflows/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows)\n\n- [`01_basic_action`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/01_basic_action)\n- [`02_pr_review`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/02_pr_review)\n- [`03_todo_management`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/03_todo_management)\n- [`04_datadog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/04_datadog_debugging)\n- [`05_posthog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/05_posthog_debugging)\n\n### [`04_llm_specific_tools/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/04_llm_specific_tools)\n\n- [`01_gpt5_apply_patch_preset.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/01_gpt5_apply_patch_preset.py)\n- [`02_gemini_file_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/02_gemini_file_tools.py)\n\n### [`05_skills_and_plugins/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins)\n\n- [`01_loading_agentskills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/01_loading_agentskills)\n- [`02_loading_plugins`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/02_loading_plugins)\n- [`03_managing_installed_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/03_managing_installed_skills)\n- [`04_mixed_marketplace_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/04_mixed_marketplace_skills)"
|
|
359
|
+
"content": "# OpenHands Software Agent SDK\n\nAll SDK documentation lives at <https://docs.openhands.dev/sdk>.\n\nFor the full topic index, fetch <https://docs.openhands.dev/llms.txt> and read\nthe \"OpenHands Software Agent SDK\" section.\n\n## Quick reference\n\nInstall: `pip install openhands-sdk openhands-tools`\n\n```python\nimport os\n\nfrom openhands.sdk import LLM, Agent, Conversation, Tool\nfrom openhands.tools.file_editor import FileEditorTool\nfrom openhands.tools.task_tracker import TaskTrackerTool\nfrom openhands.tools.terminal import TerminalTool\n\n\nllm = LLM(\n model=os.getenv(\"LLM_MODEL\", \"gpt-5.5\"),\n api_key=os.getenv(\"LLM_API_KEY\"),\n base_url=os.getenv(\"LLM_BASE_URL\", None),\n)\n\nagent = Agent(\n llm=llm,\n tools=[\n Tool(name=TerminalTool.name),\n Tool(name=FileEditorTool.name),\n Tool(name=TaskTrackerTool.name),\n ],\n)\n\ncwd = os.getcwd()\nconversation = Conversation(agent=agent, workspace=cwd)\n\nconversation.send_message(\"Write 3 facts about the current project into FACTS.txt.\")\nconversation.run()\nprint(\"All done!\")\n```\n\n## Core classes (`openhands.sdk`)\n\n| Class | Purpose |\n|---|---|\n| [`Agent`](https://docs.openhands.dev/sdk/arch/agent.md) | Reasoning-action loop |\n| [`Condenser`](https://docs.openhands.dev/sdk/arch/condenser.md) | Conversation history compression system |\n| [`Conversation`](https://docs.openhands.dev/sdk/arch/conversation.md) | Conversation orchestration system |\n| [`Event`](https://docs.openhands.dev/sdk/arch/events.md) | Typed event framework |\n| [`LLM`](https://docs.openhands.dev/sdk/arch/llm.md) | Provider-agnostic language model interface |\n| [`SecurityAnalyzer`](https://docs.openhands.dev/sdk/arch/security.md) | Action security analysis and validation |\n| [`Skill`](https://docs.openhands.dev/sdk/arch/skill.md) | Reusable prompt system |\n| [`Tool / ToolDefinition`](https://docs.openhands.dev/sdk/arch/tool-system.md) | Action-observation tool framework |\n| [`Workspace`](https://docs.openhands.dev/sdk/arch/workspace.md) | Execution environment abstraction |\n\n## API reference\n\n[`openhands.sdk.agent`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.agent.md), [`openhands.sdk.conversation`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.conversation.md), [`openhands.sdk.event`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.event.md), [`openhands.sdk.llm`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.llm.md), [`openhands.sdk.security`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.security.md), [`openhands.sdk.tool`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.tool.md), [`openhands.sdk.utils`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.utils.md), [`openhands.sdk.workspace`](https://docs.openhands.dev/sdk/api-reference/openhands.sdk.workspace.md)\n\n## Guides\n\n- [ACP Agent](https://docs.openhands.dev/sdk/guides/agent-acp.md): Delegate to an ACP-compatible server (Claude Code, Gemini CLI, etc.) instead of calling an LLM directly.\n- [Agent Settings](https://docs.openhands.dev/sdk/guides/agent-settings.md): Configure, serialize, and recreate agents from structured settings.\n- [Agent Skills & Context](https://docs.openhands.dev/sdk/guides/skill.md): Skills add specialized behaviors, domain knowledge, and context-aware triggers to your agent through structured prompts.\n- [API-based Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/api-sandbox.md): Connect to hosted API-based agent server for fully managed infrastructure.\n- [Apptainer Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/apptainer-sandbox.md): Run agent server in rootless Apptainer containers for HPC and shared computing environments.\n- [Ask Agent Questions](https://docs.openhands.dev/sdk/guides/convo-ask-agent.md): Get sidebar replies from the agent during conversation execution without interrupting the main flow.\n- [Assign Reviews](https://docs.openhands.dev/sdk/guides/github-workflows/assign-reviews.md): Automate PR management with intelligent reviewer assignment and workflow notifications using OpenHands Agent\n- [Browser Session Recording](https://docs.openhands.dev/sdk/guides/browser-session-recording.md): Record and replay your agent's browser sessions using rrweb.\n- [Browser Use](https://docs.openhands.dev/sdk/guides/agent-browser-use.md): Enable web browsing and interaction capabilities for your agent.\n- [Context Condenser](https://docs.openhands.dev/sdk/guides/context-condenser.md): Manage agent memory by condensing conversation history to save tokens.\n- [Conversation Goals](https://docs.openhands.dev/sdk/guides/agent-server/conversation-goals.md): Add a resumable goal strategy to a normal agent-server conversation.\n- [Conversation with Async](https://docs.openhands.dev/sdk/guides/convo-async.md): Use async/await for concurrent agent operations and non-blocking execution.\n- [Creating Custom Agent](https://docs.openhands.dev/sdk/guides/agent-custom.md): Learn how to design specialized agents with custom tool sets\n- [Critic (Experimental)](https://docs.openhands.dev/sdk/guides/critic.md): Real-time evaluation of agent actions using an LLM-based critic model, with built-in iterative refinement.\n- [Custom Tools](https://docs.openhands.dev/sdk/guides/custom-tools.md): Tools define what agents can do. The SDK includes built-in tools for common operations and supports creating custom tools for specialized needs.\n- [Custom Tools with Remote Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/custom-tools.md): Learn how to use custom tools with a remote agent server by building a custom base image that includes your tool implementations.\n- [Custom Visualizer](https://docs.openhands.dev/sdk/guides/convo-custom-visualizer.md): Customize conversation visualization by creating custom visualizers or configuring the default visualizer.\n- [Deferred Init (Warm-Pool)](https://docs.openhands.dev/sdk/guides/agent-server/deferred-init.md): Pre-warm agent-server pods before a user is matched, then activate them at runtime with POST /api/init.\n- [Docker Sandbox](https://docs.openhands.dev/sdk/guides/agent-server/docker-sandbox.md): Run agent server in isolated Docker containers for security and reproducibility.\n- [Exception Handling](https://docs.openhands.dev/sdk/guides/llm-error-handling.md): Provider‑agnostic exceptions raised by the SDK and recommended patterns for handling them.\n- [FAQ](https://docs.openhands.dev/sdk/faq.md): Frequently asked questions about the OpenHands SDK\n- [File-Based Agents](https://docs.openhands.dev/sdk/guides/agent-file-based.md): Define specialized sub-agents as simple Markdown files with YAML frontmatter — no Python code required.\n- [Fork a Conversation](https://docs.openhands.dev/sdk/guides/convo-fork.md): Branch off an existing conversation for follow-up exploration without contaminating the original.\n- [Getting Started](https://docs.openhands.dev/sdk/getting-started.md): Install the OpenHands SDK and build AI agents that write software.\n- [Goal Completion Loop](https://docs.openhands.dev/sdk/guides/convo-goal.md): Drive a conversation toward a verifiable objective with a judge-driven, self-continuing completion loop.\n- [GPT-5 Preset (ApplyPatchTool)](https://docs.openhands.dev/sdk/guides/llm-gpt5-preset.md): Use the GPT-5 preset to build an agent that swaps the standard FileEditorTool for ApplyPatchTool.\n- [Hello World](https://docs.openhands.dev/sdk/guides/hello-world.md): The simplest possible OpenHands agent - configure an LLM, create an agent, and complete a task.\n- [Hooks](https://docs.openhands.dev/sdk/guides/hooks.md): Use lifecycle hooks to observe, log, and customize agent execution.\n- [Image Input](https://docs.openhands.dev/sdk/guides/llm-image-input.md): Send images to multimodal agents for vision-based tasks and analysis.\n- [Interactive Terminal](https://docs.openhands.dev/sdk/guides/agent-interactive-terminal.md): Enable agents to interact with terminal applications like ipython, python REPL, and other interactive CLI tools.\n- [Iterative Refinement](https://docs.openhands.dev/sdk/guides/iterative-refinement.md): Implement iterative refinement workflows where agents refine their work based on critique feedback until quality thresholds are met.\n- [LLM Fallback Strategy](https://docs.openhands.dev/sdk/guides/llm-fallback.md): Automatically try alternate LLMs when the primary model fails with a transient error.\n- [LLM Profile Store](https://docs.openhands.dev/sdk/guides/llm-profile-store.md): Save, load, and manage reusable LLM configurations so you never repeat setup code again.\n- [LLM Registry](https://docs.openhands.dev/sdk/guides/llm-registry.md): Dynamically select and configure language models using the LLM registry.\n- [LLM Streaming](https://docs.openhands.dev/sdk/guides/llm-streaming.md): Stream LLM responses token-by-token for real-time display and interactive user experiences.\n- [LLM Subscriptions](https://docs.openhands.dev/sdk/guides/llm-subscriptions.md): Use your ChatGPT Plus/Pro subscription to access Codex models without consuming API credits.\n- [Local Agent Server](https://docs.openhands.dev/sdk/guides/agent-server/local-server.md): Install and run an OpenHands Agent Server on your machine, then connect to it from the SDK.\n- [Metrics Tracking](https://docs.openhands.dev/sdk/guides/metrics.md): Track token usage, costs, and latency metrics for your agents.\n- [Model Context Protocol](https://docs.openhands.dev/sdk/guides/mcp.md): Model Context Protocol (MCP) enables dynamic tool integration from external servers. Agents can discover and use MCP-provided tools automatically.\n- [Model Routing](https://docs.openhands.dev/sdk/guides/llm-routing.md): Route agent's LLM requests to different models.\n- [Observability & Tracing](https://docs.openhands.dev/sdk/guides/observability.md): Enable OpenTelemetry tracing to monitor and debug your agent's execution with tools like Laminar, MLflow, Honeycomb, or any OTLP-compatible backend.\n- [OpenAI-Compatible Endpoint](https://docs.openhands.dev/sdk/guides/agent-server/openai-gateway.md): Call an OpenHands agent-server through the OpenAI Chat Completions protocol.\n- [OpenHands Cloud Workspace](https://docs.openhands.dev/sdk/guides/agent-server/cloud-workspace.md): Connect to OpenHands Cloud for fully managed sandbox environments with optional SaaS credential inheritance.\n- [Overview](https://docs.openhands.dev/sdk/guides/agent-server/overview.md): Run agents on remote servers with isolated workspaces for production deployments.\n- [Parallel Tool Execution](https://docs.openhands.dev/sdk/guides/parallel-tool-execution.md): Execute multiple tools concurrently within a single LLM response to improve throughput for independent operations.\n- [Pause and Resume](https://docs.openhands.dev/sdk/guides/convo-pause-and-resume.md): Pause agent execution, perform operations, and resume without losing state.\n- [Persistence](https://docs.openhands.dev/sdk/guides/convo-persistence.md): Save and restore conversation state for multi-session workflows.\n- [Persistent Memory](https://docs.openhands.dev/sdk/guides/persistent-memory.md): Give agents opt-in, two-tier memory that survives across conversations.\n- [Plugins](https://docs.openhands.dev/sdk/guides/plugins.md): Plugins bundle skills, hooks, MCP servers, agents, and commands into reusable packages that extend agent capabilities.\n- [PR Review](https://docs.openhands.dev/sdk/guides/github-workflows/pr-review.md): Use OpenHands Agent to generate meaningful pull request review\n- [Reasoning](https://docs.openhands.dev/sdk/guides/llm-reasoning.md): Access model reasoning traces from Anthropic extended thinking and OpenAI responses API.\n- [Secret Registry](https://docs.openhands.dev/sdk/guides/secrets.md): Provide environment variables and secrets to agent workspace securely.\n- [Security & Action Confirmation](https://docs.openhands.dev/sdk/guides/security.md): Control agent action execution through confirmation policy and security analyzer.\n- [Send Message While Running](https://docs.openhands.dev/sdk/guides/convo-send-message-while-running.md): Interrupt running agents to provide additional context or corrections.\n- [Software Agent SDK](https://docs.openhands.dev/sdk.md): Build AI agents that write software. A clean, modular SDK with production-ready tools.\n- [Stuck Detector](https://docs.openhands.dev/sdk/guides/agent-stuck-detector.md): Detect and handle stuck agents automatically with timeout mechanisms.\n- [Task Tool Set](https://docs.openhands.dev/sdk/guides/task-tool-set.md): Delegate complex work to specialized sub-agents that run synchronously and return results to the parent agent.\n- [Theory of Mind (TOM) Agent](https://docs.openhands.dev/sdk/guides/agent-tom-agent.md): Enable your agent to understand user intent and preferences through Theory of Mind capabilities, providing personalized guidance based on user modeling.\n- [TODO Management](https://docs.openhands.dev/sdk/guides/github-workflows/todo-management.md): Implement TODOs using OpenHands Agent\n\n## Examples\n\nSource: [`examples/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples)\n\n### [`01_standalone_sdk/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk)\n\n- [`01_hello_world.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/01_hello_world.py)\n- [`02_custom_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/02_custom_tools.py)\n- [`03_activate_skill.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/03_activate_skill.py)\n- [`04_confirmation_mode_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/04_confirmation_mode_example.py)\n- [`05_use_llm_registry.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/05_use_llm_registry.py)\n- [`06_interactive_terminal_w_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/06_interactive_terminal_w_reasoning.py)\n- [`07_mcp_integration.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/07_mcp_integration.py)\n- [`08_mcp_with_oauth.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/08_mcp_with_oauth.py)\n- [`09_pause_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/09_pause_example.py)\n- [`10_persistence.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/10_persistence.py)\n- [`11_async.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/11_async.py)\n- [`12_custom_secrets.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/12_custom_secrets.py)\n- [`13_get_llm_metrics.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/13_get_llm_metrics.py)\n- [`14_context_condenser.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/14_context_condenser.py)\n- [`15_browser_use.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/15_browser_use.py)\n- [`16_llm_security_analyzer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/16_llm_security_analyzer.py)\n- [`17_image_input.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/17_image_input.py)\n- [`18_send_message_while_processing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/18_send_message_while_processing.py)\n- [`19_llm_routing.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/19_llm_routing.py)\n- [`20_stuck_detector.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/20_stuck_detector.py)\n- [`21_generate_extraneous_conversation_costs.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/21_generate_extraneous_conversation_costs.py)\n- [`22_anthropic_thinking.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/22_anthropic_thinking.py)\n- [`23_responses_reasoning.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/23_responses_reasoning.py)\n- [`24_planning_agent_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/24_planning_agent_workflow.py)\n- [`25_agent_delegation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/25_agent_delegation.py)\n- [`26_custom_visualizer.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/26_custom_visualizer.py)\n- [`27_observability_laminar.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/27_observability_laminar.py)\n- [`28_ask_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/28_ask_agent_example.py)\n- [`29_llm_streaming.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/29_llm_streaming.py)\n- [`30_tom_agent.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/30_tom_agent.py)\n- [`31_iterative_refinement.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/31_iterative_refinement.py)\n- [`32_configurable_security_policy.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/32_configurable_security_policy.py)\n- [`33_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/33_hooks)\n- [`34_critic_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/34_critic_example.py)\n- [`35_subscription_login.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/35_subscription_login.py)\n- [`36_event_json_to_openai_messages.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/36_event_json_to_openai_messages.py)\n- [`37_llm_profile_store`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/37_llm_profile_store)\n- [`38_browser_session_recording.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/38_browser_session_recording.py)\n- [`39_llm_fallback.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/39_llm_fallback.py)\n- [`40_acp_agent_example.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/40_acp_agent_example.py)\n- [`41_task_tool_set.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/41_task_tool_set.py)\n- [`42_file_based_subagents.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/42_file_based_subagents.py)\n- [`44_model_switching_in_convo.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/44_model_switching_in_convo.py)\n- [`45_parallel_tool_execution.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/45_parallel_tool_execution.py)\n- [`46_agent_settings.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/46_agent_settings.py)\n- [`47_defense_in_depth_security.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/47_defense_in_depth_security.py)\n- [`48_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/48_conversation_fork.py)\n- [`49_switch_llm_tool.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/49_switch_llm_tool.py)\n- [`50_async_cancellation.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/50_async_cancellation.py)\n- [`51_agent_hooks`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/01_standalone_sdk/51_agent_hooks)\n- [`52_dynamic_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/52_dynamic_workflow.py)\n- [`53_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/53_client_defined_tools.py)\n- [`54_goal_completion_loop.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/54_goal_completion_loop.py)\n- [`55_persistent_memory.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/55_persistent_memory.py)\n\n### [`02_remote_agent_server/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server)\n\n- [`01_convo_with_local_agent_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/01_convo_with_local_agent_server.py)\n- [`02_convo_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/02_convo_with_docker_sandboxed_server.py)\n- [`03_browser_use_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/03_browser_use_with_docker_sandboxed_server.py)\n- [`04_convo_with_api_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/04_convo_with_api_sandboxed_server.py)\n- [`05_vscode_with_docker_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/05_vscode_with_docker_sandboxed_server.py)\n- [`06_custom_tool`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/06_custom_tool)\n- [`07_convo_with_cloud_workspace.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/07_convo_with_cloud_workspace.py)\n- [`08_convo_with_apptainer_sandboxed_server.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/08_convo_with_apptainer_sandboxed_server.py)\n- [`09_acp_agent_with_remote_runtime.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/09_acp_agent_with_remote_runtime.py)\n- [`10_cloud_workspace_share_credentials.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/10_cloud_workspace_share_credentials.py)\n- [`11_conversation_fork.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/11_conversation_fork.py)\n- [`12_settings_and_secrets_api.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/12_settings_and_secrets_api.py)\n- [`13_workspace_get_llm.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/13_workspace_get_llm.py)\n- [`14_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/14_client_defined_tools.py)\n- [`15_openai_compatible_gateway.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/15_openai_compatible_gateway.py)\n- [`16_deferred_init.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/02_remote_agent_server/16_deferred_init.py)\n- [`hook_scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/hook_scripts)\n- [`scripts`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server/scripts)\n\n### [`03_github_workflows/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows)\n\n- [`01_basic_action`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/01_basic_action)\n- [`02_pr_review`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/02_pr_review)\n- [`03_todo_management`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/03_todo_management)\n- [`04_datadog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/04_datadog_debugging)\n- [`05_posthog_debugging`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/05_posthog_debugging)\n\n### [`04_llm_specific_tools/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/04_llm_specific_tools)\n\n- [`01_gpt5_apply_patch_preset.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/01_gpt5_apply_patch_preset.py)\n- [`02_gemini_file_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/04_llm_specific_tools/02_gemini_file_tools.py)\n\n### [`05_skills_and_plugins/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins)\n\n- [`01_loading_agentskills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/01_loading_agentskills)\n- [`02_loading_plugins`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/02_loading_plugins)\n- [`03_managing_installed_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/03_managing_installed_skills)\n- [`04_mixed_marketplace_skills`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/05_skills_and_plugins/04_mixed_marketplace_skills)"
|
|
363
360
|
},
|
|
364
361
|
{
|
|
365
362
|
"name": "pdflatex",
|
|
@@ -123,6 +123,7 @@ print("All done!")
|
|
|
123
123
|
- [Parallel Tool Execution](https://docs.openhands.dev/sdk/guides/parallel-tool-execution.md): Execute multiple tools concurrently within a single LLM response to improve throughput for independent operations.
|
|
124
124
|
- [Pause and Resume](https://docs.openhands.dev/sdk/guides/convo-pause-and-resume.md): Pause agent execution, perform operations, and resume without losing state.
|
|
125
125
|
- [Persistence](https://docs.openhands.dev/sdk/guides/convo-persistence.md): Save and restore conversation state for multi-session workflows.
|
|
126
|
+
- [Persistent Memory](https://docs.openhands.dev/sdk/guides/persistent-memory.md): Give agents opt-in, two-tier memory that survives across conversations.
|
|
126
127
|
- [Plugins](https://docs.openhands.dev/sdk/guides/plugins.md): Plugins bundle skills, hooks, MCP servers, agents, and commands into reusable packages that extend agent capabilities.
|
|
127
128
|
- [PR Review](https://docs.openhands.dev/sdk/guides/github-workflows/pr-review.md): Use OpenHands Agent to generate meaningful pull request review
|
|
128
129
|
- [Reasoning](https://docs.openhands.dev/sdk/guides/llm-reasoning.md): Access model reasoning traces from Anthropic extended thinking and OpenAI responses API.
|
|
@@ -194,6 +195,7 @@ Source: [`examples/`](https://github.com/OpenHands/software-agent-sdk/tree/main/
|
|
|
194
195
|
- [`52_dynamic_workflow.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/52_dynamic_workflow.py)
|
|
195
196
|
- [`53_client_defined_tools.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/53_client_defined_tools.py)
|
|
196
197
|
- [`54_goal_completion_loop.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/54_goal_completion_loop.py)
|
|
198
|
+
- [`55_persistent_memory.py`](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/55_persistent_memory.py)
|
|
197
199
|
|
|
198
200
|
### [`02_remote_agent_server/`](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/02_remote_agent_server)
|
|
199
201
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Reference responses for the capabilities endpoint the host queries at stage 2. The endpoint does not exist yet - defining it is OpenHands/automation#262. Field names here are the contract that setup.requires.features, the trigger kinds in setup.form.triggers, and the cron and timezone field types are written against.",
|
|
3
|
+
"endpoint": {
|
|
4
|
+
"method": "GET",
|
|
5
|
+
"path": "/v1/capabilities"
|
|
6
|
+
},
|
|
7
|
+
"responses": {
|
|
8
|
+
"supported": {
|
|
9
|
+
"description": "A deployment that is publicly reachable and can run every archetype.",
|
|
10
|
+
"status": 200,
|
|
11
|
+
"body": {
|
|
12
|
+
"ready": true,
|
|
13
|
+
"triggerKinds": ["cron", "event"],
|
|
14
|
+
"eventSources": ["github"],
|
|
15
|
+
"eventTypes": [
|
|
16
|
+
"issue_comment.created",
|
|
17
|
+
"pull_request.opened",
|
|
18
|
+
"pull_request.labeled",
|
|
19
|
+
"pull_request_review_comment.created",
|
|
20
|
+
"push"
|
|
21
|
+
],
|
|
22
|
+
"triggers": {
|
|
23
|
+
"cron": {
|
|
24
|
+
"minIntervalSeconds": 300,
|
|
25
|
+
"timezones": [
|
|
26
|
+
"UTC",
|
|
27
|
+
"America/Los_Angeles",
|
|
28
|
+
"America/New_York",
|
|
29
|
+
"Asia/Tokyo",
|
|
30
|
+
"Europe/London"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"event": {
|
|
34
|
+
"filterLanguage": "jmespath",
|
|
35
|
+
"filterFunctions": [
|
|
36
|
+
"contains",
|
|
37
|
+
"ends_with",
|
|
38
|
+
"glob",
|
|
39
|
+
"icontains",
|
|
40
|
+
"lower",
|
|
41
|
+
"regex",
|
|
42
|
+
"starts_with",
|
|
43
|
+
"upper"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"features": [
|
|
48
|
+
"conversationDispatch",
|
|
49
|
+
"mcpTools",
|
|
50
|
+
"presetPlugin",
|
|
51
|
+
"presetPrompt",
|
|
52
|
+
"repoClone",
|
|
53
|
+
"webhookDelivery"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"cronOnly": {
|
|
58
|
+
"description": "A deployment that is not reachable from the public internet, so external services cannot deliver webhooks to it. Scheduled polling is the documented alternative - see skills/openhands-automation/SKILL.md.",
|
|
59
|
+
"status": 200,
|
|
60
|
+
"body": {
|
|
61
|
+
"ready": true,
|
|
62
|
+
"triggerKinds": ["cron"],
|
|
63
|
+
"eventSources": [],
|
|
64
|
+
"eventTypes": [],
|
|
65
|
+
"triggers": {
|
|
66
|
+
"cron": {
|
|
67
|
+
"minIntervalSeconds": 300,
|
|
68
|
+
"timezones": ["UTC"]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"features": [
|
|
72
|
+
"conversationDispatch",
|
|
73
|
+
"mcpTools",
|
|
74
|
+
"presetPrompt",
|
|
75
|
+
"repoClone"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"notReady": {
|
|
80
|
+
"description": "The automation service is reachable but not accepting work. It offers no features and no trigger kinds, so every setup block is blocked.",
|
|
81
|
+
"status": 200,
|
|
82
|
+
"body": {
|
|
83
|
+
"ready": false,
|
|
84
|
+
"triggerKinds": [],
|
|
85
|
+
"eventSources": [],
|
|
86
|
+
"eventTypes": [],
|
|
87
|
+
"triggers": {},
|
|
88
|
+
"features": []
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|