Skip to content
This repository was archived by the owner on Jun 3, 2026. It is now read-only.

Commit a6c371c

Browse files
committed
docs: TS steering; direct tool calls; preserveContext AgentNode
1 parent 11f6b54 commit a6c371c

10 files changed

Lines changed: 187 additions & 77 deletions

File tree

.agents/skills/docs-writer/SKILL.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Write each section following the outline.
4646
- For agent responses, label non-deterministic output following the patterns in `voice-guide.md` under "Documenting non-deterministic behavior" (typical output as a comment under the code; capability language for tool selection).
4747
- Comments explain intent, not mechanics
4848
- One concept per code block
49+
- Match snippet length to the complexity of what's being demonstrated. Bias toward brevity. If setup machinery dwarfs the feature being shown, the snippet is overweight.
50+
- Snippets must be copy-paste-runnable: imports present, variables defined, no missing context.
51+
- Prefer prose over a snippet for trivial API surface. A single property, a single method call, or a one-line config change is often clearer as inline backtick code in a sentence than as a dedicated code block. Reach for a snippet when the shape, ordering, or interaction between calls carries the lesson.
4952

5053
### Step 3b: Apply MDX formatting
5154

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,37 @@ Documentation lives in `docs/` as Markdown files. The site structure is driven b
7373

7474
For a full reference on customizations, components, and the migration status, see [Site Architecture](SITE-ARCHITECTURE.md).
7575

