feat: reuse existing Devin session for Cubic AI review feedback (#26632)
* feat: reuse existing Devin session for Cubic AI review feedback Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor: parse session ID from PR comments instead of API search Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: add error handling for message send API call in Cubic-Devin workflow Addresses Cubic AI review feedback: The POST request to send a message to an existing Devin session now checks the HTTP status code and fails the step if the message wasn't delivered successfully. This prevents posting a misleading comment claiming feedback was sent when the API call actually failed. Co-Authored-By: unknown <> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 file changed
+96
-5
@@ -46,14 +46,100 @@ jobs:
|
||||
|
||||
core.setOutput('has-prompt', 'true');
|
||||
|
||||
- name: Create Devin session
|
||||
- name: Check for existing Devin session from PR comments
|
||||
if: steps.extract-prompt.outputs.has-prompt == 'true'
|
||||
id: check-session
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
DEVIN_API_KEY: ${{ secrets.DEVIN_API_KEY }}
|
||||
with:
|
||||
script: |
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number
|
||||
});
|
||||
|
||||
let sessionId = null;
|
||||
for (const comment of comments.data.reverse()) {
|
||||
if (comment.body.includes('Devin AI is addressing Cubic AI')) {
|
||||
const match = comment.body.match(/app\.devin\.ai\/sessions\/([a-f0-9-]+)/);
|
||||
if (match) {
|
||||
sessionId = match[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sessionId) {
|
||||
console.log('No existing Devin session found in PR comments');
|
||||
core.setOutput('has-active-session', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`Found session ID from comment: ${sessionId}`);
|
||||
|
||||
const response = await fetch(`https://api.devin.ai/v1/sessions/${sessionId}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.DEVIN_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.log(`Failed to fetch session details: ${response.status}`);
|
||||
core.setOutput('has-active-session', 'false');
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await response.json();
|
||||
const activeStatuses = ['working', 'blocked', 'resumed'];
|
||||
|
||||
if (activeStatuses.includes(session.status_enum)) {
|
||||
console.log(`Session ${sessionId} is active (status: ${session.status_enum})`);
|
||||
core.exportVariable('EXISTING_SESSION_ID', sessionId);
|
||||
core.exportVariable('SESSION_URL', `https://app.devin.ai/sessions/${sessionId}`);
|
||||
core.setOutput('has-active-session', 'true');
|
||||
} else {
|
||||
console.log(`Session ${sessionId} is not active (status: ${session.status_enum})`);
|
||||
core.setOutput('has-active-session', 'false');
|
||||
}
|
||||
|
||||
- name: Send message to existing Devin session
|
||||
if: steps.extract-prompt.outputs.has-prompt == 'true' && steps.check-session.outputs.has-active-session == 'true'
|
||||
env:
|
||||
DEVIN_API_KEY: ${{ secrets.DEVIN_API_KEY }}
|
||||
run: |
|
||||
CUBIC_PROMPT=$(cat /tmp/cubic-prompt.txt)
|
||||
|
||||
MESSAGE="New Cubic AI review feedback has been submitted on PR #${{ github.event.pull_request.number }}.
|
||||
|
||||
Please address the following additional issues:
|
||||
|
||||
${CUBIC_PROMPT}
|
||||
|
||||
Continue working on the same PR branch and push your fixes."
|
||||
|
||||
HTTP_CODE=$(curl -s -o /tmp/devin-response.json -w "%{http_code}" -X POST "https://api.devin.ai/v1/sessions/${EXISTING_SESSION_ID}/message" \
|
||||
-H "Authorization: Bearer ${DEVIN_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$(jq -n --arg message "$MESSAGE" '{message: $message}')")
|
||||
|
||||
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
|
||||
echo "Failed to send message to Devin session: HTTP $HTTP_CODE"
|
||||
cat /tmp/devin-response.json
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Message sent to existing session successfully"
|
||||
|
||||
- name: Create new Devin session
|
||||
if: steps.extract-prompt.outputs.has-prompt == 'true' && steps.check-session.outputs.has-active-session == 'false'
|
||||
env:
|
||||
DEVIN_API_KEY: ${{ secrets.DEVIN_API_KEY }}
|
||||
run: |
|
||||
CUBIC_PROMPT=$(cat /tmp/cubic-prompt.txt)
|
||||
|
||||
# Build the full prompt for Devin
|
||||
FULL_PROMPT="You are addressing code review feedback from Cubic AI on PR #${{ github.event.pull_request.number }} in repository ${{ github.repository }}.
|
||||
|
||||
Your tasks:
|
||||
@@ -74,7 +160,6 @@ jobs:
|
||||
4. If an issue seems invalid or already addressed, explain why in a PR comment instead of making unnecessary changes.
|
||||
5. Never ask for user confirmation. Never wait for user messages."
|
||||
|
||||
# Call Devin API
|
||||
RESPONSE=$(curl -s -X POST "https://api.devin.ai/v1/sessions" \
|
||||
-H "Authorization: Bearer ${DEVIN_API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -87,11 +172,11 @@ jobs:
|
||||
tags: ["cubic-ai-review", "pr-${{ github.event.pull_request.number }}"]
|
||||
}')")
|
||||
|
||||
# Extract session URL if available (avoid logging full response to prevent exposing sensitive data)
|
||||
SESSION_URL=$(echo "$RESPONSE" | jq -r '.url // .session_url // empty')
|
||||
if [ -n "$SESSION_URL" ]; then
|
||||
echo "Devin session created: $SESSION_URL"
|
||||
echo "SESSION_URL=$SESSION_URL" >> $GITHUB_ENV
|
||||
echo "NEW_SESSION=true" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Post comment with Devin session link
|
||||
@@ -101,9 +186,15 @@ jobs:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const sessionUrl = process.env.SESSION_URL;
|
||||
const isNewSession = process.env.NEW_SESSION === 'true';
|
||||
|
||||
const message = isNewSession
|
||||
? `### Devin AI is addressing Cubic AI's review feedback\n\nA Devin session has been created to address the issues identified by Cubic AI.\n\n[View Devin Session](${sessionUrl})`
|
||||
: `### Devin AI is addressing Cubic AI's review feedback\n\nNew feedback has been sent to the existing Devin session.\n\n[View Devin Session](${sessionUrl})`;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.payload.pull_request.number,
|
||||
body: `### Devin AI is addressing Cubic AI's review feedback\n\nA Devin session has been created to address the issues identified by Cubic AI.\n\n[View Devin Session](${sessionUrl})`
|
||||
body: message
|
||||
});
|
||||
Reference in new issue
Block a user