Skip to content

Commit 83beef7

Browse files
committed
resolve: merge upstream changes and resolve conflicts
- Resolve conflicts in pyproject.toml, multiagent files, and tests - Accept upstream changes for better compatibility - Maintain existing functionality while incorporating latest updates - Addresses PR strands-agents#927 conflict resolution
2 parents 54f186e + eef11cc commit 83beef7

File tree

95 files changed

+7728
-994
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+7728
-994
lines changed

.github/workflows/auto-close.yml

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
name: Auto Close Issues
2+
3+
on:
4+
schedule:
5+
- cron: '0 14 * * 1-5' # 9 AM EST (2 PM UTC) Monday through Friday
6+
workflow_dispatch:
7+
inputs:
8+
dry_run:
9+
description: 'Run in dry-run mode (no actions taken, only logging)'
10+
required: false
11+
default: 'false'
12+
type: boolean
13+
14+
permissions:
15+
contents: read
16+
issues: write
17+
pull-requests: write
18+
19+
jobs:
20+
auto-close:
21+
runs-on: ubuntu-latest
22+
strategy:
23+
matrix:
24+
include:
25+
- label: 'autoclose in 3 days'
26+
days: 3
27+
issue_types: 'issues' #issues/pulls/both
28+
replacement_label: ''
29+
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.'
30+
dry_run: 'false'
31+
- label: 'autoclose in 7 days'
32+
days: 7
33+
issue_types: 'issues' # issues/pulls/both
34+
replacement_label: ''
35+
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.'
36+
dry_run: 'false'
37+
steps:
38+
- name: Validate and process ${{ matrix.label }}
39+
uses: actions/github-script@v8
40+
env:
41+
LABEL_NAME: ${{ matrix.label }}
42+
DAYS_TO_WAIT: ${{ matrix.days }}
43+
AUTHORIZED_USERS: ''
44+
AUTH_MODE: 'write-access'
45+
ISSUE_TYPES: ${{ matrix.issue_types }}
46+
DRY_RUN: ${{ matrix.dry_run }}
47+
REPLACEMENT_LABEL: ${{ matrix.replacement_label }}
48+
CLOSE_MESSAGE: ${{matrix.closure_message}}
49+
with:
50+
script: |
51+
const REQUIRED_PERMISSIONS = ['write', 'admin'];
52+
const CLOSE_MESSAGE = process.env.CLOSE_MESSAGE;
53+
const isDryRun = '${{ inputs.dry_run }}' === 'true' || process.env.DRY_RUN === 'true';
54+
55+
const config = {
56+
labelName: process.env.LABEL_NAME,
57+
daysToWait: parseInt(process.env.DAYS_TO_WAIT),
58+
authMode: process.env.AUTH_MODE,
59+
authorizedUsers: process.env.AUTHORIZED_USERS?.split(',').map(u => u.trim()).filter(u => u) || [],
60+
issueTypes: process.env.ISSUE_TYPES,
61+
replacementLabel: process.env.REPLACEMENT_LABEL?.trim() || null
62+
};
63+
64+
console.log(`🏷️ Processing label: "${config.labelName}" (${config.daysToWait} days)`);
65+
if (isDryRun) console.log('🧪 DRY-RUN MODE: No actions will be taken');
66+
67+
const cutoffDate = new Date();
68+
cutoffDate.setDate(cutoffDate.getDate() - config.daysToWait);
69+
70+
async function isAuthorizedUser(username) {
71+
try {
72+
if (config.authMode === 'users') {
73+
return config.authorizedUsers.includes(username);
74+
} else if (config.authMode === 'write-access') {
75+
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
76+
owner: context.repo.owner,
77+
repo: context.repo.repo,
78+
username: username
79+
});
80+
return REQUIRED_PERMISSIONS.includes(data.permission);
81+
}
82+
} catch (error) {
83+
console.log(`⚠️ Failed to check authorization for ${username}: ${error.message}`);
84+
return false;
85+
}
86+
return false;
87+
}
88+
89+
let allIssues = [];
90+
let page = 1;
91+
92+
while (true) {
93+
const { data: issues } = await github.rest.issues.listForRepo({
94+
owner: context.repo.owner,
95+
repo: context.repo.repo,
96+
state: 'open',
97+
labels: config.labelName,
98+
sort: 'updated',
99+
direction: 'desc',
100+
per_page: 100,
101+
page: page
102+
});
103+
104+
if (issues.length === 0) break;
105+
allIssues = allIssues.concat(issues);
106+
if (issues.length < 100) break;
107+
page++;
108+
}
109+
110+
const targetIssues = allIssues.filter(issue => {
111+
if (config.issueTypes === 'issues' && issue.pull_request) return false;
112+
if (config.issueTypes === 'pulls' && !issue.pull_request) return false;
113+
return true;
114+
});
115+
116+
console.log(`🔍 Found ${targetIssues.length} items with label "${config.labelName}"`);
117+
118+
if (targetIssues.length === 0) {
119+
console.log('✅ No items to process');
120+
return;
121+
}
122+
123+
let closedCount = 0;
124+
let labelRemovedCount = 0;
125+
let skippedCount = 0;
126+
127+
for (const issue of targetIssues) {
128+
console.log(`\n📋 Processing #${issue.number}: ${issue.title}`);
129+
130+
try {
131+
const { data: events } = await github.rest.issues.listEvents({
132+
owner: context.repo.owner,
133+
repo: context.repo.repo,
134+
issue_number: issue.number
135+
});
136+
137+
const labelEvents = events
138+
.filter(e => e.event === 'labeled' && e.label?.name === config.labelName)
139+
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
140+
141+
if (labelEvents.length === 0) {
142+
console.log(`⚠️ No label events found for #${issue.number}`);
143+
skippedCount++;
144+
continue;
145+
}
146+
147+
const lastLabelAdded = new Date(labelEvents[0].created_at);
148+
const labelAdder = labelEvents[0].actor.login;
149+
150+
const { data: comments } = await github.rest.issues.listComments({
151+
owner: context.repo.owner,
152+
repo: context.repo.repo,
153+
issue_number: issue.number,
154+
since: lastLabelAdded.toISOString()
155+
});
156+
157+
let hasUnauthorizedComment = false;
158+
159+
for (const comment of comments) {
160+
if (comment.user.login === labelAdder) continue;
161+
162+
const isAuthorized = await isAuthorizedUser(comment.user.login);
163+
if (!isAuthorized) {
164+
console.log(`❌ New comment from ${comment.user.login}`);
165+
hasUnauthorizedComment = true;
166+
break;
167+
}
168+
}
169+
170+
if (hasUnauthorizedComment) {
171+
if (isDryRun) {
172+
console.log(`🧪 DRY-RUN: Would remove ${config.labelName} label from #${issue.number}`);
173+
if (config.replacementLabel) {
174+
console.log(`🧪 DRY-RUN: Would add ${config.replacementLabel} label to #${issue.number}`);
175+
}
176+
} else {
177+
await github.rest.issues.removeLabel({
178+
owner: context.repo.owner,
179+
repo: context.repo.repo,
180+
issue_number: issue.number,
181+
name: config.labelName
182+
});
183+
console.log(`🏷️ Removed ${config.labelName} label from #${issue.number}`);
184+
185+
if (config.replacementLabel) {
186+
await github.rest.issues.addLabels({
187+
owner: context.repo.owner,
188+
repo: context.repo.repo,
189+
issue_number: issue.number,
190+
labels: [config.replacementLabel]
191+
});
192+
console.log(`🏷️ Added ${config.replacementLabel} label to #${issue.number}`);
193+
}
194+
}
195+
labelRemovedCount++;
196+
continue;
197+
}
198+
199+
if (lastLabelAdded > cutoffDate) {
200+
const daysRemaining = Math.ceil((lastLabelAdded - cutoffDate) / (1000 * 60 * 60 * 24));
201+
console.log(`⏳ Label added too recently (${daysRemaining} days remaining)`);
202+
skippedCount++;
203+
continue;
204+
}
205+
206+
if (isDryRun) {
207+
console.log(`🧪 DRY-RUN: Would close #${issue.number} with comment`);
208+
} else {
209+
await github.rest.issues.createComment({
210+
owner: context.repo.owner,
211+
repo: context.repo.repo,
212+
issue_number: issue.number,
213+
body: CLOSE_MESSAGE
214+
});
215+
216+
await github.rest.issues.update({
217+
owner: context.repo.owner,
218+
repo: context.repo.repo,
219+
issue_number: issue.number,
220+
state: 'closed'
221+
});
222+
223+
console.log(`🔒 Closed #${issue.number}`);
224+
}
225+
closedCount++;
226+
} catch (error) {
227+
console.log(`❌ Error processing #${issue.number}: ${error.message}`);
228+
skippedCount++;
229+
}
230+
}
231+
232+
console.log(`\n📊 Summary for "${config.labelName}":`);
233+
if (isDryRun) {
234+
console.log(` 🧪 DRY-RUN MODE - No actual changes made:`);
235+
console.log(` • Issues that would be closed: ${closedCount}`);
236+
console.log(` • Labels that would be removed: ${labelRemovedCount}`);
237+
} else {
238+
console.log(` • Issues closed: ${closedCount}`);
239+
console.log(` • Labels removed: ${labelRemovedCount}`);
240+
}
241+
console.log(` • Issues skipped: ${skippedCount}`);
242+
console.log(` • Total processed: ${targetIssues.length}`);