76+
### Using the `docs-` skills
77+
78+
The repo ships four agent skills that cover the documentation workflow: `docs-planner`, `docs-audit`, `docs-writer`, and `docs-reviewer`. They live under `.agents/skills/` (with symlinks at `.claude/skills/` and `.kiro/skills/`). See [`site/AGENTS.md`](site/AGENTS.md#documentation-skills-and-voice-references) for triggers and scopes.
79+
80+
Use them piecemeal when you already know the scope:
81+
82+
- `/docs-audit <page>` to assess a published page before rewriting.
83+
- `/docs-writer <page or topic>` to draft a new page or rewrite an existing one. Step 7 of the skill runs `docs-reviewer` automatically.
84+
- `/docs-reviewer <draft>` on its own when you want a voice/style sign-off without a rewrite.
85+
- `/docs-planner` to prioritize the backlog when you don't yet know what to touch.
86+
87+
Or chain them with a `/goal` directive to drive a full update from a single SDK change. `/goal` is a usage convention, not a built-in command — you set the target and the workflow, the skills do the work. For example:
88+
89+
```
90+
/goal https://github.com/strands-agents/sdk-typescript/commit/<sha>
91+
92+
1. /docs-planner — pick the top item touched by this commit.
93+
2. /docs-audit — find issues on that page.
94+
3. /docs-writer — fix them.
95+
4. /docs-reviewer — sign off, or send back. Default to step 3 for voice/style/code
96+
fixes; bounce to step 2 (or step 1) if the finding is structural. Cap retries at
97+
3, then escalate.
98+
99+
The goal is complete when docs-reviewer returns a "Ship it" verdict and the
100+
resulting commit is on a branch ready for PR.
101+
```
102+
103+
This pattern is useful when the change is narrow (one feature, one or two pages) and you want the skills to handle planner → audit → write → review without you re-prompting at every step.
104+
105+
> These skills are a work in progress. If outputs are wrong, insufficient, or unexpected, contribute updates to `.agents/`.
106+
76107
## Contributing ❤️
77108

78109
We welcome contributions! See our [Contributing Guide](CONTRIBUTING.md) for details on:

site/src/content/docs/user-guide/concepts/multi-agent/graph.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ The `Graph` constructor accepts:
106106

107107
To bound an individual `AgentNode`, pass `timeout` to its options object instead of relying on the orchestrator's `nodeTimeout`. Per-node `timeout` overrides `nodeTimeout` for that node and must be at least 1 ms.
108108

109+
Each `AgentNode` defaults to snapshotting the wrapped agent's state before execution and restoring it afterward, so a node visited multiple times runs from a clean slate. Set `preserveContext: true` on the node (e.g. `new AgentNode({ agent: analyst, preserveContext: true })`) to opt out: the wrapped agent then accumulates messages, app state, and model state across executions, which suits revisited nodes that build on prior work like iterative refinement. `preserveContext: true` requires an `Agent` instance; passing it with a non-`Agent` `InvokableAgent` throws at construction time.
110+
109111
If neither `maxSteps` nor `timeout` is set, the SDK emits a one-time warning at construction since a graph with cyclic edges and no bound can run indefinitely.
110112

111113
Timeouts are enforced via `AbortSignal` and are cooperative. A tool that neither polls its cancel signal nor forwards it to a cancellable API can run past the deadline.
@@ -774,7 +776,7 @@ The Graph pattern is available in multiple SDKs. While the core concept is the s
774776

775777
**Scheduling**: Python executes in discrete batches, waiting for the entire batch to complete before scheduling the next set of nodes. TypeScript launches nodes individually as they become ready, up to `maxConcurrency`. This avoids artificial bottlenecks where a fast node waits for a slow sibling to finish before its dependents can start.
776778

777-
**Node state**: Python accumulates agent state across executions unless `reset_on_revisit` is explicitly enabled. TypeScript agent nodes are stateless by default, snapshotting and restoring the agent's messages and state on each execution.
779+
**Node state**: Python accumulates agent state across executions unless `reset_on_revisit` is explicitly enabled. TypeScript agent nodes are stateless by default, snapshotting and restoring the agent's messages and state on each execution. Set `preserveContext: true` on an individual `AgentNode` to opt into accumulation for revisited nodes.
778780

779781
**Error handling**: Python node failures throw exceptions (fail-fast), while orchestrator-level limit violations return a FAILED result. TypeScript does the inverse: node failures produce a FAILED result, allowing parallel paths to continue, while orchestrator-level limits (`maxSteps`) throw exceptions to promote fail-fast behavior for global failures.
780782

site/src/content/docs/user-guide/concepts/multi-agent/graph.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,3 +410,4 @@ async function topologyFeedbackLoop() {
410410
})
411411
// --8<-- [end:topology_feedback]
412412
}
413+
Lines changed: 69 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,138 @@
11
---
22
title: Steering
33
tags: [hooks, conversation-management, prompt-authoring]
4-
languages: [python]
54
---
65

76

8-
Strands Steering provides modular prompting for complex agent tasks through context-aware guidance that appears when relevant, rather than front-loading all instructions in monolithic prompts. This enables developers to assign agents complex, multi-step tasks while maintaining effectiveness through just-in-time feedback loops.
7+
Steering provides modular prompting for complex agent tasks through context-aware guidance that appears when relevant, rather than front-loading all instructions in monolithic prompts. This lets you assign agents complex, multi-step tasks while maintaining effectiveness through just-in-time feedback loops.
98

109
## What Is Steering?
1110

12-
Developers building AI agents for complex multi-step tasks face a key prompting challenge. Traditional approaches require front-loading all instructions, business rules, and operational guidance into a single prompt. For tasks with 30+ steps, these monolithic prompts become unwieldy, leading to prompt bloat where agents ignore instructions, hallucinate behaviors, or fail to follow critical procedures.
11+
Building agents for complex multi-step tasks runs into a prompting wall. Traditional approaches require front-loading all instructions, business rules, and operational guidance into a single prompt. For tasks with 30+ steps, monolithic prompts become unwieldy: agents ignore instructions, hallucinate behaviors, or fail to follow critical procedures.
1312

