Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
bdc893b
[Feat] Update structured output error message (#563)
Unshure Jul 29, 2025
4e0e0a6
feat(mcp): retain structured content in the AgentTool response (#528)
dbschmigelski Jul 29, 2025
b13c5c5
feat(mcp): Add list_prompts, get_prompt methods (#160)
Ketansuhaas Jul 30, 2025
3d526f2
fix(deps): pin a2a-sdk>=0.2.16 to resolve #572 (#581)
minorun365 Jul 31, 2025
b56a4ff
chore: pin a2a to a minor version while it is still in beta (#586)
dbschmigelski Aug 1, 2025
8b1de4d
fix: uses new a2a snake_case for lints to pass (#591)
theagenticguy Aug 1, 2025
c85464c
fix(event_loop): raise dedicated exception when encountering max toke…
dbschmigelski Aug 1, 2025
34d499a
fix(telemetry): added mcp tracing context propagation (#569)
poshinchen Aug 5, 2025
09ca806
Change max_tokens type to int to match Anthropic API (#588)
vinc3m1 Aug 5, 2025
bf24ebf
feat: Add additional intructions for contributors to find issues that…
mehtarac Aug 6, 2025
297ec5c
feat(a2a): configurable request handler (#601)
jer96 Aug 6, 2025
ec5304c
chore(a2a): update host per AppSec recommendation (#619)
jer96 Aug 6, 2025
29b2127
fix(event_loop): ensure tool_use content blocks are valid after max_t…
dbschmigelski Aug 8, 2025
adac26f
fix(structured_output): do not modify conversation_history when promp…
dbschmigelski Aug 8, 2025
99963b6
feature(graph): Allow cyclic graphs (#497)
mkmeral Aug 11, 2025
72709cf
chore: request to include code snippet section (#654)
poshinchen Aug 11, 2025
8434409
feat: Add configuration option to MCP Client for server init timeout …
fhwilton55 Aug 12, 2025
49ff226
fix: Bedrock hang when exception occurs during message conversion (#643)
zastrowm Aug 13, 2025
0455756
feat: add structured_output_span (#655)
poshinchen Aug 13, 2025
1c7257b
litellm - set 1.73.1 as minimum version (#668)
pgrayy Aug 14, 2025
606f657
feat: expose tool_use and agent through ToolContext to decorated tool…
dbschmigelski Aug 14, 2025
8c63d75
session manager - prevent file path injection (#680)
pgrayy Aug 15, 2025
fbd598a
fix: only set signature in message if signature was provided by the m…
clareliguori Aug 18, 2025
ae74aa3
fix: Add openai dependency to sagemaker dependency group (#678)
zastrowm Aug 18, 2025
980a988
Have [all] group reference the other optional dependency groups by na…
zastrowm Aug 18, 2025
b1df148
fix: append blank text content if assistant content is empty (#677)
poshinchen Aug 18, 2025
cfcf93d
feat: add cached token metrics support for Amazon Bedrock (#531)
oaltagar-aws Aug 18, 2025
c087f18
fix: fix non-serializable parameter of agent from toolUse block (#568)
JackYPCOnline Aug 19, 2025
17ccdd2
chore: add .DS_Store to .gitignore (#681)
vawsgit Aug 19, 2025
ef18a25
feat(a2a): support A2A FileParts and DataParts (#596)
jer96 Aug 20, 2025
60dcb45
ci: update pre-commit requirement from <4.2.0,>=3.2.0 to >=3.2.0,<4.4…
dependabot[bot] Aug 20, 2025
b61a064
ci: update ruff requirement from <0.5.0,>=0.4.4 to >=0.4.4,<0.13.0 (#…
dependabot[bot] Aug 21, 2025
93d3ac8
ci: update pytest-asyncio requirement from <0.27.0,>=0.26.0 to >=0.26…
dependabot[bot] Aug 21, 2025
9397f58
fix: add system_prompt to structured_output_span before adding input_…
chengweitsai Aug 21, 2025
6ef6447
feat(multiagent): Add __call__ implementation to MultiAgentBase (#645)
mkmeral Aug 25, 2025
e4879e1
chore: Update pydantic minimum version (#723)
mehtarac Aug 25, 2025
c18ef93
tool executors (#658)
pgrayy Aug 25, 2025
dbe0fea
feat: Add support for agent invoke with no input, or Message input (#…
Unshure Aug 25, 2025
b156ea6
ci: bump actions/checkout from 4 to 5 (#711)
dependabot[bot] Aug 25, 2025
0283169
ci: bump actions/download-artifact from 4 to 5 (#712)
dependabot[bot] Aug 25, 2025
e5e308f
ci: update pytest-cov requirement from <5.0.0,>=4.1.0 to >=4.1.0,<7.0…
dependabot[bot] Aug 25, 2025
918f094
fix: prevent path traversal for message_id in file_session_manager (#…
mehtarac Aug 25, 2025
f028dc9
fix: Add AgentInput TypeAlias (#738)
Unshure Aug 25, 2025
0fac648
fix: Move AgentInput to types submodule (#746)
Unshure Aug 26, 2025
aa03b3d
feat: Implement typed events internally (#745)
zastrowm Aug 27, 2025
d9f8d8a
summarization manager - add summary prompt to messages (#698)
pgrayy Aug 28, 2025
6dadbce
feat: Use TypedEvent inheritance for callback behavior (#755)
zastrowm Aug 28, 2025
47faba0
feat: claude citation support with BedrockModel (#631)
theagenticguy Aug 28, 2025
94b41b4
feat: Enable hooks for MultiAgents (#760)
zastrowm Aug 28, 2025
b008cf5
Add invocation_state to ToolContext (#761)
zastrowm Aug 28, 2025
ae9d5ad
feat(models): Add VPC endpoint support to BedrockModel class (#502)
dbavro19 Aug 29, 2025
7a5caad
fix: fix stop reason for bedrock model when stop_reason (#767)
JackYPCOnline Aug 29, 2025
cb4b7fb
fix: Fix tool result message event (#771)
zastrowm Aug 29, 2025
e7d95d6
fix: fix loading tools with same tool name (#772)
JackYPCOnline Aug 29, 2025
237e188
fix: don't emit ToolStream events for non generator functions (#773)
zastrowm Sep 3, 2025
4dee33b
fix(tests): adjust test_bedrock_guardrails to account for async behav…
dbschmigelski Sep 3, 2025
2db5226
fix(doc): replace invalid Hook names in doc comment with BeforeInvoca…
deepyes02 Sep 3, 2025
1e6d12d
fix: Remove status field from toolResult for non-claude 3 models in B…
mehtarac Sep 4, 2025
ed33868
fix: filter 'SDK_UNKNOWN_MEMBER' from response content (#798)
JackYPCOnline Sep 4, 2025
d07629f
feat: Implement async generator tools (#788)
zastrowm Sep 4, 2025
ec000b8
ci: update openai requirement from <1.100.0 to <1.102.0 (#722)
dependabot[bot] Sep 5, 2025
d77f08b
fix: only add signature to reasoning blocks if signature is provided …
zastrowm Sep 5, 2025
faeb21a
fix: Moved tool_spec retrieval to after the before model invocation c…
pghazanfari Sep 8, 2025
b568864
fix(graph): fix cyclic graph behavior (#768)
mkmeral Sep 8, 2025
8cb53d3
fix(models): filter reasoningContent in Bedrock requests using DeepSe…
aryan835-datainflexion Sep 8, 2025
c142e7a
docs: cleanup docs so the yields section renders correctly (#820)
afarntrog Sep 8, 2025
f185c52
feat: Warn on unknown model configuration properties (#819)
zastrowm Sep 8, 2025
1f27488
fix: do not block asyncio event loop between retries (#805)
osdemah Sep 8, 2025
5420679
feat: improve structured output tool circular reference handling (#817)
afarntrog Sep 8, 2025
6ab1aca
fix(tools/loader): load and register all decorated @tool functions fr…
Ratish1 Sep 9, 2025
d66fcdb
fix(models): patch litellm bug to honor passing in use_litellm_proxy …
dbschmigelski Sep 9, 2025
9213bc5
feat: add default read timeout to Bedrock model (#829)
afarntrog Sep 9, 2025
001aa93
feat: add support for Bedrock/Anthropic ToolChoice to structured_outp…
liushang1997 Sep 10, 2025
7f58ce9
feat(multiagent): allow callers of swarm and graph to pass kwargs to …
dbschmigelski Sep 10, 2025
64d61e0
feat: add region-aware default model ID for Bedrock (#835)
afarntrog Sep 10, 2025
ab125f5
llama.cpp model provider support (#585)
westonbrown Sep 10, 2025
4fbe46a
fix(llama.cpp) - add ToolChoice and validation of model config values…
awsarron Sep 10, 2025
bf4e3e4
feat(telemetry): add cache usage metrics to OpenTelemetry spans (#825)
vamgan Sep 11, 2025
7f77a59
docs: improve docstring formatting for `invoke_async` function in `A…
waitasecant Sep 11, 2025
7d1bdbf
ci: bump actions/setup-python from 5 to 6 (#796)
dependabot[bot] Sep 11, 2025
eace0ec
ci: bump actions/github-script from 7 to 8 (#801)
dependabot[bot] Sep 11, 2025
fe7a700
ci: bump aws-actions/configure-aws-credentials from 4 to 5 (#795)
dependabot[bot] Sep 11, 2025
f12fee8
fix: Add type to tool_input (#854)
Unshure Sep 12, 2025
cbdab32
feat(swarm): Make entry point configurable (#851)
mkmeral Sep 12, 2025
5790a9c
ci: update ruff requirement from <0.13.0,>=0.12.0 to >=0.12.0,<0.14.0…
dependabot[bot] Sep 12, 2025
6a1b2d4
ci: update openai requirement (#827)
dependabot[bot] Sep 12, 2025
066a427
feat: add automated issue auto-close workflows with dry-run testing (…
yonib05 Sep 12, 2025
500d01a
fix: Clean up pyproject.toml (#844)
Unshure Sep 12, 2025
69d3910
Fixing documentation in decorator.py (#852)
prabhuteja12 Sep 12, 2025
6ccc8e7
models - openai - use client context (#856)
pgrayy Sep 15, 2025
8122453
Feature: Handle Bedrock redactedContent (#848)
afarntrog Sep 15, 2025
7226025
fix(telemetry): correctly label tool result messages in OpenTelemetry…
vamgan Sep 15, 2025
4b29edc
models - openai - client context comment (#864)
pgrayy Sep 16, 2025
8805021
fix(test): litellm structured_output test with more descriptive model…
dbschmigelski Sep 16, 2025
03c62f7
fix(mcp): auto cleanup on exceptions occurring in __enter__ (#833)
dbschmigelski Sep 16, 2025
2a5f0f1
fix(mcp): do not verify _background_session is present in stop() (#876)
dbschmigelski Sep 16, 2025
1f25512
docs(readme): fix links and imports, document all model providers (#837)
awsarron Sep 16, 2025
406458d
feat: decouple Strands ContentBlock and BedrockModel (#836)
dbschmigelski Sep 18, 2025
e17772f
fix: add timeout support for MCP tools to resolve long-running tool h…
Unshure Sep 17, 2025
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
7 changes: 4 additions & 3 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ body:
label: Steps to Reproduce
description: Detailed steps to reproduce the behavior
placeholder: |
1. Install Strands using...
2. Run the command...
3. See error...
1. Code Snippet (Minimal reproducible example)
2. Install Strands using...
3. Run the command...
4. See error...
validations:
required: true
- type: textarea
Expand Down
237 changes: 237 additions & 0 deletions .github/workflows/auto-close.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
name: Auto Close Issues

on:
schedule:
- cron: '0 14 * * 1-5' # 9 AM EST (2 PM UTC) Monday through Friday
workflow_dispatch:
inputs:
dry_run:
description: 'Run in dry-run mode (no actions taken, only logging)'
required: false
default: 'false'
type: boolean

jobs:
auto-close:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- label: 'autoclose in 3 days'
days: 3
issue_types: 'issues' #issues/pulls/both
replacement_label: ''
closure_message: 'This issue has been automatically closed as it was marked for auto-closure by the team and no additional responses was received within 3 days.'
dry_run: 'false'
- label: 'autoclose in 7 days'
days: 7
issue_types: 'issues' # issues/pulls/both
replacement_label: ''
closure_message: 'This issue has been automatically closed as it was marked for auto-closure by the team and no additional responses was received within 7 days.'
dry_run: 'false'
steps:
- name: Validate and process ${{ matrix.label }}
uses: actions/github-script@v8
env:
LABEL_NAME: ${{ matrix.label }}
DAYS_TO_WAIT: ${{ matrix.days }}
AUTHORIZED_USERS: ''
AUTH_MODE: 'write-access'
ISSUE_TYPES: ${{ matrix.issue_types }}
DRY_RUN: ${{ matrix.dry_run }}
REPLACEMENT_LABEL: ${{ matrix.replacement_label }}
CLOSE_MESSAGE: ${{matrix.closure_message}}
with:
script: |
const REQUIRED_PERMISSIONS = ['write', 'admin'];
const CLOSE_MESSAGE = process.env.CLOSE_MESSAGE;
const isDryRun = '${{ inputs.dry_run }}' === 'true' || process.env.DRY_RUN === 'true';

const config = {
labelName: process.env.LABEL_NAME,
daysToWait: parseInt(process.env.DAYS_TO_WAIT),
authMode: process.env.AUTH_MODE,
authorizedUsers: process.env.AUTHORIZED_USERS?.split(',').map(u => u.trim()).filter(u => u) || [],
issueTypes: process.env.ISSUE_TYPES,
replacementLabel: process.env.REPLACEMENT_LABEL?.trim() || null
};

console.log(`🏷️ Processing label: "${config.labelName}" (${config.daysToWait} days)`);
if (isDryRun) console.log('🧪 DRY-RUN MODE: No actions will be taken');

const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - config.daysToWait);

async function isAuthorizedUser(username) {
try {
if (config.authMode === 'users') {
return config.authorizedUsers.includes(username);
} else if (config.authMode === 'write-access') {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: username
});
return REQUIRED_PERMISSIONS.includes(data.permission);
}
} catch (error) {
console.log(`⚠️ Failed to check authorization for ${username}: ${error.message}`);
return false;
}
return false;
}

let allIssues = [];
let page = 1;

while (true) {
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: config.labelName,
sort: 'updated',
direction: 'desc',
per_page: 100,
page: page
});

if (issues.length === 0) break;
allIssues = allIssues.concat(issues);
if (issues.length < 100) break;
page++;
}

const targetIssues = allIssues.filter(issue => {
if (config.issueTypes === 'issues' && issue.pull_request) return false;
if (config.issueTypes === 'pulls' && !issue.pull_request) return false;
return true;
});

console.log(`🔍 Found ${targetIssues.length} items with label "${config.labelName}"`);

if (targetIssues.length === 0) {
console.log('✅ No items to process');
return;
}

let closedCount = 0;
let labelRemovedCount = 0;
let skippedCount = 0;

for (const issue of targetIssues) {
console.log(`\n📋 Processing #${issue.number}: ${issue.title}`);

try {
const { data: events } = await github.rest.issues.listEvents({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number
});

const labelEvents = events
.filter(e => e.event === 'labeled' && e.label?.name === config.labelName)
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));

if (labelEvents.length === 0) {
console.log(`⚠️ No label events found for #${issue.number}`);
skippedCount++;
continue;
}

const lastLabelAdded = new Date(labelEvents[0].created_at);
const labelAdder = labelEvents[0].actor.login;

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
since: lastLabelAdded.toISOString()
});

let hasUnauthorizedComment = false;

for (const comment of comments) {
if (comment.user.login === labelAdder) continue;

const isAuthorized = await isAuthorizedUser(comment.user.login);
if (!isAuthorized) {
console.log(`❌ New comment from ${comment.user.login}`);
hasUnauthorizedComment = true;
break;
}
}

if (hasUnauthorizedComment) {
if (isDryRun) {
console.log(`🧪 DRY-RUN: Would remove ${config.labelName} label from #${issue.number}`);
if (config.replacementLabel) {
console.log(`🧪 DRY-RUN: Would add ${config.replacementLabel} label to #${issue.number}`);
}
} else {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: config.labelName
});
console.log(`🏷️ Removed ${config.labelName} label from #${issue.number}`);

if (config.replacementLabel) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: [config.replacementLabel]
});
console.log(`🏷️ Added ${config.replacementLabel} label to #${issue.number}`);
}
}
labelRemovedCount++;
continue;
}

if (lastLabelAdded > cutoffDate) {
const daysRemaining = Math.ceil((lastLabelAdded - cutoffDate) / (1000 * 60 * 60 * 24));
console.log(`⏳ Label added too recently (${daysRemaining} days remaining)`);
skippedCount++;
continue;
}

if (isDryRun) {
console.log(`🧪 DRY-RUN: Would close #${issue.number} with comment`);
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: CLOSE_MESSAGE
});

await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed'
});

console.log(`🔒 Closed #${issue.number}`);
}
closedCount++;
} catch (error) {
console.log(`❌ Error processing #${issue.number}: ${error.message}`);
skippedCount++;
}
}

console.log(`\n📊 Summary for "${config.labelName}":`);
if (isDryRun) {
console.log(` 🧪 DRY-RUN MODE - No actual changes made:`);
console.log(` • Issues that would be closed: ${closedCount}`);
console.log(` • Labels that would be removed: ${labelRemovedCount}`);
} else {
console.log(` • Issues closed: ${closedCount}`);
console.log(` • Labels removed: ${labelRemovedCount}`);
}
console.log(` • Issues skipped: ${skippedCount}`);
console.log(` • Total processed: ${targetIssues.length}`);
8 changes: 4 additions & 4 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
approval-env: ${{ steps.collab-check.outputs.result }}
steps:
- name: Collaborator Check
uses: actions/github-script@v7
uses: actions/github-script@v8
id: collab-check
with:
result-encoding: string
Expand Down Expand Up @@ -46,18 +46,18 @@ jobs:
contents: read
steps:
- name: Configure Credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v5
with:
role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }}
aws-region: us-east-1
mask-aws-account-id: true
- name: Checkout head commit
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
ref: ${{ github.event.pull_request.head.sha }} # Pull the commit from the forked repo
persist-credentials: false # Don't persist credentials for subsequent actions
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.10'
- name: Install dependencies
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pypi-publish-on-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.10'

Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:

steps:
- name: Download all the dists
uses: actions/download-artifact@v4
uses: actions/download-artifact@v5
with:
name: python-package-distributions
path: dist/
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ jobs:
LOG_LEVEL: DEBUG
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }} # Explicitly define which commit to check out
persist-credentials: false # Don't persist credentials for subsequent actions
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand All @@ -73,13 +73,13 @@ jobs:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
ref: ${{ inputs.ref }}
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.10'
cache: 'pip'
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
build
__pycache__*
.coverage*
Expand All @@ -9,4 +10,5 @@ __pycache__*
*.bak
.vscode
dist
repl_state
repl_state
.kiro
9 changes: 1 addition & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ repos:
hooks:
- id: hatch-format
name: Format code
entry: hatch fmt --formatter
entry: hatch run test-format
language: system
pass_filenames: false
types: [python]
Expand All @@ -15,13 +15,6 @@ repos:
pass_filenames: false
types: [python]
stages: [pre-commit]
- id: hatch-test-lint
name: Type linting
entry: hatch run test-lint
language: system
pass_filenames: false
types: [ python ]
stages: [ pre-commit ]
- id: hatch-test
name: Unit tests
entry: hatch test
Expand Down
Loading
Loading