diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index aa3c6a8e3..3d9b71a82 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -244,21 +244,27 @@ jobs:
if: ${{ inputs.use_ai_notes }}
shell: bash
env:
- MODELS_TOKEN: ${{ secrets.MODELS_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
python <<'PY'
from pathlib import Path
import json
- import os
prompt = Path(".github/release-artifacts/release-prompt.txt").read_text(encoding="utf-8")
payload = {
- "model": "gpt-5.4",
+ "model": "openai/gpt-5.4",
"messages": [
- {"role": "user", "content": prompt}
- ],
+ {
+ "role": "system",
+ "content": "You write concise, accurate release notes in markdown."
+ },
+ {
+ "role": "user",
+ "content": prompt
+ }
+ ]
}
Path(".github/release-artifacts/openai-payload.json").write_text(
json.dumps(payload, ensure_ascii=False),
@@ -266,11 +272,23 @@ jobs:
)
PY
- curl -fsSL https://models.inference.ai.azure.com/chat/completions \
- -H "Content-Type: application/json" \
- -H "Authorization: Bearer $MODELS_TOKEN" \
- -d @.github/release-artifacts/openai-payload.json \
- > .github/release-artifacts/openai-response.json
+ status_code=$(
+ curl -sS -L \
+ -o .github/release-artifacts/openai-response.json \
+ -w "%{http_code}" \
+ -X POST \
+ -H "Accept: application/vnd.github+json" \
+ -H "Authorization: Bearer $GITHUB_TOKEN" \
+ -H "X-GitHub-Api-Version: 2026-03-10" \
+ -H "Content-Type: application/json" \
+ https://models.github.ai/orgs/dataelement/inference/chat/completions \
+ -d @.github/release-artifacts/openai-payload.json
+ )
+
+ echo "HTTP status: $status_code"
+ cat .github/release-artifacts/openai-response.json
+
+ test "$status_code" -lt 400
python <<'PY'
from pathlib import Path
diff --git a/backend/app/services/trigger_runtime/executions.py b/backend/app/services/trigger_runtime/executions.py
index c25882565..bda34f1c0 100644
--- a/backend/app/services/trigger_runtime/executions.py
+++ b/backend/app/services/trigger_runtime/executions.py
@@ -84,8 +84,10 @@ async def claim_pending_trigger_executions(
claimed_pairs.append((execution, trigger))
await db.commit()
for execution, trigger in claimed_pairs:
- db.expunge(execution)
- db.expunge(trigger)
+ if execution in db:
+ db.expunge(execution)
+ if trigger in db:
+ db.expunge(trigger)
return claimed_pairs
diff --git a/backend/app/services/trigger_runtime/invoker.py b/backend/app/services/trigger_runtime/invoker.py
index 56f29a49d..9c585c8ff 100644
--- a/backend/app/services/trigger_runtime/invoker.py
+++ b/backend/app/services/trigger_runtime/invoker.py
@@ -103,15 +103,21 @@ async def invoke_agent_for_triggers(agent_id: uuid.UUID, triggers: list[AgentTri
result = await db.execute(select(Agent).where(Agent.id == agent_id))
agent = result.scalar_one_or_none()
if not agent or agent.is_expired:
+ if execution_ids:
+ await mark_trigger_executions_failed(execution_ids, "Agent not found or is expired")
return
if not agent.primary_model_id:
logger.warning(f"Agent {agent.name} has no LLM model, skipping trigger invocation")
+ if execution_ids:
+ await mark_trigger_executions_failed(execution_ids, "Agent has no LLM model configured")
return
result = await db.execute(select(LLMModel).where(LLMModel.id == agent.primary_model_id))
model = result.scalar_one_or_none()
if not model or not model.enabled:
logger.warning(f"Agent {agent.name}'s model is unavailable, skipping trigger invocation")
+ if execution_ids:
+ await mark_trigger_executions_failed(execution_ids, "Agent primary model is unavailable or disabled")
return
context_parts = []
diff --git a/frontend/src/components/MarkdownRenderer.tsx b/frontend/src/components/MarkdownRenderer.tsx
index 48f44e6fe..4c38df536 100644
--- a/frontend/src/components/MarkdownRenderer.tsx
+++ b/frontend/src/components/MarkdownRenderer.tsx
@@ -106,10 +106,10 @@ function renderInline(text: string): string {
.replace(/\*\*\*(.*?)\*\*\*/g, '$1')
// Bold
.replace(/\*\*(.*?)\*\*/g, '$1')
- .replace(/__(.*?)__/g, '$1')
+ .replace(/(?$1')
// Italic
.replace(/\*(.*?)\*/g, '$1')
- .replace(/_(.*?)_/g, '$1')
+ .replace(/(?$1')
// Strikethrough
.replace(/~~(.*?)~~/g, '$1');