14-
To address this, developers often decompose these agents into graph structures with predefined nodes and edges that control execution flow. While this improves predictability and reduces prompt complexity, it severely limits the agent's adaptive reasoning capabilities that make AI valuable in the first place, and is costly to develop and maintain.
13+
A common workaround is decomposing the agent into a graph with predefined nodes and edges that control execution flow. While this improves predictability and reduces prompt complexity, it limits the adaptive reasoning that makes agents valuable in the first place, and it is costly to maintain as requirements change.
1514

16-
Strands Steering solves this challenge through **modular prompting**. Instead of front-loading all instructions, developers define context-aware steering handlers that provide feedback at the right moment. These handlers define the business rules that need to be followed and the lifecycle hooks where agent behavior should be validated, like before a tool call or before returning output to the user.
15+
Steering takes a different approach: **modular prompting**. Instead of front-loading all instructions, you define context-aware steering handlers that provide feedback at the right moment. Each handler defines the business rules to enforce and the lifecycle hooks where agent behavior should be validated, like before a tool call or before returning output to the user.
1716

1817
## Context Population
1918

20-
Steering handlers maintain local context that gets populated by callbacks registered for hook events:
19+
To give the handler something to reason about, attach a provider that observes agent activity and records it as steering context.
2120

2221
```mermaid
2322
flowchart LR
24-
A[Hook Events] --> B[Context Callbacks]
25-
B --> C[Update steering_context]
23+
A[Hook Events] --> B[Context Providers]
24+
B --> C[Update Steering Context]
2625
C --> D[Handler Access]
2726
```
2827

29-
**Context Callbacks** follow the `SteeringContextCallback` protocol and update the handler's `steering_context` dictionary based on specific events like BeforeToolCallEvent or AfterToolCallEvent.
28+
**Context Providers** observe agent activity and contribute structured data into the handler's steering context. The built-in tool ledger provider tracks tool call history, timing, and results. Steering handlers read from this context when deciding whether to intervene.
3029

31-
**Context Providers** implement `SteeringContextProvider` to supply multiple callbacks for different event types. The built-in `LedgerProvider` tracks tool call history, timing, and results.
30+
## Steering Moments
3231

33-
## Steering
32+
### Before a Tool Call
3433

35-
Steering handlers can intercept agent behavior at two points: before tool calls and after model responses.
36-
37-
### Tool Steering
38-
39-
When agents attempt tool calls, steering handlers evaluate the action via `steer_before_tool()`:
34+
When you want the handler to validate a tool call before it runs, return a steering action from the before-tool-call moment:
4035

4136
```mermaid
4237
flowchart LR
4338
A[Tool Call Attempt] --> B[BeforeToolCallEvent]
44-
B --> C["Handler.steer_before_tool()"]
45-
C --> D{ToolSteeringAction}
46-
D -->|Proceed| E[Tool Executes]
39+
B --> C[Handler Evaluates Call]
40+
C --> D{Steering Action}
41+
D -->|Approve| E[Tool Executes]
4742
D -->|Guide| F[Cancel + Feedback]
48-
D -->|Interrupt| G[Human Input]
43+
D -->|Pause for Human| G[Human Input]
4944
```
5045

51-
**Tool steering** returns a `ToolSteeringAction`:
46+
The handler returns one of three actions:
47+
48+
- **Approve**: tool executes immediately
49+
- **Guide**: tool is cancelled, agent receives contextual feedback
50+
- **Pause for human input**: tool execution pauses for human input
5251

53-
- **Proceed**: Tool executes immediately
54-
- **Guide**: Tool cancelled, agent receives contextual feedback
55-
- **Interrupt**: Tool execution paused for human input
52+
The action symbols differ by language. Python returns `Proceed`, `Guide`, or `Interrupt`. TypeScript returns `proceed()`, `guide()`, or `confirm()`.
5653

57-
### Model Steering
54+
### After a Model Response
5855

59-
After each model response, steering handlers can evaluate output via `steer_after_model()`:
56+
When you want the handler to validate the model's output before it reaches the user, return a steering action from the after-model-call moment:
6057

