hooks
strands_teams.hooks ¶
Generic HookProviders for agent guidance, quality control, and display.
Ported from the pre-split code_context_agent.agent.hooks with every domain literal replaced by :class:~strands_teams.usecase.UseCase-supplied data. The eight providers here know nothing about any specific domain: reasoning prompts, shell alternatives, fail-fast exemptions, artifact paths, and the scoring rubric all arrive through constructor parameters (fed by :func:create_all_hooks from a UseCase), so the framework never hardcodes a tool name or artifact scheme.
Uses the stable strands.hooks API (verified against strands-agents 1.47.0):
BeforeInvocationEvent/AfterInvocationEvent— invocation lifecycle.AfterInvocationEvent.resumeis the single writable field (_can_writereturnsTrueonly for"resume"); setting it to a non-Noneagent input triggers a full re-invocation cycle. This mechanism is unchanged from the port source, so :class:ArtifactQualityHookuses it directly (AC-3-3, AC-3-6).BeforeToolCallEvent/AfterToolCallEvent— per-tool hooks.
Display coupling (T-C3 anti-goal)¶
The concrete display state lives in the consumer/display layer (a separate task). To avoid a hard dependency in the wrong direction, :class:ToolDisplayHook and :class:TeamDispatchHook accept any object satisfying the duck-typed :class:TeamDisplayState Protocol (start_team / complete_team / record_tool). The framework never imports the concrete state class.
TeamDisplayState ¶
Bases: Protocol
Duck-typed contract the display hooks require of a display-state object.
The concrete state class lives in the consumer/display layer (a separate task). Depending on this Protocol rather than the concrete class keeps the framework free of a dependency on its own consumer.
FullModeToolError ¶
Bases: RuntimeError
Raised by :class:FailFastHook when a critical tool returns an error.
Source code in packages/strands-teams/src/strands_teams/hooks.py
OutputQualityHook ¶
Bases: HookProvider
Logs a warning when a tool produces unusually large output.
register_hooks ¶
Register the output-quality callback.
ConversationCompactionHook ¶
Bases: HookProvider
Strips large toolUse/toolResult payloads from older conversation history.
After the model has reasoned about tool results, the raw payloads are no longer needed. Before each model invocation this hook replaces large tool payloads in older messages with stubs, keeping all reasoning turns and the most recent messages intact — preventing context overflow without ever truncating data the model has not yet seen.
register_hooks ¶
Register the conversation-compaction callback.
ToolEfficiencyHook ¶
Bases: HookProvider
Warns when shell is used for a task that has a dedicated tool.
The mapping of shell-command substring -> suggested alternative is supplied by the use case (alternatives), so the framework holds no domain literals.
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the tool-efficiency callback.
ReasoningCheckpointHook ¶
Bases: HookProvider
Appends a reasoning-checkpoint prompt to results of mapped analysis tools.
Only tools present in the prompts map (supplied by the use case) get a checkpoint appended; every other tool's result passes through unchanged (AC-3-2). Forces the model to interpret combined signals rather than merely collecting tool outputs.
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the reasoning-checkpoint callback.
FailFastHook ¶
Bases: HookProvider
Raises :class:FullModeToolError when a non-exempt tool errors (full mode).
In full mode, most tool failures should halt the run rather than silently degrade. The exempt tool-name set and exempt name-prefixes both come from the use case (search tools may return no results; external MCP tools may be unavailable), so the framework holds no domain literals (AC-3-4).
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
ArtifactQualityHook ¶
ArtifactQualityHook(
layout,
rubric,
max_passes=2,
resume_template=DEFAULT_RESUME_TEMPLATE,
coverage_resume_template=DEFAULT_COVERAGE_RESUME_TEMPLATE,
)
Bases: HookProvider
Triggers revision passes on weak rubric scores OR uncovered acceptance criteria.
After the coordinator finishes an invocation this hook applies two gates (AC-4-1):
- Rubric. Scores every artifact under
layout.artifacts_dir()(matched bylayout.artifact_glob()) with the sharedrubric.score. An artifact below the rubric's revision threshold is "weak". - Acceptance-criteria coverage. Reads every dispatched team's
acceptance_criteriafrom itscontract.json(written bydispatch_team) and checks each criterion against the corpus of produced artifacts + team findings. A criterion whose significant tokens are mostly absent from that corpus is "uncovered".
If any artifact is weak OR any criterion is uncovered, the run needs revision and event.resume (verified writable on AfterInvocationEvent in strands 1.47.0) is set to re-invoke the coordinator. An uncovered criterion forces a revision regardless of the rubric total (AC-4-2) and the emitted resume prompt names the uncovered criteria (AC-4-3). When all criteria are covered and no artifact is weak, no resume is emitted (AC-4-4). When no acceptance criteria were supplied for the run, the hook falls back to unchanged rubric-only behavior (AC-4-5). The single max_passes budget caps both the rubric- and coverage-driven resumes combined (AC-4-6).
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the artifact-quality callback.
ToolDisplayHook ¶
Bases: HookProvider
Tracks tool calls on a display state for TUI rendering.
Depends on the duck-typed :class:TeamDisplayState Protocol rather than a concrete state class so the framework does not import its own consumer.
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the tool-display callbacks.
Source code in packages/strands-teams/src/strands_teams/hooks.py
TeamDispatchHook ¶
Bases: HookProvider
Tracks dispatch_team tool calls on a display state.
dispatch_team is a framework-level core tool (not a domain literal), so the name is fixed. Depends on the duck-typed :class:TeamDisplayState.
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the team-dispatch callbacks.
Source code in packages/strands-teams/src/strands_teams/hooks.py
JsonLogHook ¶
Bases: HookProvider
Emits one structured JSON log line per tool start/end for --quiet mode.
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the JSON-log callbacks.
Source code in packages/strands-teams/src/strands_teams/hooks.py
PolicyGateDenied ¶
Bases: RuntimeError
Raised by :class:PolicyGateHook to block a denied consequential tool call (AC-6-4).
Source code in packages/strands-teams/src/strands_teams/hooks.py
PolicyGateHook ¶
Bases: HookProvider
Structurally blocks a denied consequential tool call before it runs (AC-6-4, §14.7).
On BeforeToolCallEvent for a tool whose name is in consequential_tools, the hook builds a :class:~strands_teams.models.TransitionRequest from the tool input and the current actor, calls :meth:~strands_teams.policy.PolicyEngine.authorize_transition (reading grants, approvals, findings, and revision hashes from the event's invocation_state by reference — AC-3-7), and raises :class:PolicyGateDenied if the verdict is allowed=False — so the action never executes without a valid revision-bound approval and a clear blocking-finding slate (AC-6-2, AC-6-3). Non-consequential tools pass straight through; the engine is present but, on a run that requests no consequential transitions, is never invoked to deny (AC-7-5).
The transition kind, target revision, and presented tokens are read from the tool input under conventional keys (transition_kind/kind, target_revision_id, presented_tokens, consequential); a use case that names them differently supplies an input_mapper callable.
Wire the gate to a policy engine and the set of consequential tools.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
engine | Any | The :class: | required |
consequential_tools | frozenset[str] | Tool names whose calls are gated. | required |
actor_of | Any | Optional callable mapping | None |
input_mapper | Any | Optional callable | None |
Source code in packages/strands-teams/src/strands_teams/hooks.py
register_hooks ¶
Register the pre-tool authorization callback.
create_all_hooks ¶
create_all_hooks(
use_case,
*,
full_mode=False,
state=None,
quiet=False,
policy_engine=None,
consequential_tools=None,
)
Assemble the hook providers for a run from a UseCase (AC-3-5).
Always includes: :class:ConversationCompactionHook, :class:OutputQualityHook, :class:ToolEfficiencyHook, :class:ReasoningCheckpointHook, and :class:ArtifactQualityHook. Adds :class:FailFastHook iff full_mode. For display: :class:JsonLogHook iff quiet; otherwise :class:ToolDisplayHook + :class:TeamDispatchHook iff state is provided.
The reasoning prompts, fail-fast exempt set, artifact layout, and rubric come from the use-case contract members (reasoning_prompts, fail_fast_exempt, layout, rubric). Two knobs are NOT part of the UseCase contract and are read optionally via getattr so a use case may supply them without the framework requiring them: shell_alternatives (mapping, default empty) and fail_fast_exempt_prefixes (tuple, default empty).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
use_case | Any | The use case supplying reasoning prompts, exemptions, layout, and rubric. | required |
full_mode | bool | If True, include :class: | False |
state | TeamDisplayState | None | A display state (duck-typed :class: | None |
quiet | bool | If True, use :class: | False |
policy_engine | Any | Optional :class: | None |
consequential_tools | frozenset[str] | None | Tool names gated by the policy engine (AC-6-4). | None |
Returns:
| Type | Description |
|---|---|
list[HookProvider] | A flat list of :class: |