Skip to content
Draft
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
73 changes: 73 additions & 0 deletions src/oss/deepagents/harness.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,76 @@ These files often contain general coding style, preferences, conventions, and gu
- Always available to the agent, ensuring consistent behavior

For configuration details and examples, see [Memory](/oss/deepagents/customization#memory).

## Harness profiles

<Info>
`HarnessProfile` is a public beta API and may be updated in future releases.
</Info>

**Harness profiles** let you shape how the harness behaves once a model is selected so the agent is guided toward the optimal behavior for your application.

Use harness profiles to augment the runtime experience of an agent, for example by:

- Appending to the base `deepagents` system prompt (`system_prompt_suffix`), or replacing it outright (`base_system_prompt`)
- Overriding individual tool descriptions (`tool_description_overrides`)
- Excluding specific harness-level tools (`excluded_tools`)
- Excluding specific middleware classes entirely (`excluded_middleware`)
- Adding extra middleware for specific models or providers (`extra_middleware`)
- Disabling, renaming, or re-prompting the general-purpose subagent (`general_purpose_subagent`)

Register a profile under a provider name like `"openai"` for provider-wide defaults, or under a fully qualified `provider:model` key like `"openai:gpt-5.4"` for per-model overrides. Registrations are additive: re-registering under an existing key merges on top of the prior registration (unioning `excluded_tools` and `excluded_middleware`, merging middleware by type, merging `general_purpose_subagent` field-wise, and preserving any fields the new registration leaves unset).

```python
from deepagents import (
GeneralPurposeSubagentProfile,
HarnessProfile,
register_harness_profile,
)
from deepagents.middleware.summarization import SummarizationMiddleware

# Illustrative example showing some of the capabilities of harness profiles:
# Applied by `create_deep_agent` when the selected model resolves to
# `openai:gpt-5.4`. Appends a system-prompt suffix, hides the `execute` tool,
# drops conversation summarization, and skips the auto-added `general-purpose`
# subagent (which also drops the `task` tool when no other subagents are
# configured).
register_harness_profile(
"openai:gpt-5.4",
HarnessProfile(
system_prompt_suffix="Respond in under 100 words.",
excluded_tools={"execute"},
excluded_middleware=frozenset({SummarizationMiddleware}),
general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False),
),
)
```

<Warning>
`excluded_middleware` cannot remove scaffolding that deep agents rely on. Listing `FilesystemMiddleware`, `SubAgentMiddleware`, or the internal permission middleware raises `ValueError` when `create_deep_agent` resolves the profile.
</Warning>

When you pass a preconfigured chat model instance (@[`BaseChatModel`] subclass) instead of a `provider:model` string, the harness synthesizes the canonical `provider:identifier` key from the instance and looks it up in this order: `provider:identifier` -> identifier-only (only when the identifier already contains `:`) -> provider-only fallback.

Harness profiles are complementary to [Provider profiles](/oss/deepagents/models#provider-profiles): provider profiles shape how the model is built, while harness profiles shape how the harness works once that model is in use.

<Accordion title="Ship a harness profile as a plugin">
Distributable harness profiles can register themselves via `importlib.metadata` entry points instead of requiring callers to run `register_harness_profile` by hand. Declare an entry point in the distribution's own `pyproject.toml` under the `deepagents.harness_profiles` group:

```toml
[project.entry-points."deepagents.harness_profiles"]
gemini = "my_pkg.profiles:register"
```

The target resolves to a zero-arg callable that performs the registrations when `deepagents.profiles` is imported:

```python
from deepagents import HarnessProfile, register_harness_profile

def register() -> None:
register_harness_profile(
"google_genai",
HarnessProfile(system_prompt_suffix="Batch independent tool calls in parallel."),
)
```
</Accordion>
50 changes: 49 additions & 1 deletion src/oss/deepagents/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,57 @@ To configure model-specific parameters, use @[`init_chat_model`] or instantiate
:::

<Note>
Available parameters vary by provider. See the [chat model integrations](/oss/integrations/chat) page for provider-specific configuration options.
Available parameters vary by provider. See the [chat model integrations](/oss/integrations/chat) page for provider-specific configuration options.
</Note>

### Provider profiles

<Info>
`ProviderProfile` is a public beta API and may be updated in future releases.
</Info>

**Provider profiles** let you package model setup for a provider or a specific model. They apply when the harness turns a string spec like `"openai:gpt-5.4"` into a chat model, and shape *how the client is built*:

- `init_kwargs` — default kwargs forwarded to @[`init_chat_model`]
- `pre_init` — side effects to run before construction (for example, credential validation for a clearer error than the SDK would give)
- `init_kwargs_factory` — kwargs derived from runtime state (for example, headers pulled from environment variables)

Register a profile under a provider name like `"openai"` for provider-wide defaults, or under a fully qualified `provider:model` key like `"openai:gpt-5.4"` for per-model overrides. Registrations are additive: re-registering under an existing key merges on top of the prior registration. `init_kwargs` dicts merge key-wise (your value wins on a shared key), `pre_init` callables chain (existing runs first, then the new one), and `init_kwargs_factory` callables chain with their outputs merged every time `resolve_model` runs.

```python
from deepagents import ProviderProfile, register_provider_profile

# `temperature=0` is forwarded whenever the harness builds an
# `openai:*` model from a string spec.
register_provider_profile(
"openai",
ProviderProfile(init_kwargs={"temperature": 0}),
)
```

This is useful when you want model selection to carry the right defaults automatically, without repeating setup code everywhere you create an agent. If you pass a preconfigured chat model instance directly, that instance's settings take precedence — `ProviderProfile` is only consulted when the harness constructs the model from a string spec. For harness behavior after model creation, see [Harness profiles](/oss/deepagents/harness#harness-profiles).

<Accordion title="Ship a provider profile as a plugin">
Distributable profiles can register themselves via `importlib.metadata` entry points instead of requiring callers to run `register_provider_profile` by hand. Declare an entry point in the distribution's own `pyproject.toml` under the `deepagents.provider_profiles` group:

```toml
[project.entry-points."deepagents.provider_profiles"]
my_provider = "my_pkg.profiles:register"
```

The target resolves to a zero-arg callable that performs the registrations when `deepagents.profiles` is imported:

```python
from deepagents import ProviderProfile, register_provider_profile

def register() -> None:
register_provider_profile(
"my_provider",
ProviderProfile(init_kwargs={"temperature": 0}),
)
```
</Accordion>

## Select a model at runtime

If your application lets users choose a model (for example using a dropdown in the UI), use [middleware](/oss/langchain/middleware) to swap the model at runtime without rebuilding the agent.
Expand Down
12 changes: 12 additions & 0 deletions src/oss/deepagents/subagents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ Subagents solve the **context bloat problem**. When agents use tools with large

`subagents` should be a list of dictionaries or @[`CompiledSubAgent`] objects. There are two types:

### Default subagent

Deep Agents automatically adds a synchronous `general-purpose` subagent unless you already provide a synchronous subagent with that name.

- To replace it, pass your own subagent named `general-purpose`.
- To rename or re-prompt the auto-added version, set `general_purpose_subagent=GeneralPurposeSubagentProfile(...)` on the active [harness profile](/oss/deepagents/harness#harness-profiles).
- To remove it entirely, set `general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False)` on the active harness profile.

If no synchronous subagents remain after that, Deep Agents does not add the `task` tool. This behavior only affects synchronous subagents. Async subagents still use the async task tools described in [Async subagents](/oss/deepagents/async-subagents).

### SubAgent (Dictionary-based)

For most use cases, define subagents as dictionaries matching the @[`SubAgent`] spec with the following fields:
Expand Down Expand Up @@ -368,6 +378,8 @@ const agent = await createDeepAgent({

When you provide a subagent with the general-purpose name, the default general-purpose subagent is not added. Your spec fully replaces it.

To remove the built-in general-purpose subagent entirely instead of replacing it, set the active harness profile's general-purpose subagent `enabled` flag to `False`.

### When to use it

The general-purpose subagent is ideal for context isolation without specialized behavior. The main agent can delegate a complex multi-step task to this subagent and get a concise result back without bloat from intermediate tool calls.
Expand Down
Loading