mirror of
https://github.com/MervinPraison/PraisonAIUI.git
synced 2026-11-07 05:56:17 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3e7731547 |
No files matched your search
@@ -0,0 +1,86 @@
|
||||
name: Auto Issue Comment
|
||||
|
||||
# Optional: automatically escalate every new issue to Claude for a full
|
||||
# investigation + draft fix. Disabled by default (only workflow_dispatch).
|
||||
# To enable auto-triage on every new issue, uncomment the `issues:` trigger.
|
||||
#
|
||||
# Note: `@claude` mentions only trigger claude.yml when the commenter is a
|
||||
# HUMAN user (or github-actions[bot] via PAT). This workflow posts the
|
||||
# comment as github-actions[bot], so claude.yml must allow that bot.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
issue_number:
|
||||
description: "Issue number to triage with Claude"
|
||||
required: true
|
||||
type: number
|
||||
# issues:
|
||||
# types: [opened]
|
||||
|
||||
jobs:
|
||||
# Escalate an issue to full Claude implementation by adding the `claude`
|
||||
# label. claude.yml listens on `issues:labeled` + label=='claude' and
|
||||
# triggers Job 2 (claude-response) which does the actual work.
|
||||
trigger-claude:
|
||||
if: |
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'issues' && !contains(toJSON(github.event.issue.labels), 'claude'))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: Resolve issue number
|
||||
id: resolve
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
echo "number=${{ inputs.issue_number }}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Add claude label + post instructions
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const issueNumber = Number('${{ steps.resolve.outputs.number }}');
|
||||
const { data: issue } = await github.rest.issues.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
|
||||
const labels = (issue.labels || []).map(l => typeof l === 'string' ? l : l.name);
|
||||
if (labels.includes('claude')) {
|
||||
console.log(`Issue #${issueNumber} already has 'claude' label — skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
labels: ['claude'],
|
||||
});
|
||||
|
||||
const body = [
|
||||
'🤖 Auto-triaging with Claude.',
|
||||
'',
|
||||
'Claude will:',
|
||||
'',
|
||||
'1. Read this issue and all comments.',
|
||||
'2. Classify and route to the right area (`src/praisonaiui/`, `src/frontend/`, `docs/`, or external repo).',
|
||||
'3. Implement a minimal fix per `AGENTS.md`.',
|
||||
'4. Run `pytest` + the import-time invariant locally.',
|
||||
'5. Open a draft PR linked to this issue.',
|
||||
'',
|
||||
'Follow-ups in this thread with `@claude` will re-trigger the loop.'
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issueNumber,
|
||||
body,
|
||||
});
|
||||
+225
-27
@@ -1,8 +1,26 @@
|
||||
name: Claude Assistant
|
||||
|
||||
# Triggers:
|
||||
# - issues:opened → lightweight triage (welcome comment + label)
|
||||
# - issues:labeled → full implementation when `claude` label applied
|
||||
# - issues:assigned → full implementation when issue assigned to Claude
|
||||
# - issue_comment → full implementation when @claude mentioned (issues + PRs)
|
||||
# - pull_request_review → full implementation when @claude mentioned in review
|
||||
# - pull_request_review_comment → full implementation when @claude mentioned inline
|
||||
#
|
||||
# Focus: CLAUDE only. Copilot and CodeRabbit are GitHub Apps that react to PRs
|
||||
# automatically — no workflow file needed. auto-pr-comment.yml orchestrates the
|
||||
# CodeRabbit → Copilot → Claude review chain for PRs.
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, labeled, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -12,15 +30,74 @@ permissions:
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
# ================================================================
|
||||
# Job 1 — Issue triage (runs on ANY new issue, including from external users)
|
||||
# Posts a welcome comment. Does NOT execute Claude Code.
|
||||
# To escalate to full implementation, a maintainer adds the `claude` label
|
||||
# or mentions @claude in a comment — which triggers Job 2.
|
||||
# ================================================================
|
||||
issue-triage:
|
||||
if: |
|
||||
github.event_name == 'issues' &&
|
||||
github.event.action == 'opened' &&
|
||||
!contains(toJSON(github.event.issue.labels), 'claude')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Post welcome comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const body = [
|
||||
'👋 Thanks for opening an issue in **PraisonAIUI**.',
|
||||
'',
|
||||
'A maintainer will triage this shortly. If you would like Claude to investigate and draft a fix, a maintainer can:',
|
||||
'',
|
||||
'- Apply the `claude` label to this issue, **or**',
|
||||
'- Mention `@claude` in a comment with any additional instructions.',
|
||||
'',
|
||||
'Please make sure your issue includes:',
|
||||
'',
|
||||
'1. A clear description of the behaviour you expect vs what you see.',
|
||||
'2. Minimal reproduction steps (code snippet or `aiui.template.yaml`).',
|
||||
'3. Version: `python -c "import praisonaiui; print(praisonaiui.__version__)"`.',
|
||||
'4. Any relevant log output.',
|
||||
'',
|
||||
'See [AGENTS.md](https://github.com/MervinPraison/PraisonAIUI/blob/main/AGENTS.md) for project conventions.'
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body
|
||||
});
|
||||
|
||||
# ================================================================
|
||||
# Job 2 — Full Claude Code implementation
|
||||
# Runs when:
|
||||
# - A comment containing `@claude` is posted on an issue or PR
|
||||
# - The `claude` label is added to an issue
|
||||
# - The issue is assigned to a Claude bot
|
||||
# - A PR review or review-comment contains `@claude`
|
||||
# ================================================================
|
||||
claude-response:
|
||||
env:
|
||||
ISSUE_NUMBER_RESOLVED: ${{ github.event.issue.number }}
|
||||
ISSUE_NUMBER_RESOLVED: ${{ github.event.issue.number || github.event.pull_request.number }}
|
||||
if: |
|
||||
github.event_name == 'issue_comment' &&
|
||||
contains(github.event.comment.body, '@claude') &&
|
||||
github.actor != 'dependabot[bot]' &&
|
||||
github.actor != 'cursor[bot]' &&
|
||||
github.actor != 'renovate[bot]'
|
||||
github.actor != 'renovate[bot]' &&
|
||||
(
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||
(github.event_name == 'issues' && github.event.action == 'labeled' && contains(toJSON(github.event.label), 'claude')) ||
|
||||
(github.event_name == 'issues' && github.event.action == 'assigned')
|
||||
)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -42,46 +119,167 @@ jobs:
|
||||
allowed_bots: "praisonai-triage-agent[bot]"
|
||||
timeout_minutes: "30"
|
||||
direct_prompt: |
|
||||
You are implementing changes in MervinPraison/PraisonAIUI (Server-Driven UI). Follow AGENTS.md in this repository.
|
||||
You are implementing changes in **MervinPraison/PraisonAIUI** (YAML-driven server-driven UI with agentic chat).
|
||||
Follow `AGENTS.md` at the repository root. If a conflict arises between this prompt and `AGENTS.md`, `AGENTS.md` wins.
|
||||
|
||||
Primary scope: src/praisonaiui/, tests/, docs/. If the fix belongs in praisonaiagents, praisonai, or PraisonAI-Tools, route there and explain — do not implement SDK/tool code inside this repo unless it is AIUI integration only.
|
||||
|
||||
STEP 0 — GIT & GITHUB CLI:
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 0 — GIT & GITHUB CLI
|
||||
═══════════════════════════════════════════════════════════════
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
gh auth setup-git
|
||||
|
||||
STEP 1 — ISSUE:
|
||||
Read the issue and all comments. Implement what the issue describes with minimal, focused changes.
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 1 — READ GUIDELINES
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Read `AGENTS.md` and any `docs/principles.md`. Key invariants:
|
||||
• Cold import of `praisonaiui` must stay under 200 ms; module count must not grow.
|
||||
• Heavy / optional deps (`mcp`, `langchain`, `llama_index`, `semantic_kernel`,
|
||||
`slack_sdk`, `discord.py`, `botbuilder.core`, `openai`, `anthropic`, `mistralai`,
|
||||
`google.generativeai`) must be **lazy-imported** — never eager.
|
||||
• Public API is verb-first. New classes in `src/praisonaiui/message.py` ending
|
||||
in `Message` with a verb prefix (Ask*, Do*, Request*, …) are forbidden —
|
||||
use a module-level `async def` verb helper instead (see `prompt`, `error`).
|
||||
• Deprecations must emit a runtime `warnings.warn(..., DeprecationWarning, stacklevel=2)`
|
||||
on first access, not only in the docstring.
|
||||
• Deterministic serialisation in anything reaching the wire (sorted keys, stable field
|
||||
order). See existing `to_dict` patterns.
|
||||
• Multi-agent + async safe: no global mutable state without a lock.
|
||||
|
||||
STEP 2 — BRANCH (single name; reuse in STEP 4):
|
||||
BRANCH="claude/issue-${{ env.ISSUE_NUMBER_RESOLVED }}-$(date +%Y%m%d-%H%M%S)"
|
||||
git checkout -b "$BRANCH"
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 2 — ARCHITECTURE VALIDATION & ROUTING (MANDATORY before any code)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Answer these questions inline in your response, then proceed only if you pass:
|
||||
|
||||
STEP 3 — TEST / VERIFY:
|
||||
Run targeted pytest or smoke checks relevant to your edits (e.g. pytest tests/unit -q).
|
||||
ROUTING:
|
||||
1. **Core aiui** (`src/praisonaiui/`) — protocols, message types, server, features.
|
||||
2. **Features** (`src/praisonaiui/features/`) — opt-in capabilities (MCP, platforms, lifecycle, audio, auth, sharing, etc.).
|
||||
3. **UI builders** (`src/praisonaiui/ui.py`) — declarative component helpers.
|
||||
4. **Frontend** (`src/frontend/`) — React components / stores / SSE handlers.
|
||||
5. **Tests** (`tests/unit/`, `tests/integration/`) — new features require both smoke and real-agentic tests.
|
||||
6. **Docs** (`docs/`) — canonical name per feature, migration table for renames.
|
||||
|
||||
STEP 4 — COMMIT, PUSH, OPEN PR (mandatory if you produced commits):
|
||||
git add -A
|
||||
git commit -m "feat: <short summary> (fixes #${{ env.ISSUE_NUMBER_RESOLVED }})"
|
||||
git push -u origin "$BRANCH"
|
||||
REPO="${{ github.repository }}"
|
||||
COUNT=$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')
|
||||
if [ "$COUNT" -gt 0 ]; then
|
||||
gh pr list --repo "$REPO" --head "$BRANCH" --json url --jq '.[0].url'
|
||||
else
|
||||
gh pr create --repo "$REPO" --base main --head "$BRANCH" --title "feat: <short title>" --body "Fixes #${{ env.ISSUE_NUMBER_RESOLVED }}"
|
||||
fi
|
||||
CRITICAL: Do not stop after `git push`. You MUST complete `gh pr create` (or print the existing PR URL from the step above) and post that URL on the issue. Never ask a human to open the PR manually.
|
||||
EXTERNAL REPOS (do NOT edit from within this repo — route the work to the right place and stop):
|
||||
• Core SDK: `MervinPraison/PraisonAI` (`praisonaiagents`, `praisonai`) — agent runtime.
|
||||
• Tools: `MervinPraison/PraisonAI-Tools` — tool implementations.
|
||||
• Docs site: `MervinPraison/PraisonAIDocs` — product docs.
|
||||
If the requested change belongs in an external repo, comment on the issue explaining
|
||||
where it should live and DO NOT open a PR in this repo.
|
||||
|
||||
CONCEPTUAL CHECKS (if ANY fails — add a comment, do NOT open a PR):
|
||||
• Does it duplicate an existing public symbol in `src/praisonaiui/__init__.py`?
|
||||
• Does it add new class-first message types (`class Ask*Message`, `class *Message`
|
||||
with a verb in the name)? → Use a verb-first helper instead.
|
||||
• Does it add a new hard dependency to `pyproject.toml` `[project] dependencies`?
|
||||
→ Move to `[project.optional-dependencies]` and wrap imports lazily.
|
||||
• Does it break backward compat (rename, signature change, removal)? → Add
|
||||
a deprecation alias that emits `DeprecationWarning`; never hard-remove before the
|
||||
documented removal version (e.g. `0.5.0`).
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 3 — IMPLEMENT
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Single branch for the whole flow (reuse the same name in STEP 5):
|
||||
BRANCH="claude/issue-${{ env.ISSUE_NUMBER_RESOLVED }}-$(date +%Y%m%d-%H%M%S)"
|
||||
git checkout -b "$BRANCH"
|
||||
|
||||
Make minimal, focused changes:
|
||||
• Stay within the files listed in the issue's "Scope" / "Files to change" section.
|
||||
• Prefer extending existing modules over adding new ones.
|
||||
• No emojis, no comments, no markdown except where the user asked for it.
|
||||
• Python ≥ 3.10 style (`list[...]` not `List[...]`, `X | None` not `Optional[X]`).
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 4 — TEST / VERIFY
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Run these targeted checks (NOT the full suite):
|
||||
|
||||
# 1. Lint on only the files you changed:
|
||||
CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '\.py$' | tr '\n' ' ')
|
||||
[ -n "$CHANGED" ] && ruff check $CHANGED
|
||||
|
||||
# 2. Unit tests for the module(s) you touched:
|
||||
pytest tests/unit/<your_new_test_file>.py -v --tb=short
|
||||
|
||||
# 3. Import-time invariant (MUST stay under 200 ms cold):
|
||||
python -c "import time, sys; t=time.time(); import praisonaiui; dt=(time.time()-t)*1000; heavy=[m for m in sys.modules if any(h in m for h in ['langchain','llama_index','mcp','slack','discord','botbuilder','openai.','anthropic.','mistralai','google.generativeai'])]; print(f'{dt:.1f}ms modules={len(sys.modules)} leaked={heavy}'); assert heavy == [], f'Heavy deps leaked: {heavy}'"
|
||||
|
||||
# 4. Real agentic end-to-end test (write this into tests/integration/
|
||||
# if your feature changes the agent-facing API):
|
||||
# from praisonaiagents import Agent
|
||||
# import praisonaiui as aiui
|
||||
# agent = Agent(name="demo", instructions="You are a helpful assistant")
|
||||
# result = agent.start("Say hello in one sentence")
|
||||
# print(result)
|
||||
|
||||
If anything fails, fix the root cause (never skip, xfail, or delete the test).
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 5 — COMMIT, PUSH, OPEN PR (MANDATORY if you produced commits)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
git add -A
|
||||
git commit -m "feat: <short summary> (fixes #${{ env.ISSUE_NUMBER_RESOLVED }})"
|
||||
git push -u origin "$BRANCH"
|
||||
REPO="${{ github.repository }}"
|
||||
COUNT=$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')
|
||||
if [ "$COUNT" -gt 0 ]; then
|
||||
gh pr list --repo "$REPO" --head "$BRANCH" --json url --jq '.[0].url'
|
||||
else
|
||||
gh pr create --repo "$REPO" --base main --head "$BRANCH" \
|
||||
--title "feat: <short title>" \
|
||||
--body "Fixes #${{ env.ISSUE_NUMBER_RESOLVED }}
|
||||
|
||||
## Summary
|
||||
|
||||
<what changed in one paragraph>
|
||||
|
||||
## Before / After
|
||||
|
||||
<copy-pasteable snippet per public API change>
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
<copy from the issue; tick boxes only with commit SHA + file path evidence>
|
||||
|
||||
## Test evidence
|
||||
|
||||
\`\`\`
|
||||
<paste pytest output>
|
||||
\`\`\`
|
||||
|
||||
## Import-time proof
|
||||
|
||||
\`\`\`
|
||||
<paste the python -c import-time output>
|
||||
\`\`\`
|
||||
"
|
||||
fi
|
||||
|
||||
CRITICAL: Do NOT stop after `git push`. You MUST complete `gh pr create` (or print the
|
||||
existing PR URL from the step above) and post that URL on the issue. Never ask a
|
||||
human to open the PR manually.
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
STEP 6 — RESPOND TO REVIEW FEEDBACK (if this run was triggered by a review comment)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
If you were invoked by a PR review comment, you are the Lead Engineer for this PR:
|
||||
• Read ALL reviewer comments in chronological order (CodeRabbit → Copilot → human).
|
||||
• Fix every VALID issue by pushing commits to THIS branch (do NOT open a new PR).
|
||||
• Reply with a summary of which comments you addressed, which you disagreed with (and why).
|
||||
• Never ship a fix that removes/weakens a test.
|
||||
|
||||
allowed_tools: |
|
||||
Bash(git:*)
|
||||
Bash(python:*)
|
||||
Bash(pip:*)
|
||||
Bash(pytest:*)
|
||||
Bash(ruff:*)
|
||||
Bash(gh:*)
|
||||
Bash(npm:*)
|
||||
Bash(npx:*)
|
||||
Bash(python -m pytest:*)
|
||||
Bash(python -m pip:*)
|
||||
Bash(python -m ruff:*)
|
||||
View
|
||||
GlobTool
|
||||
GrepTool
|
||||
|
||||
Reference in new issue
Block a user