-
Notifications
You must be signed in to change notification settings - Fork 16
docs: add AgentSettings example guide #430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| --- | ||
| title: Agent Settings | ||
| description: Configure, serialize, and recreate agents from structured settings. | ||
| --- | ||
|
|
||
| import RunExampleCode from "/sdk/shared-snippets/how-to-run-example.mdx"; | ||
|
|
||
| > A ready-to-run example is available [here](#ready-to-run-example)! | ||
|
|
||
| `AgentSettings` gives you a structured, serializable way to define an agent's model, tools, and optional subsystems like the condenser. Use it when you want to store agent configuration in JSON, send it over an API, or rebuild agents from validated settings later. | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ Verified Accurate: Confirmed |
||
| ## Why Use AgentSettings | ||
|
|
||
| - Keep agent configuration as data instead of wiring everything together imperatively. | ||
| - Validate settings with Pydantic before creating an agent. | ||
| - Serialize and deserialize settings for storage, transport, or UI-driven configuration. | ||
| - Create different agent variants by changing only the settings payload. | ||
|
|
||
| ## Build Settings | ||
|
|
||
| Create an `AgentSettings` object with the same ingredients you would normally pass to an `Agent`. | ||
|
|
||
| ```python icon="python" focus={8, 11, 12, 13} | ||
| from pydantic import SecretStr | ||
|
|
||
| from openhands.sdk import AgentSettings, LLM, Tool | ||
| from openhands.sdk.settings import CondenserSettings | ||
| from openhands.tools.file_editor import FileEditorTool | ||
| from openhands.tools.terminal import TerminalTool | ||
|
|
||
| settings = AgentSettings( | ||
| llm=LLM( | ||
| model="anthropic/claude-sonnet-4-5-20250929", | ||
| api_key=SecretStr("your-api-key"), | ||
| ), | ||
| tools=[ | ||
| Tool(name=TerminalTool.name), | ||
| Tool(name=FileEditorTool.name), | ||
| ], | ||
| condenser=CondenserSettings(enabled=True, max_size=50), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ Verified Accurate: |
||
| ) | ||
| ``` | ||
|
|
||
| ## Serialize and Restore Settings | ||
|
|
||
| Because `AgentSettings` is a Pydantic model, you can dump it to JSON-compatible data and restore it later. | ||
|
|
||
| ```python icon="python" focus={1, 2} | ||
| payload = settings.model_dump(mode="json") | ||
| restored = AgentSettings.model_validate(payload) | ||
| ``` | ||
|
|
||
| This is useful when: | ||
|
|
||
| - Saving agent configuration in a database | ||
| - Sending settings through an API | ||
| - Letting users edit agent configuration in a form-based UI | ||
| - Rehydrating the same agent setup in another process | ||
|
|
||
| ## Create an Agent from Settings | ||
|
|
||
| Once validated, create a working agent directly from the settings object. | ||
|
|
||
| ```python icon="python" focus={1} | ||
| agent = settings.create_agent() | ||
| ``` | ||
|
|
||
| You can then pass that agent into a `Conversation`, or derive another agent by changing the settings payload. For example, the full example below also shows how removing `FileEditorTool` and disabling the condenser produces a different agent configuration without rewriting the rest of the setup. | ||
|
|
||
| ## Ready-to-run Example | ||
|
|
||
| <Note> | ||
| This example is available on GitHub: [examples/01_standalone_sdk/46_agent_settings.py](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/46_agent_settings.py) | ||
| </Note> | ||
|
|
||
| ```python icon="python" expandable examples/01_standalone_sdk/46_agent_settings.py | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ Code Sync Format Correct: The code block format |
||
| """Create, serialize, and deserialize AgentSettings, then build a working agent. | ||
|
|
||
| Demonstrates: | ||
| 1. Configuring an agent entirely through AgentSettings (LLM, tools, condenser). | ||
| 2. Serializing settings to JSON and restoring them. | ||
| 3. Building an Agent from settings via ``create_agent()``. | ||
| 4. Running a short conversation to prove the settings take effect. | ||
| 5. Changing the tool list and showing the agent's capabilities change. | ||
| """ | ||
|
|
||
| import json | ||
| import os | ||
|
|
||
| from pydantic import SecretStr | ||
|
|
||
| from openhands.sdk import LLM, AgentSettings, Conversation, Tool | ||
| from openhands.sdk.settings import CondenserSettings | ||
| from openhands.tools.file_editor import FileEditorTool | ||
| from openhands.tools.terminal import TerminalTool | ||
|
|
||
|
|
||
| # ── 1. Build settings ──────────────────────────────────────────────────── | ||
| api_key = os.getenv("LLM_API_KEY") | ||
| assert api_key is not None, "LLM_API_KEY environment variable is not set." | ||
|
|
||
| settings = AgentSettings( | ||
| llm=LLM( | ||
| model=os.getenv("LLM_MODEL", "anthropic/claude-sonnet-4-5-20250929"), | ||
| api_key=SecretStr(api_key), | ||
| base_url=os.getenv("LLM_BASE_URL"), | ||
| ), | ||
| tools=[ | ||
| Tool(name=TerminalTool.name), | ||
| Tool(name=FileEditorTool.name), | ||
| ], | ||
| condenser=CondenserSettings(enabled=True, max_size=50), | ||
| ) | ||
|
|
||
| # ── 2. Serialize → JSON → deserialize ──────────────────────────────────── | ||
| payload = settings.model_dump(mode="json") | ||
| print("Serialized settings (JSON):") | ||
| print(json.dumps(payload, indent=2, default=str)[:800], "…") | ||
| print() | ||
|
|
||
| restored = AgentSettings.model_validate(payload) | ||
| assert restored.condenser.enabled is True | ||
| assert restored.condenser.max_size == 50 | ||
| assert len(restored.tools) == 2 | ||
| print("✓ Roundtrip deserialization successful — all fields preserved") | ||
| print() | ||
|
|
||
| # ── 3. Create agent from settings and run a task ───────────────────────── | ||
| agent = settings.create_agent() | ||
| print(f"Agent created: llm.model={agent.llm.model}") | ||
| print(f" tools={[t.name for t in agent.tools]}") | ||
| print(f" condenser={type(agent.condenser).__name__}") | ||
| print() | ||
|
|
||
| cwd = os.getcwd() | ||
| conversation = Conversation(agent=agent, workspace=cwd) | ||
| conversation.send_message( | ||
| "Create a file called hello_settings.txt containing " | ||
| "'Agent settings work!' then confirm the file exists with ls." | ||
| ) | ||
| conversation.run() | ||
|
|
||
| # Verify the agent actually wrote the file | ||
| assert os.path.exists(os.path.join(cwd, "hello_settings.txt")), ( | ||
| "Agent should have created hello_settings.txt" | ||
| ) | ||
| print("✓ Agent created hello_settings.txt — settings drove real behavior") | ||
| print() | ||
|
|
||
| # ── 4. Different settings → different behavior ─────────────────────────── | ||
| # Now create settings with ONLY the terminal tool and condenser disabled. | ||
| terminal_only_settings = AgentSettings( | ||
| llm=settings.llm, | ||
| tools=[Tool(name=TerminalTool.name)], | ||
| condenser=CondenserSettings(enabled=False), | ||
| ) | ||
|
|
||
| terminal_agent = terminal_only_settings.create_agent() | ||
| print(f"Terminal-only agent tools: {[t.name for t in terminal_agent.tools]}") | ||
| assert len(terminal_agent.tools) == 1 | ||
| assert terminal_agent.condenser is None # condenser disabled in these settings | ||
| print("✓ Different settings produce different agent configuration") | ||
| print() | ||
|
|
||
| # ── Cleanup ────────────────────────────────────────────────────────────── | ||
| os.remove(os.path.join(cwd, "hello_settings.txt")) | ||
|
|
||
| # Report cost | ||
| cost = conversation.conversation_stats.get_combined_metrics().accumulated_cost | ||
| print(f"\nEXAMPLE_COST: {cost}") | ||
| ``` | ||
|
|
||
| <RunExampleCode path_to_script="examples/01_standalone_sdk/46_agent_settings.py"/> | ||
|
|
||
| ## Next Steps | ||
|
|
||
| - **[Getting Started](/sdk/getting-started)** - Start from a minimal agent and conversation setup | ||
| - **[Context Condenser](/sdk/guides/context-condenser)** - Control conversation compaction behavior | ||
| - **[Agent Delegation](/sdk/guides/agent-delegation)** - Compose specialized agents for larger tasks | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Suggestion - PR Reference: The PR description references SDK PR #2661 which is about bumping actions/checkout, not AgentSettings. Since the example file
46_agent_settings.pyalready exists in the SDK main branch, this is accurate documentation and can be merged. Consider updating the PR description to clarify that the SDK example is already merged, or reference the correct SDK PR that added it.The branch name
dependabot/github_actions/actions/checkout-6is also confusing since it suggests a Dependabot PR, but this doesn't block the merge.