.github/workflows/integration-test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
approval-env: ${{ steps.collab-check.outputs.result }}
1313
steps:
1414
- name: Collaborator Check
15-
uses: actions/github-script@v7
15+
uses: actions/github-script@v8
1616
id: collab-check
1717
with:
1818
result-encoding: string
@@ -46,7 +46,7 @@ jobs:
4646
contents: read
4747
steps:
4848
- name: Configure Credentials
49-
uses: aws-actions/configure-aws-credentials@v4
49+
uses: aws-actions/configure-aws-credentials@v5
5050
with:
5151
role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }}
5252
aws-region: us-east-1
@@ -57,7 +57,7 @@ jobs:
5757
ref: ${{ github.event.pull_request.head.sha }} # Pull the commit from the forked repo
5858
persist-credentials: false # Don't persist credentials for subsequent actions
5959
- name: Set up Python
60-
uses: actions/setup-python@v5
60+
uses: actions/setup-python@v6
6161
with:
6262
python-version: '3.10'
6363
- name: Install dependencies

.github/workflows/pypi-publish-on-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
persist-credentials: false
2828

2929
- name: Set up Python
30-
uses: actions/setup-python@v5
30+
uses: actions/setup-python@v6
3131
with:
3232
python-version: '3.10'
3333

.github/workflows/test-lint.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
ref: ${{ inputs.ref }} # Explicitly define which commit to check out
5757
persist-credentials: false # Don't persist credentials for subsequent actions
5858
- name: Set up Python
59-
uses: actions/setup-python@v5
59+
uses: actions/setup-python@v6
6060
with:
6161
python-version: ${{ matrix.python-version }}
6262
- name: Install dependencies
@@ -79,7 +79,7 @@ jobs:
7979
persist-credentials: false
8080