6158
```mermaid
6259
flowchart LR
6360
A[Model Response] --> B[AfterModelCallEvent]
64-
B --> C["Handler.steer_after_model()"]
65-
C --> D{ModelSteeringAction}
66-
D -->|Proceed| E[Response Accepted]
61+
B --> C[Handler Evaluates Output]
62+
C --> D{Steering Action}
63+
D -->|Approve| E[Response Accepted]
6764
D -->|Guide| F[Discard + Retry]
6865
```
6966

70-
**Model steering** returns a `ModelSteeringAction`:
67+
The handler returns one of two actions:
7168

72-
- **Proceed**: Accept the response as-is
73-
- **Guide**: Discard the response and retry with guidance injected into the conversation
69+
- **Approve**: accept the response as-is
70+
- **Guide**: discard the response and retry with guidance injected into the conversation
7471

75-
This enables handlers to validate model responses, ensure required tools are used before completion, or guide conversation flow based on output.
72+
After-model steering enables handlers to validate responses, ensure required tools are used before completion, or guide conversation flow based on output.
7673

7774
## Getting Started
7875

7976
### Natural Language Steering
8077

81-
The LLMSteeringHandler enables developers to express guidance in natural language rather than formal policy languages. This approach is powerful because it can operate on any amount of context you provide and make contextual decisions based on the full steering context.
78+
When you want to express guidance in plain English rather than imperative code, use the `LLMSteeringHandler`. The handler operates on whatever context you provide and makes contextual decisions across the full steering context.
79+
80+
For best practices on writing steering prompts, see the [Agent Standard Operating Procedures (SOP)](https://github.com/strands-agents/agent-sop) framework, which provides structured templates for effective agent prompts.
81+
82+
The two SDKs attach steering handlers differently. Python passes them through `plugins=[handler]`; TypeScript passes them through `interventions: [handler]`.
8283

83-
For best practices for defining the prompts, use the [Agent Standard Operating Procedures (SOP)](https://github.com/strands-agents/agent-sop) framework which provides structured templates and guidelines for creating effective agent prompts.
84+
<Tabs>
85+
<Tab label="Python">
8486

8587
```python
8688
from strands import Agent, tool
8789
from strands.vended_plugins.steering import LLMSteeringHandler
8890

91+
8992
@tool
9093
def send_email(recipient: str, subject: str, message: str) -> str:
9194
"""Send an email to a recipient."""
9295
return f"Email sent to {recipient}"
9396

94-
# Create steering handler to ensure cheerful tone
97+
9598
handler = LLMSteeringHandler(
9699
system_prompt="""
97100
You are providing guidance to ensure emails maintain a cheerful, positive tone.
98-
101+
99102
Guidance:
100103
- Review email content for tone and sentiment
101104
- Suggest more cheerful phrasing if the message seems negative or neutral
102105
- Encourage use of positive language and friendly greetings
103-
106+
104107
When agents attempt to send emails, check if the message tone
105108
is appropriately cheerful and provide feedback if improvements are needed.
106109
"""
107110
)
108111

109112
agent = Agent(
110113
tools=[send_email],
111-
plugins=[handler] # Steering handler integrates as a plugin
114+
plugins=[handler],
112115
)
113116

114-
# Agent receives guidance about email tone
115-
response = agent("Send a frustrated email to tom@example.com, a client who keeps rescheduling important meetings at the last minute")
116-
print(agent.messages) # Shows "Tool call cancelled given new guidance..."
117+
agent(
118+
"Send a frustrated email to tom@example.com, "
119+
"a client who keeps rescheduling important meetings at the last minute"
120+
)
121+
print(agent.messages)
122+
123+
# Typical: agent.messages includes a cancelled send_email ToolUseBlock,
124+
# a guidance message, then a retried send_email with cheerier wording.
125+
```
126+
</Tab>
127+
<Tab label="TypeScript">
128+
129+
```typescript
130+
--8<-- "user-guide/concepts/plugins/steering_imports.ts:natural_language_steering_imports"
131+
132+
--8<-- "user-guide/concepts/plugins/steering.ts:natural_language_steering"
117133
```
134+
</Tab>
135+
</Tabs>
118136

119137
```mermaid
120138
sequenceDiagram
@@ -131,28 +149,26 @@ sequenceDiagram
131149
A->>U: "Let me reframe this more positively..."
132150
```
133151

152+
## Tool Ledger Provider
134153

135-
136-
## Built-in Context Providers
137-
138-
### Ledger Provider
139-
140-
The `LedgerProvider` tracks comprehensive agent activity for audit trails and usage-based guidance. It automatically captures tool call history with inputs, outputs, timing, and success/failure status.
154+
The tool ledger provider tracks tool call history for audit trails and usage-based guidance. It captures every tool invocation with inputs, execution time, and success/failure status.
141155

142156
The ledger captures:
143157

144-
**Tool Call History**: Every tool invocation with inputs, execution time, and success/failure status. Before tool calls, it records pending status with timestamp and arguments. After tool calls, it updates with completion timestamp, final status, results, and any errors.
158+
**Tool Call History**: every tool invocation with inputs, execution time, and result status. Before tool calls, it records pending status with timestamp and arguments. After tool calls, it updates with completion timestamp, final status, results, and any errors.
159+
160+
**Session Metadata**: session start time and other context that persists across the handler's lifecycle.
145161

146-
**Session Metadata**: Session start time and other contextual information that persists across the handler's lifecycle.
162+
**Structured Data**: the ledger is stored in JSON-serializable form in the handler's steering context, making it directly accessible to LLM-based steering decisions.
147163

148-
**Structured Data**: All data is stored in JSON-serializable format in the handler's `steering_context` under the "ledger" key, making it accessible to LLM-based steering decisions.
164+
The provider class name differs by language: Python exposes `LedgerProvider`, TypeScript exposes `ToolLedgerProvider`. Both default to retaining the most recent 100 tool calls; older entries are dropped.
149165

150166
## Comparison with Other Approaches
151167

152168
### Steering vs. Workflow Frameworks
153169

154-
Workflow frameworks force you to specify discrete steps and control flow logic upfront, making agents brittle and requiring extensive developer time to define complex decision trees. When business requirements change, you must rebuild entire workflow logic. Strands Steering uses modular prompting where you define contextual guidance that appears when relevant rather than prescribing exact execution paths. This maintains the adaptive reasoning capabilities that make AI agents valuable while enabling reliable execution of complex procedures.
170+
Workflow frameworks force you to specify discrete steps and control flow logic upfront, making agents brittle and requiring extensive developer time to define complex decision trees. When business requirements change, you rebuild the workflow logic. Steering uses modular prompting where you define contextual guidance that appears when relevant rather than prescribing exact execution paths. This maintains the adaptive reasoning that makes agents valuable while enabling reliable execution of complex procedures.
155171

156172
### Steering vs. Traditional Prompting
157173

158-
Traditional prompting requires front-loading all instructions into a single prompt. For complex tasks with 30+ steps, this leads to prompt bloat where agents ignore instructions, hallucinate behaviors, or fail to follow critical procedures. Strands Steering provides context-aware reminders that appear at the right moment, like post-it notes that guide agents when they need specific information. This keeps context windows lean while maintaining agent effectiveness on complex tasks.
174+
Traditional prompting requires front-loading all instructions into a single prompt. For complex tasks with 30+ steps, this leads to prompt bloat where agents ignore instructions, hallucinate behaviors, or fail to follow critical procedures. Steering provides context-aware reminders that appear at the right moment, like post-it notes that guide agents when they need specific information. This keeps context windows lean while maintaining agent effectiveness on complex tasks.

0 commit comments

Comments
 (0)