Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pipeline/preprocessors/link_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class LinkMap(TypedDict):
# Deep Agents
"create_deep_agent": "deepagents/graph/create_deep_agent",
"DeepAgentState": "deepagents/graph/DeepAgentState",
"SystemPromptConfig": "deepagents/graph/SystemPromptConfig",
"SubAgent": "deepagents/middleware/subagents/SubAgent",
"CompiledSubAgent": "deepagents/middleware/subagents/CompiledSubAgent",
"SubAgentMiddleware": "deepagents/middleware/subagents/SubAgentMiddleware",
Expand Down
77 changes: 24 additions & 53 deletions src/oss/deepagents/customization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import CustomizationToolsPy from '/snippets/code-samples/customization-tools-py.
import CustomizationToolsJs from '/snippets/code-samples/customization-tools-js.mdx';
import CustomizationSystemPromptPy from '/snippets/code-samples/customization-system-prompt-py.mdx';
import CustomizationSystemPromptJs from '/snippets/code-samples/customization-system-prompt-js.mdx';

import CustomizationMiddlewarePy from '/snippets/code-samples/customization-middleware-py.mdx';
import CustomizationMiddlewareJs from '/snippets/code-samples/customization-middleware-js.mdx';
import CustomizationMiddlewareDoPy from '/snippets/code-samples/customization-middleware-do-py.mdx';
Expand All @@ -52,7 +53,6 @@ import CustomizationOverviewPy from '/snippets/code-samples/customization-overvi
import CustomizationOverviewJs from '/snippets/code-samples/customization-overview-js.mdx';
import CustomizationMcpPy from '/snippets/code-samples/customization-mcp-py.mdx';
import CustomizationMcpJs from '/snippets/code-samples/customization-mcp-js.mdx';
import CustomizationPromptAssemblyPy from '/snippets/code-samples/customization-prompt-assembly-py.mdx';
import CustomizationGpSubagentProfilePy from '/snippets/code-samples/customization-gp-subagent-profile-py.mdx';

Build the harness around your goal. `create_deep_agent` gives you a production-ready foundation: connect it to your data, shape its behavior, and add the capabilities your use case needs.
Expand Down Expand Up @@ -177,11 +177,7 @@ For detailed configuration options including stdio servers, OAuth authentication

## System prompt