8181
- name: Set up Python
82-
uses: actions/setup-python@v5
82+
uses: actions/setup-python@v6
8383
with:
8484
python-version: '3.10'
8585
cache: 'pip'
@@ -90,5 +90,5 @@ jobs:
9090
9191
- name: Run lint
9292
id: lint
93-
run: hatch run test-lint
93+
run: hatch fmt --linter --check
9494
continue-on-error: false

.pre-commit-config.yaml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,18 @@ repos:
33
hooks:
44
- id: hatch-format
55
name: Format code
6-
entry: hatch fmt --formatter
6+
entry: hatch fmt --formatter --check
77
language: system
88
pass_filenames: false
99
types: [python]
1010
stages: [pre-commit]
1111
- id: hatch-lint
1212
name: Lint code
13-
entry: hatch run test-lint
13+
entry: hatch fmt --linter --check
1414
language: system
1515
pass_filenames: false
1616
types: [python]
1717
stages: [pre-commit]
18-
- id: hatch-test-lint
19-
name: Type linting
20-
entry: hatch run test-lint
21-
language: system
22-
pass_filenames: false
23-
types: [ python ]
24-
stages: [ pre-commit ]
2518
- id: hatch-test
2619
name: Unit tests
2720
entry: hatch test

CONTRIBUTING.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,7 @@ This project uses [hatchling](https://hatch.pypa.io/latest/build/#hatchling) as
4444

4545
1. Entering virtual environment using `hatch` (recommended), then launch your IDE in the new shell.
4646
```bash
47-
hatch shell dev
48-
```
49-
50-
Alternatively, install development dependencies in a manually created virtual environment:
51-
```bash
52-
pip install -e ".[all]"
47+
hatch shell
5348
```
5449

5550

@@ -73,6 +68,10 @@ This project uses [hatchling](https://hatch.pypa.io/latest/build/#hatchling) as
7368
```bash
7469
hatch test
7570
```
71+
Or run them with coverage:
72+
```bash
73+
hatch test -c
74+
```
7675

7776
6. Run integration tests:
7877
```bash

0 commit comments

Comments
 (0)