Skip to content

[Bug]: OLLAMA_ADD_FAILED (fp: 4ebb535d) #394

[Bug]: OLLAMA_ADD_FAILED (fp: 4ebb535d)

[Bug]: OLLAMA_ADD_FAILED (fp: 4ebb535d) #394

name: Issue Auto Response
on:
issues:
types: [opened, labeled]
issue_comment:
types: [created]
concurrency:
group: issue-auto-response-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
contents: read
jobs:
auto-response:
if: |
!github.event.issue.pull_request &&
!endsWith(github.actor, '[bot]') &&
!contains(github.event.issue.labels.*.name, 'duplicate') &&
!contains(github.event.issue.labels.*.name, 'spam') &&
!contains(github.event.issue.labels.*.name, 'bot-skip') &&
vars.CODEX_BOT_ENABLED == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- name: Check bot response state
id: check_bot
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
const marker = "*Open-CoDesign Bot*";
const allowedLogins = (process.env.BOT_LOGINS || "github-actions[bot]")
.split(",").map((v) => v.trim()).filter(Boolean);
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100
}
);
const botComments = comments
.filter((c) => {
if (!(c?.body || "").includes(marker)) return false;
const u = c.user;
if (!u || u.type !== "Bot") return false;
return allowedLogins.includes(u.login);
})
.sort((a, b) => new Date(b.created_at || 0) - new Date(a.created_at || 0));
const latestBot = botComments[0] || null;
let shouldRespond = false;
let reason = "unhandled event";
if (context.eventName === "issues") {
const body = (context.payload.issue?.body || "").trim();
const labelName = context.payload.label?.name || "";
const forceRerun = labelName === "bot-rerun";
shouldRespond = Boolean(body) && (!latestBot || forceRerun);
reason = !body
? "skip empty issue body"
: shouldRespond
? forceRerun
? "forced issue bot rerun"
: "new issue without bot response"
: "issue already has bot response";
} else if (context.eventName === "issue_comment") {
const comment = context.payload.comment;
const author = comment?.user;
const isBotComment =
author?.type === "Bot" ||
(author?.login || "").endsWith("[bot]");
const body = (comment?.body || "").trim();
if (isBotComment) {
reason = "skip bot comment";
} else if (!body) {
reason = "skip empty comment";
} else if (!latestBot) {
shouldRespond = true;
reason = "human comment without prior bot response";
} else {
const commentTime = new Date(comment.created_at || 0).getTime();
const botTime = new Date(latestBot.created_at || 0).getTime();
shouldRespond = commentTime > botTime;
reason = shouldRespond
? "human follow-up after bot response"
: "comment is not newer than latest bot response";
}
}
core.info(`Issue bot response decision: ${shouldRespond ? "run" : "skip"} (${reason})`);
core.setOutput("should_respond", shouldRespond ? "true" : "false");
core.setOutput("reason", reason);
core.setOutput("latest_bot_comment_id", latestBot ? String(latestBot.id) : "");
env:
BOT_LOGINS: ${{ vars.BOT_LOGINS }}
- name: Checkout repository
if: steps.check_bot.outputs.should_respond == 'true'
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Resolve issue provider config
if: steps.check_bot.outputs.should_respond == 'true'
id: issue_config
shell: bash
env:
DEFAULT_API_KEY: ${{ secrets.OPENAI_API_KEY }}
DEFAULT_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
DEFAULT_MODEL: ${{ vars.OPENAI_MODEL }}
DEFAULT_EFFORT: ${{ vars.OPENAI_EFFORT }}
REVIEW_API_KEY: ${{ secrets.REVIEW_OPENAI_API_KEY }}
REVIEW_BASE_URL: ${{ secrets.REVIEW_OPENAI_BASE_URL }}
REVIEW_MODEL: ${{ vars.REVIEW_OPENAI_MODEL }}
REVIEW_EFFORT: ${{ vars.REVIEW_OPENAI_EFFORT }}
run: |
api_key="$REVIEW_API_KEY"
[ -n "$api_key" ] || api_key="$DEFAULT_API_KEY"
base_url="$REVIEW_BASE_URL"
[ -n "$base_url" ] || base_url="$DEFAULT_BASE_URL"
model="$REVIEW_MODEL"
[ -n "$model" ] || model="$DEFAULT_MODEL"
effort="$REVIEW_EFFORT"
[ -n "$effort" ] || effort="$DEFAULT_EFFORT"
[ -n "$model" ] || model='gpt-5.4'
[ -n "$effort" ] || effort='high'
is_deepseek='false'
case "$base_url" in
*api.deepseek.com*)
is_deepseek='true'
;;
esac
{
echo "api_key=$api_key"
echo "base_url=$base_url"
echo "model=$model"
echo "effort=$effort"
echo "is_deepseek=$is_deepseek"
} >> "$GITHUB_OUTPUT"
- name: Set up Node.js for DeepSeek issue response
if: steps.check_bot.outputs.should_respond == 'true' && steps.issue_config.outputs.is_deepseek == 'true'
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "20"
- name: Run DeepSeek for Issue Auto Response
if: steps.check_bot.outputs.should_respond == 'true' && steps.issue_config.outputs.is_deepseek == 'true'
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
DEEPSEEK_API_KEY: ${{ steps.issue_config.outputs.api_key }}
DEEPSEEK_BASE_URL: ${{ steps.issue_config.outputs.base_url }}
DEEPSEEK_MODEL: ${{ steps.issue_config.outputs.model }}
DEEPSEEK_EFFORT: ${{ steps.issue_config.outputs.effort }}
run: node .github/scripts/deepseek-issue-response.mjs
- name: Run Codex for Issue Auto Response
if: steps.check_bot.outputs.should_respond == 'true' && steps.issue_config.outputs.is_deepseek != 'true'
uses: openai/codex-action@e0fdf01220eb9a88167c4898839d273e3f2609d1 # v1
env:
GH_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ github.token }}
with:
openai-api-key: ${{ steps.issue_config.outputs.api_key }}
responses-api-endpoint: ${{ steps.issue_config.outputs.base_url }}
model: ${{ steps.issue_config.outputs.model }}
effort: ${{ steps.issue_config.outputs.effort }}
sandbox: danger-full-access
safety-strategy: drop-sudo
prompt-file: .github/prompts/issue-auto-response.md
allow-bots: true
allow-users: '*'