Deep Agents come with a built-in system prompt. A deep agent's value comes from the orchestration layer the SDK provides on top of the model—planning, virtual-filesystem tools, and subagents—and the model needs to know those exist and when to reach for them. The built-in prompt teaches the agent how to use that scaffolding so you don't have to re-derive it for every project; tweak it through a [profile](/oss/deepagents/profiles#harness-profiles) or your own `system_prompt=` rather than copying it verbatim.

When middleware add special tools, like the filesystem tools, it appends them to the system prompt.

Each deep agent should also include a custom system prompt specific to its specific use case:
Deep Agents ship with a built-in base system prompt that teaches the agent how to use the harness scaffolding (planning, filesystem tools, subagents). Pass `system_prompt=` to prepend your own instructions before that base prompt:

:::python
<CustomizationSystemPromptPy />
Expand All @@ -191,73 +187,48 @@ Each deep agent should also include a custom system prompt specific to its speci
<CustomizationSystemPromptJs />
:::

### Prompt assembly

Deep Agents builds the system prompt from up to four named parts so that caller-supplied instructions, the SDK's built-in agent guidance, and any model-specific [profile](/oss/deepagents/profiles) overrides can coexist with predictable precedence. Without this layering, a profile suffix tuned for Claude (for example) could overwrite or be overwritten by your `system_prompt=` argument depending on call order; the named slots make the ordering explicit and stable.

In practice, most callers only encounter two slots: `USER` (your `system_prompt=`) and `BASE` (the SDK default). Selecting a model with a built-in profile—Anthropic or OpenAI today—adds a `SUFFIX`. The full four-part assembly is mainly relevant when you author a custom `HarnessProfile` or debug why a profile's text appears where it does.
When middleware adds special tools, like the filesystem tools, it appends its own guidance to the system prompt at runtime.

The four named parts (each may be absent):

| Name | Source | Notes |
| -------- | ------------------------------------------------- | ------------------------------------------------- |
| `USER` | `system_prompt=` argument to `create_deep_agent` | `str` or `SystemMessage`; omitted when unset. |
| `BASE` | The SDK default (`BASE_AGENT_PROMPT`) | Always present unless replaced by a profile's `CUSTOM`. |
| `CUSTOM` | [`HarnessProfile.base_system_prompt`](/oss/deepagents/profiles#harness-profiles) | Replaces `BASE` outright when a matching profile sets it. |
| `SUFFIX` | [`HarnessProfile.system_prompt_suffix`](/oss/deepagents/profiles#harness-profiles) | Appended last when a matching profile sets it. |
:::python
<Note>
`SystemPromptConfig` requires `deepagents>=0.7.0a6`.
</Note>

The order is always **`USER` -> (`BASE` or `CUSTOM`) -> `SUFFIX`**, joined by blank lines (`\n\n`). Two invariants follow:
For full control over prompt assembly, pass a @[`SystemPromptConfig`] dict with `prefix`, `base`, and `suffix` keys:

1. **`USER` is always at the front.** The caller's text precedes any SDK or profile content, so persona/instructions take precedence regardless of which model is selected.
2. **`SUFFIX` is always at the end.** Profile suffixes sit closest to the conversation history, where model-tuning guidance lands most reliably.
- **`prefix`**: text placed before the base prompt (same as passing a bare string).
- **`base`**: replaces the built-in base prompt. Omit the key to keep the built-in base, or set it to `None` to drop the base entirely.
- **`suffix`**: text placed after the base prompt.

Assembled shapes (✓ = field is set, - = field is unset):
Parts are assembled in order: `prefix` -> `base` -> `suffix` -> any model-specific [profile](/oss/deepagents/profiles) suffix. Each part accepts a `str` or a `SystemMessage` (to preserve `cache_control` markers for Anthropic prompt caching).

| `system_prompt=` | profile `base_system_prompt` (`CUSTOM`) | profile `system_prompt_suffix` (`SUFFIX`) | Final assembled system prompt |
| ---------------- | :-------------------------------------: | :---------------------------------------: | ----------------------------- |
| `None` | - | - | `BASE` |
| `None` | - | ✓ | `BASE` + `SUFFIX` |
| `None` | ✓ | - | `CUSTOM` |
| `None` | ✓ | ✓ | `CUSTOM` + `SUFFIX` |
| `str` | - | - | `USER` + `BASE` |
| `str` | - | ✓ | `USER` + `BASE` + `SUFFIX` |
| `str` | ✓ | - | `USER` + `CUSTOM` |
| `str` | ✓ | ✓ | `USER` + `CUSTOM` + `SUFFIX` |
```python
# Overwrite the default base prompt:
create_deep_agent(..., system_prompt={"base": "..."})

Worked example—built-in profiles (Anthropic, OpenAI) ship only a `system_prompt_suffix`, so a typical call lands in the `str` + `-` + `✓` row:
# No system prompt except from middleware:
create_deep_agent(..., system_prompt={"base": None})

<CustomizationPromptAssemblyPy />
# Sandwich the default base prompt:
create_deep_agent(..., system_prompt={"prefix": "...", "suffix": "..."})
```

<Note>
Passing a `SystemMessage` (rather than a string) triggers a different concatenation path: the right-hand assembly (`BASE`-or-`CUSTOM` plus any `SUFFIX`) is appended as an additional text content block onto the message's existing `content_blocks`. The same logical ordering applies (caller blocks first), and any `cache_control` markers on the caller's blocks are preserved—useful for placing explicit Anthropic prompt-cache breakpoints.
</Note>
For model-specific system prompt customization, such as replacing the base prompt or appending a suffix for a particular provider, use a [harness profile](/oss/deepagents/profiles#harness-profiles).
:::

<AccordionGroup>
<Accordion title="Subagent prompts">
The [prompt assembly](#prompt-assembly) overlay rules also apply to declarative [subagents](/oss/deepagents/subagents): each subagent re-runs profile resolution against **its own model**, then applies the resolved profile's `base_system_prompt` / `system_prompt_suffix` to its authored `system_prompt`. The subagent's `system_prompt` plays the `BASE` role; `CUSTOM` and `SUFFIX` come from the profile that matches the subagent's model (which may differ from the main agent's profile).

| `spec["system_prompt"]` | profile `base_system_prompt` (`CUSTOM`) | profile `system_prompt_suffix` (`SUFFIX`) | Final subagent system prompt |
| ----------------------- | :-------------------------------------: | :---------------------------------------: | ---------------------------- |
| authored | - | - | authored |
| authored | - | ✓ | authored + `SUFFIX` |
| authored | ✓ | - | `CUSTOM` |
| authored | ✓ | ✓ | `CUSTOM` + `SUFFIX` |

There is no `USER` segment for subagents. The spec's authored `system_prompt` is the closest analog and stays in the `BASE` slot. A profile that ships only a `system_prompt_suffix` (the common case for built-in Anthropic / OpenAI profiles) just appends to whatever the subagent author wrote. A profile that sets `base_system_prompt` will *replace* the authored prompt outright.
Declarative [subagents](/oss/deepagents/subagents) resolve profile overlays against their own model, then apply the resolved profile's `base_system_prompt` / `system_prompt_suffix` to the subagent's authored `system_prompt`. A profile that ships only a `system_prompt_suffix` (the common case for built-in Anthropic / OpenAI profiles) appends to the authored prompt. A profile that sets `base_system_prompt` replaces it outright.
</Accordion>
<Accordion title="General-purpose subagent prompt">
The auto-added [general-purpose subagent](/oss/deepagents/subagents#the-general-purpose-subagent) follows the [prompt assembly](#prompt-assembly) overlay rules with one extra layer: the GP base prompt is resolved as **`general_purpose_subagent.system_prompt` (if set) -> `HarnessProfile.base_system_prompt` (if set) -> SDK general-purpose default**. The profile suffix layers on top either way.

The two override fields can both carry a base-prompt replacement, but they are not interchangeable. `general_purpose_subagent.system_prompt` is general-purpose-specific configuration; `base_system_prompt` is a global override that primarily targets the main agent. When both are set, the **general-purpose-specific intent wins for the general-purpose subagent** so a user tuning both fields never sees their GP override silently dropped:
The auto-added [general-purpose subagent](/oss/deepagents/subagents#the-general-purpose-subagent) resolves its base prompt as **`general_purpose_subagent.system_prompt` (if set) -> `HarnessProfile.base_system_prompt` (if set) -> SDK general-purpose default**, with the profile suffix layered on top. When both override fields are set, the general-purpose-specific one wins so a caller tuning both fields never sees their GP override silently dropped:

<CustomizationGpSubagentProfilePy />

| Stack | Final system prompt |
| ----- | ------------------- |
| Main agent | `"You are ACME's support orchestrator." + SUFFIX` |
| GP subagent | `"You are a research subagent. Cite sources." + SUFFIX` |

If `general_purpose_subagent.system_prompt` is unset, the GP subagent falls back to `base_system_prompt` (when set) and finally to the SDK general-purpose default.
</Accordion>
</AccordionGroup>

Expand Down
12 changes: 6 additions & 6 deletions src/oss/deepagents/profiles.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ A harness profile describes prompt-assembly, tool-visibility, middleware, and de

:::python
<ResponseField name="base_system_prompt" type="string">
Replace the base Deep Agents system prompt (`CUSTOM` in [Prompt assembly](/oss/deepagents/customization#prompt-assembly)).
Replace the base Deep Agents system prompt (the `base` key in [System prompt](/oss/deepagents/customization#system-prompt)).
</ResponseField>

<ResponseField name="system_prompt_suffix" type="string">
Append text to the assembled base prompt (`SUFFIX` in [Prompt assembly](/oss/deepagents/customization#prompt-assembly)); applied to the main agent, declarative subagents, and the auto-added general-purpose subagent.
Append text after the caller's `suffix`, placed last in the assembled system prompt. Applied to the main agent, declarative subagents, and the auto-added general-purpose subagent.
</ResponseField>

<ResponseField name="tool_description_overrides" type="Mapping[str, str]">
Expand All @@ -72,11 +72,11 @@ A harness profile describes prompt-assembly, tool-visibility, middleware, and de

:::js
<ResponseField name="baseSystemPrompt" type="string">
Replace the base Deep Agents system prompt (`CUSTOM` in [Prompt assembly](/oss/deepagents/customization#prompt-assembly)).
Replace the base Deep Agents system prompt (the `base` key in [System prompt](/oss/deepagents/customization#system-prompt)).
</ResponseField>

<ResponseField name="systemPromptSuffix" type="string">
Append text to the assembled base prompt (`SUFFIX` in [Prompt assembly](/oss/deepagents/customization#prompt-assembly)); applied to the main agent, declarative subagents, and the auto-added general-purpose subagent.
Append text after the caller's `suffix`, placed last in the assembled system prompt. Applied to the main agent, declarative subagents, and the auto-added general-purpose subagent.
</ResponseField>

<ResponseField name="toolDescriptionOverrides" type="Record<string, string>">
Expand All @@ -102,13 +102,13 @@ A harness profile describes prompt-assembly, tool-visibility, middleware, and de

:::python
<Note>
Caller-supplied `system_prompt=` always sits at the front of the assembled prompt, and `system_prompt_suffix` always sits at the end—regardless of which model is selected. The same overlay rules apply to subagents: each subagent re-runs profile resolution against its own model. See [Prompt assembly](/oss/deepagents/customization#prompt-assembly) for the full per-case breakdown (main agent, subagents, and the general-purpose subagent).
Caller-supplied `system_prompt=` always sits at the front of the assembled prompt, and `system_prompt_suffix` always sits at the end—regardless of which model is selected. The same overlay rules apply to subagents: each subagent re-runs profile resolution against its own model. See [System prompt](/oss/deepagents/customization#system-prompt) for the full per-case breakdown (main agent, subagents, and the general-purpose subagent).
</Note>
:::

:::js
<Note>
Caller-supplied `systemPrompt` always sits at the front of the assembled prompt, and `systemPromptSuffix` always sits at the end—regardless of which model is selected. The same overlay rules apply to subagents: each subagent re-runs profile resolution against its own model. See [Prompt assembly](/oss/deepagents/customization#prompt-assembly) for the full per-case breakdown (main agent, subagents, and the general-purpose subagent).
Caller-supplied `systemPrompt` always sits at the front of the assembled prompt, and `systemPromptSuffix` always sits at the end—regardless of which model is selected. The same overlay rules apply to subagents: each subagent re-runs profile resolution against its own model. See [System prompt](/oss/deepagents/customization#system-prompt) for the full per-case breakdown (main agent, subagents, and the general-purpose subagent).
</Note>
:::

Expand Down
2 changes: 1 addition & 1 deletion src/oss/deepagents/subagents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ For full details on schema types and strategies (tool calling vs. provider-nativ

In addition to any user-defined subagents, every deep agent has access to a `general-purpose` subagent at all times. This subagent:

- Uses its own [default system prompt with profile overlays applied](/oss/deepagents/customization#prompt-assembly)
- Uses its own [default system prompt with profile overlays applied](/oss/deepagents/customization#system-prompt)
- Has access to all the same tools
- Uses the same model (unless overridden)
- Inherits skills from the main agent (when skills are configured)
Expand Down
1 change: 1 addition & 0 deletions src/oss/python/releases/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ rss: true
- **`write_file` now overwrites existing files**: `write_file` used to error if the target file already existed. It now overwrites it — use `edit_file` for targeted changes to an existing file.
- **[Override a default middleware instance](/oss/deepagents/customization#override-a-default-middleware-instance)**: A `middleware=` (or subagent `middleware`) instance whose `.name` matches a default now replaces that default in place, instead of erroring on duplicate middleware.
- **[Restrict filesystem tools](/oss/deepagents/overview#virtual-filesystem-access)**: `FilesystemMiddleware` now accepts a `tools` allowlist to expose only a subset of the built-in filesystem tools to the model, building on the middleware-override behavior above.
- **[Structured system prompt configuration](/oss/deepagents/customization#system-prompt)**: The `system_prompt` parameter now accepts a `SystemPromptConfig` dict with `prefix`, `base`, and `suffix` keys, enabling callers to replace or remove the built-in base prompt and add text before or after it.

</Update>
<Update label="May 12, 2026" tags={["deepagents"]} rss={{ title: "May 12, 2026 - langchain" }}>
Expand Down
Loading