Skip to content

Commit b2c742b

Browse files
docs: sync documentation from agent-sdk
- Synced code blocks from examples - Generated API reference documentation Synced from agent-sdk ref: main
1 parent 7a72883 commit b2c742b

9 files changed

Lines changed: 111 additions & 68 deletions

File tree

‎docs.json‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@
140140
},
141141
{
142142
"group": "Tips and Tricks",
143-
"pages": ["openhands/usage/tips/prompting-best-practices"]
143+
"pages": [
144+
"openhands/usage/tips/prompting-best-practices"
145+
]
144146
},
145147
{
146148
"group": "Troubleshooting & Feedback",
@@ -280,7 +282,9 @@
280282
},
281283
{
282284
"tab": "Success Stories",
283-
"pages": ["success-stories/index"]
285+
"pages": [
286+
"success-stories/index"
287+
]
284288
}
285289
],
286290
"global": {
@@ -321,7 +325,7 @@
321325
}
322326
},
323327
"banner": {
324-
"content": "📢 **GitHub Org Rename:** All-Hands-AI to OpenHands on Monday Oct 20th at 18:00 UTC. [Migration details →](https://github.com/OpenHands/OpenHands/issues/11376)",
328+
"content": "\ud83d\udce2 **GitHub Org Rename:** All-Hands-AI to OpenHands on Monday Oct 20th at 18:00 UTC. [Migration details \u2192](https://github.com/OpenHands/OpenHands/issues/11376)",
325329
"dismissible": true
326330
},
327331
"head": [
@@ -333,7 +337,12 @@
333337
}
334338
],
335339
"contextual": {
336-
"options": ["copy", "view", "chatgpt", "claude"]
340+
"options": [
341+
"copy",
342+
"view",
343+
"chatgpt",
344+
"claude"
345+
]
337346
},
338347
"redirects": [
339348
{

‎sdk/api-reference/openhands.sdk.conversation.mdx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ exchange, execution control, and state management.
2929

3030
#### Methods
3131

32+
#### __init__()
33+
34+
Initialize the base conversation with span tracking.
35+
3236
#### abstractmethod close()
3337

3438
#### static compose_callbacks()

‎sdk/api-reference/openhands.sdk.llm.mdx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ retry logic, and tool calling capabilities.
5151
#### Properties
5252

5353
- `OVERRIDE_ON_SERIALIZE`: tuple[str, ...]
54-
- `api_key`: SecretStr | None
54+
- `api_key`: str | SecretStr | None
5555
- `api_version`: str | None
56-
- `aws_access_key_id`: SecretStr | None
56+
- `aws_access_key_id`: str | SecretStr | None
5757
- `aws_region_name`: str | None
58-
- `aws_secret_access_key`: SecretStr | None
58+
- `aws_secret_access_key`: str | SecretStr | None
5959
- `base_url`: str | None
6060
- `caching_prompt`: bool
6161
- `custom_llm_provider`: str | None
@@ -90,6 +90,7 @@ retry logic, and tool calling capabilities.
9090
- `openrouter_site_url`: str
9191
- `output_cost_per_token`: float | None
9292
- `reasoning_effort`: Literal['low', 'medium', 'high', 'none'] | None
93+
- `reasoning_summary`: Literal['auto', 'concise', 'detailed'] | None
9394
- `retry_listener`: SkipJsonSchema[Callable[[int, int], None] | None]
9495
- `retry_max_wait`: int
9596
- `retry_min_wait`: int

‎sdk/api-reference/openhands.sdk.tool.mdx‎

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,37 @@ Base schema for output observation.
7676

7777
#### Properties
7878

79+
- `ERROR_MESSAGE_HEADER`: ClassVar[str] = '[An error occurred during execution.]n'
80+
- `content`: list[TextContent | ImageContent]
81+
- `is_error`: bool
7982
- `kind`: str
8083
- `model_config`: ClassVar[ConfigDict] = (configuration object)
8184
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
85+
- `text`: str
86+
Extract all text content from the observation.
87+
* Returns:
88+
Concatenated text from all TextContent items in content.
8289
- `to_llm_content`: Sequence[TextContent | ImageContent]
83-
Get the observation string to show to the agent.
90+
Default content formatting for converting observation to LLM readable content.
91+
Subclasses can override to provide richer content (e.g., images, diffs).
8492
- `visualize`: Text
85-
Return Rich Text representation of this action.
86-
This method can be overridden by subclasses to customize visualization.
87-
The base implementation displays all action fields systematically.
93+
Return Rich Text representation of this observation.
94+
Subclasses can override for custom visualization; by default we show the
95+
same text that would be sent to the LLM.
96+
97+
#### Methods
98+
99+
#### classmethod from_text()
100+
101+
Utility to create an Observation from a simple text string.
102+
103+
* Parameters:
104+
* `text` – The text content to include in the observation.
105+
* `is_error` – Whether this observation represents an error.
106+
kwargs* – Additional fields for the observation subclass.
107+
* Returns:
108+
An Observation instance with the text wrapped in a TextContent.
109+
88110
### class ThinkTool
89111

90112
Bases: `ToolDefinition[ThinkAction, ThinkObservation]`

‎sdk/getting-started.mdx‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,37 +74,32 @@ Here's a complete example that creates an agent and asks it to perform a simple
7474
```python icon="python" expandable examples/01_standalone_sdk/01_hello_world.py
7575
import os
7676

77-
from pydantic import SecretStr
77+
from openhands.sdk import LLM, Agent, Conversation, Tool
78+
from openhands.tools.execute_bash import BashTool
79+
from openhands.tools.file_editor import FileEditorTool
80+
from openhands.tools.task_tracker import TaskTrackerTool
7881

79-
from openhands.sdk import LLM, Conversation
80-
from openhands.tools.preset.default import get_default_agent
8182

82-
83-
# Configure LLM and agent
84-
# You can get an API key from https://app.all-hands.dev/settings/api-keys
85-
api_key = os.getenv("LLM_API_KEY")
86-
assert api_key is not None, "LLM_API_KEY environment variable is not set."
87-
model = os.getenv("LLM_MODEL", "openhands/claude-sonnet-4-5-20250929")
88-
base_url = os.getenv("LLM_BASE_URL")
8983
llm = LLM(
90-
model=model,
91-
api_key=SecretStr(api_key),
92-
base_url=base_url,
93-
usage_id="agent",
84+
model="anthropic/claude-sonnet-4-5-20250929",
85+
api_key=os.getenv("LLM_API_KEY"),
86+
)
87+
88+
agent = Agent(
89+
llm=llm,
90+
tools=[
91+
Tool(name=BashTool.name),
92+
Tool(name=FileEditorTool.name),
93+
Tool(name=TaskTrackerTool.name),
94+
],
9495
)
95-
agent = get_default_agent(llm=llm, cli_mode=True)
9696

97-
# Start a conversation and send some messages
9897
cwd = os.getcwd()
9998
conversation = Conversation(agent=agent, workspace=cwd)
10099

101-
# Send a message and let the agent run
102100
conversation.send_message("Write 3 facts about the current project into FACTS.txt.")
103101
conversation.run()
104-
105-
# Report cost
106-
cost = llm.metrics.accumulated_cost
107-
print(f"EXAMPLE_COST: {cost}")
102+
print("All done!")
108103
```
109104

110105
Run the example:

‎sdk/guides/agent-server/docker-sandbox.mdx‎

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ def detect_platform():
6060
# the Docker container automatically
6161
with DockerWorkspace(
6262
# dynamically build agent-server image
63-
# base_image="nikolaik/python-nodejs:python3.12-nodejs22",
63+
base_image="nikolaik/python-nodejs:python3.12-nodejs22",
6464
# use pre-built image for faster startup
65-
server_image="ghcr.io/openhands/agent-server:main-python",
65+
# server_image="ghcr.io/openhands/agent-server:main-python",
6666
host_port=8010,
6767
platform=detect_platform(),
6868
) as workspace:
@@ -122,6 +122,9 @@ with DockerWorkspace(
122122
logger.info("✅ Second task completed!")
123123

124124
# Report cost (must be before conversation.close())
125+
conversation.state._cached_state = (
126+
None # Invalidate cache to fetch latest stats
127+
)
125128
cost = conversation.conversation_stats.get_combined_metrics().accumulated_cost
126129
print(f"EXAMPLE_COST: {cost}")
127130
finally:
@@ -467,7 +470,7 @@ def detect_platform():
467470
# Create a Docker-based remote workspace with extra ports for browser access
468471
with DockerWorkspace(
469472
base_image="nikolaik/python-nodejs:python3.12-nodejs22",
470-
host_port=8010,
473+
host_port=8011,
471474
platform=detect_platform(),
472475
extra_ports=True, # Expose extra ports for VSCode and VNC
473476
) as workspace:
@@ -506,17 +509,26 @@ with DockerWorkspace(
506509
)
507510
conversation.run()
508511

509-
# Wait for user confirm to exit
510-
y = None
511-
while y != "y":
512-
y = input(
513-
"Because you've enabled extra_ports=True in DockerWorkspace, "
514-
"you can open a browser tab to see the *actual* browser OpenHands "
515-
"is interacting with via VNC.\n\n"
516-
"Link: http://localhost:8012/vnc.html?autoconnect=1&resize=remote\n\n"
517-
"Press 'y' and Enter to exit and terminate the workspace.\n"
518-
">> "
512+
conversation.state._cached_state = None # Invalidate cache to fetch latest stats
513+
cost = conversation.conversation_stats.get_combined_metrics().accumulated_cost
514+
print(f"EXAMPLE_COST: {cost}")
515+
516+
if os.getenv("CI"):
517+
logger.info(
518+
"CI environment detected; skipping interactive prompt and closing workspace." # noqa: E501
519519
)
520+
else:
521+
# Wait for user confirm to exit when running locally
522+
y = None
523+
while y != "y":
524+
y = input(
525+
"Because you've enabled extra_ports=True in DockerWorkspace, "
526+
"you can open a browser tab to see the *actual* browser OpenHands "
527+
"is interacting with via VNC.\n\n"
528+
"Link: http://localhost:8012/vnc.html?autoconnect=1&resize=remote\n\n"
529+
"Press 'y' and Enter to exit and terminate the workspace.\n"
530+
">> "
531+
)
520532
```
521533

522534
```bash Running the Example

‎sdk/guides/agent-server/local-server.mdx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ with ManagedAPIServer(port=8001) as server:
254254
logger.info(f" - {event}")
255255

256256
# Report cost (must be before conversation.close())
257+
conversation.state._cached_state = (
258+
None # Invalidate cache to fetch latest stats
259+
)
257260
cost = conversation.conversation_stats.get_combined_metrics().accumulated_cost
258261
print(f"EXAMPLE_COST: {cost}")
259262

‎sdk/guides/custom-tools.mdx‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ class GrepExecutor(ToolExecutor[GrepAction, GrepObservation]):
134134
files: set[str] = set()
135135

136136
# grep returns exit code 1 when no matches; treat as empty
137-
if result.output.strip():
138-
for line in result.output.strip().splitlines():
137+
output_text = result.text
138+
139+
if output_text.strip():
140+
for line in output_text.strip().splitlines():
139141
matches.append(line)
140142
# Expect "path:line:content" — take the file part before first ":"
141143
file_path = line.split(":", 1)[0]

‎sdk/guides/hello-world.mdx‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,32 @@ This is the most basic example showing how to set up and run an OpenHands agent:
1212
```python icon="python" examples/01_standalone_sdk/01_hello_world.py
1313
import os
1414

15-
from pydantic import SecretStr
15+
from openhands.sdk import LLM, Agent, Conversation, Tool
16+
from openhands.tools.execute_bash import BashTool
17+
from openhands.tools.file_editor import FileEditorTool
18+
from openhands.tools.task_tracker import TaskTrackerTool
1619

17-
from openhands.sdk import LLM, Conversation
18-
from openhands.tools.preset.default import get_default_agent
1920

20-
21-
# Configure LLM and agent
22-
# You can get an API key from https://app.all-hands.dev/settings/api-keys
23-
api_key = os.getenv("LLM_API_KEY")
24-
assert api_key is not None, "LLM_API_KEY environment variable is not set."
25-
model = os.getenv("LLM_MODEL", "openhands/claude-sonnet-4-5-20250929")
26-
base_url = os.getenv("LLM_BASE_URL")
2721
llm = LLM(
28-
model=model,
29-
api_key=SecretStr(api_key),
30-
base_url=base_url,
31-
usage_id="agent",
22+
model="anthropic/claude-sonnet-4-5-20250929",
23+
api_key=os.getenv("LLM_API_KEY"),
24+
)
25+
26+
agent = Agent(
27+
llm=llm,
28+
tools=[
29+
Tool(name=BashTool.name),
30+
Tool(name=FileEditorTool.name),
31+
Tool(name=TaskTrackerTool.name),
32+
],
3233
)
33-
agent = get_default_agent(llm=llm, cli_mode=True)
3434

35-
# Start a conversation and send some messages
3635
cwd = os.getcwd()
3736
conversation = Conversation(agent=agent, workspace=cwd)
3837

39-
# Send a message and let the agent run
4038
conversation.send_message("Write 3 facts about the current project into FACTS.txt.")
4139
conversation.run()
42-
43-
# Report cost
44-
cost = llm.metrics.accumulated_cost
45-
print(f"EXAMPLE_COST: {cost}")
40+
print("All done!")
4641
```
4742

4843
```bash Running the Example

0 commit comments

Comments
 (0)