Skip to content

docs(aimlapi): list AI/ML API in the Popular Providers sidebar #1

docs(aimlapi): list AI/ML API in the Popular Providers sidebar

docs(aimlapi): list AI/ML API in the Popular Providers sidebar #1

# Post a patience comment on PRs from external contributors that add
# integration docs (hosted MDX pages or external listing YAML rows), and
# apply the `integration` label to those PRs.
#
# NOTE: Uses `pull_request_target` so it can comment on PRs from forks.
# The script only reads changed files from the GitHub API and checks org
# membership — no untrusted code is executed.
name: External Integration PR Comment
on:
pull_request_target:
types: [opened, ready_for_review, synchronize]
jobs:
integration-comment:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
if: ${{ !github.event.pull_request.draft }}
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.ORG_MEMBERSHIP_APP_ID }}
private-key: ${{ secrets.ORG_MEMBERSHIP_APP_PRIVATE_KEY }}
- name: Comment on external new integration PRs
uses: actions/github-script@v8
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const { owner, repo } = context.repo;
const pr = context.payload.pull_request;
const author = pr.user.login;
if (pr.user.type === 'Bot') {
console.log(`Skipping bot author ${author}`);
return;
}
const integrationPrefixes = [
'src/oss/python/integrations/',
'src/oss/javascript/integrations/',
];
const externalListingPath = 'scripts/data/integration_external_docs.yaml';
const files = await github.paginate(github.rest.pulls.listFiles, {
owner,
repo,
pull_number: pr.number,
per_page: 100,
});
const newIntegrationFiles = files.filter((file) => {
if (file.status !== 'added') return false;
if (!integrationPrefixes.some((prefix) => file.filename.startsWith(prefix))) {
return false;
}
const basename = file.filename.split('/').pop();
if (basename === 'TEMPLATE.mdx') return false;
return true;
});
const hasExternalListingChange = files.some(
(file) => file.filename === externalListingPath
);
if (newIntegrationFiles.length === 0 && !hasExternalListingChange) {
console.log('No integration contribution files found; skipping');
return;
}
if (newIntegrationFiles.length > 0) {
console.log(
`Found ${newIntegrationFiles.length} new integration file(s): ` +
newIntegrationFiles.map((f) => f.filename).join(', ')
);
}
if (hasExternalListingChange) {
console.log(`Found changes to ${externalListingPath}`);
}
const internalBots = new Set(['open-swe[bot]']);
let isExternal;
if (internalBots.has(author)) {
isExternal = false;
} else {
try {
const membership = await github.rest.orgs.getMembershipForUser({
org: 'langchain-ai',
username: author,
});
isExternal = membership.data.state !== 'active';
} catch (error) {
if (error.status === 404) {
isExternal = true;
} else {
console.error('Error checking membership:', error);
isExternal = true;
}
}
}
if (!isExternal) {
console.log(`Author ${author} is internal; skipping`);
return;
}
const hasIntegrationLabel = pr.labels.some(
(label) => label.name === 'integration'
);
if (hasIntegrationLabel) {
console.log(`PR #${pr.number} already has the integration label; skipping labeling`);
} else {
await github.rest.issues.addLabels({
owner,
repo,
issue_number: pr.number,
labels: ['integration'],
});
console.log(`Added integration label to PR #${pr.number}`);
}
const marker = '<!-- external-integration-contribution -->';
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: pr.number,
per_page: 100,
});
if (comments.some((comment) => comment.body.includes(marker))) {
console.log('Comment already posted; skipping comment');
return;
}
const body = [
marker,
`Thanks for contributing a new integration docs page, @${author}!`,
'',
'As of July 28, 2026, we have changed how we accept external integrations submissions. Please review the [new integration submission process](https://docs.langchain.com/oss/python/contributing/publish-langchain#make-your-integration-discoverable) for more information.',
'',
'We receive a large number of PRs and review them as quickly as we can. Please bear with us as we work through the queue.',
'',
'If you have already tagged a maintainer on this PR, do not tag them again.',
].join('\n');
await github.rest.issues.createComment({
owner,
repo,
issue_number: pr.number,
body,
});
console.log(`Posted external integration comment on PR #${pr.number}`);