Skip to content

Commit 7a22dd3

Browse files
committed
docs(showcase/strands): region markers for shared-state-read-write + subagents
Catches up strands's shared-state-read-write and subagents demos (added in CopilotKit#4359, post smalls batch 1) to parity with langgraph-python. - shared-state-read-write: nested use-agent/use-agent-read and set-state/use-agent-write on page.tsx; notes-card-render and preferences-card-render on the card components (8 regions total) - subagents: delegation-log-frontend on the log component; subagent-setup + supervisor-delegation-tools on src/agents/agent.py wrapping the _SUBAGENT_SYSTEM_PROMPTS dict and the @tool delegation wrappers (3 regions total — strands keeps everything in one god-file but both regions still have clean wrappable boundaries)
1 parent fb6546a commit 7a22dd3

5 files changed

Lines changed: 39 additions & 0 deletions

File tree

showcase/integrations/strands/src/agents/agent.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,12 @@ async def notes_state_from_args(context):
379379
# entry the moment the tool returns.
380380

381381

382+
# @region[subagent-setup]
383+
# Each sub-agent is a single-shot OpenAI completion driven by its own
384+
# system prompt. They don't share memory or tools with the supervisor —
385+
# the supervisor only sees the returned text. We keep the prompts in a
386+
# dict (rather than spinning up a full secondary Strands ``Agent`` per
387+
# delegation) because the demo only needs one round-trip per call.
382388
_SUBAGENT_SYSTEM_PROMPTS: dict[str, str] = {
383389
"research_agent": (
384390
"You are a research sub-agent. Given a topic, produce a concise "
@@ -394,6 +400,7 @@ async def notes_state_from_args(context):
394400
"2-3 crisp, actionable critiques. No preamble."
395401
),
396402
}
403+
# @endregion[subagent-setup]
397404

398405

399406
# Per-thread scratchpad of delegations. Keyed by ``thread_id``; the entry
@@ -521,6 +528,14 @@ class name. ``_make_subagent_state_from_result`` recognizes the
521528
return f"{_SUBAGENT_FAILURE_MARKER}{exc.__class__.__name__}"
522529

523530

531+
# @region[supervisor-delegation-tools]
532+
# Each @tool wraps a sub-agent invocation. The supervisor LLM "calls"
533+
# these tools to delegate work; ``_run_subagent`` synchronously runs the
534+
# matching sub-agent (a single-shot OpenAI completion), and the result
535+
# string is returned to the supervisor as the tool result. The matching
536+
# ``ToolBehavior(state_from_result=...)`` hook on each tool (registered
537+
# in ``build_showcase_agent``) appends a Delegation entry to shared
538+
# state so the UI's <DelegationLog/> reflects the call in real time.
524539
@tool
525540
def research_agent(task: str) -> str:
526541
"""Delegate a research task to the research sub-agent.
@@ -557,6 +572,7 @@ def critique_agent(task: str) -> str:
557572
task: The draft to critique.
558573
"""
559574
return _run_subagent("critique_agent", task)
575+
# @endregion[supervisor-delegation-tools]
560576

561577

562578
def _make_subagent_state_from_result(sub_agent_name: str):

showcase/integrations/strands/src/app/demos/shared-state-read-write/notes-card.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ export interface NotesCardProps {
1818
* The "Clear" button is a write-back (UI -> agent state) to demonstrate
1919
* both directions on the same field.
2020
*/
21+
// @region[notes-card-render]
22+
// Read-side render: this card reflects the agent-authored `notes` slice
23+
// of shared state. The parent page passes `state.notes` in; we never
24+
// touch agent state ourselves — we just render it. The Clear button is
25+
// a small write-back, exposed as an `onClear` prop.
2126
export function NotesCard({ notes, onClear }: NotesCardProps) {
2227
return (
2328
<div
@@ -69,3 +74,4 @@ export function NotesCard({ notes, onClear }: NotesCardProps) {
6974
</div>
7075
);
7176
}
77+
// @endregion[notes-card-render]

showcase/integrations/strands/src/app/demos/shared-state-read-write/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ export default function SharedStateReadWriteDemo() {
3737
}
3838

3939
function DemoContent() {
40+
// @region[use-agent]
41+
// @region[use-agent-read]
4042
// Subscribe the component to agent state changes. Any time the agent
4143
// mutates its state (e.g. via its `set_notes` tool emitting a
4244
// StateSnapshotEvent through ag_ui_strands' ToolBehavior hook) this
@@ -46,6 +48,8 @@ function DemoContent() {
4648
agentId: "shared-state-read-write",
4749
updates: [UseAgentUpdate.OnStateChanged],
4850
});
51+
// @endregion[use-agent-read]
52+
// @endregion[use-agent]
4953

5054
useConfigureSuggestions({
5155
suggestions: [
@@ -79,6 +83,8 @@ function DemoContent() {
7983
// eslint-disable-next-line react-hooks/exhaustive-deps
8084
}, []);
8185

86+
// @region[set-state]
87+
// @region[use-agent-write]
8288
// WRITE: every edit in the sidebar goes straight into agent state.
8389
// On the agent's next turn, `build_state_prompt` (the Strands
8490
// state_context_builder) reads this back out of state and prepends a
@@ -90,6 +96,8 @@ function DemoContent() {
9096
notes, // preserve what the agent has written
9197
} as RWAgentState);
9298
};
99+
// @endregion[use-agent-write]
100+
// @endregion[set-state]
93101

94102
// WRITE: let the user clear the agent-authored notes from the UI.
95103
const handleClearNotes = () => {

showcase/integrations/strands/src/app/demos/shared-state-read-write/preferences-card.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ export interface PreferencesCardProps {
3434
* `input_data.state` and prepends it to the user message so the agent's
3535
* reply visibly adapts.
3636
*/
37+
// @region[preferences-card-render]
38+
// Write-side render: every edit here bubbles up through `onChange`, and
39+
// the parent pipes it straight into `agent.setState({ preferences: ... })`.
40+
// Nothing in this component knows about the agent directly — that's
41+
// intentional: the card is a plain controlled form, and the agent state
42+
// wiring lives one layer up.
3743
export function PreferencesCard({ value, onChange }: PreferencesCardProps) {
3844
const set = <K extends keyof Preferences>(key: K, v: Preferences[K]) =>
3945
onChange({ ...value, [key]: v });
@@ -142,3 +148,4 @@ export function PreferencesCard({ value, onChange }: PreferencesCardProps) {
142148
</div>
143149
);
144150
}
151+
// @endregion[preferences-card-render]

showcase/integrations/strands/src/app/demos/subagents/delegation-log.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const STATUS_COLOR: Record<Delegation["status"], string> = {
4848
failed: "text-[#FA5F67]",
4949
};
5050

51+
// @region[delegation-log-frontend]
5152
/**
5253
* Live delegation log — renders the `delegations` slot of agent state.
5354
*
@@ -135,3 +136,4 @@ export function DelegationLog({ delegations, isRunning }: DelegationLogProps) {
135136
</div>
136137
);
137138
}
139+
// @endregion[delegation-log-frontend]

0 commit comments

Comments
 (0)