diff --git a/.github/scripts/merge-gate-selftest.js b/.github/scripts/merge-gate-selftest.js index 5fef08aa5..3075ebb91 100644 --- a/.github/scripts/merge-gate-selftest.js +++ b/.github/scripts/merge-gate-selftest.js @@ -103,12 +103,56 @@ assert('external contributor blocked', mg.maintainerOnlyAuthorReason({ assert('first-time contributor blocked', mg.maintainerOnlyAuthorReason({ user: { login: 'new-dev' }, author_association: 'FIRST_TIME_CONTRIBUTOR', -})?.includes('FIRST_TIME_CONTRIBUTOR')); +})?.includes('first-time contributor')); assert('maintainer login allowed', mg.maintainerOnlyAuthorReason({ user: { login: 'MervinPraison' }, author_association: 'OWNER', }) === null); +const fxmacroFile = { + status: 'added', + filename: 'src/praisonai-agents/praisonaiagents/tools/fxmacrodata_tools.py', +}; +assert( + 'new vendor *_tools.py blocked for merge gate', + mg.newVendorToolModuleInCoreReason([fxmacroFile], [])?.includes('PraisonAI-Tools') +); +assert( + 'maintainer-accept-core-tools opts in', + mg.newVendorToolModuleInCoreReason([fxmacroFile], [mg.MAINTAINER_ACCEPT_CORE_TOOLS_LABEL]) === null +); +assert( + 'modified legacy tool file not blocked', + mg.newVendorToolModuleInCoreReason( + [{ status: 'modified', filename: 'src/praisonai-agents/praisonaiagents/tools/tavily_tools.py' }], + [] + ) === null +); +assert( + 'FINAL prompt mentions 6c vendor tools rule', + mg.FINAL_CLAUDE_REVIEW_BODY.includes('6c.') && + mg.FINAL_CLAUDE_REVIEW_BODY.includes('maintainer-accept-core-tools') +); +assert( + 'FINAL Phase 3 forbids approve on routing fail', + mg.FINAL_CLAUDE_REVIEW_BODY.includes('Never') && + mg.FINAL_CLAUDE_REVIEW_BODY.includes('6b/6c') +); +const fx5661Finished = { + user: { login: 'praisonai-triage-agent[bot]' }, + body: '**Claude finished @MervinPraison\'s task**\nVerdict: ✅ Approve for merge.', + created_at: '2026-10-07T09:40:28Z', +}; +assert( + '#5661-style wrong FINAL approval blocked', + mg.wrongFinalApprovalForVendorToolInCoreReason( + [fx5661Finished], + '2026-10-07T09:00:00Z', + [fxmacroFile], + [] + )?.includes('wrong verdict') +); + const coreGreenRuns = [ { name: 'test-core', status: 'completed', conclusion: 'success' }, { name: 'test-core (cli)', status: 'completed', conclusion: 'success' }, diff --git a/.github/scripts/merge-gate.js b/.github/scripts/merge-gate.js index c7e9901f4..142289acb 100644 --- a/.github/scripts/merge-gate.js +++ b/.github/scripts/merge-gate.js @@ -19,6 +19,8 @@ const WORKFLOW_ONLY_LABEL = 'merge-gate-ci-only'; const EXTERNAL_EXAMPLE_PATH_PREFIX = 'examples/tools/external/'; const EXTERNAL_EXAMPLE_LABEL = 'pipeline/external-example'; const MAINTAINER_ACCEPT_EXAMPLE_LABEL = 'maintainer-accept-example'; +const CORE_TOOLS_DIR_PREFIX = 'src/praisonai-agents/praisonaiagents/tools/'; +const MAINTAINER_ACCEPT_CORE_TOOLS_LABEL = 'maintainer-accept-core-tools'; const CI_ONLY_PATH_PREFIXES = ['.github/workflows/', '.github/actions/', '.github/scripts/merge-gate']; const SDK_PATH_PREFIXES = ['src/praisonai-agents/', 'src/praisonai/', 'src/praisonai-ts/']; const TS_SDK_SOURCE_PREFIX = 'src/praisonai-ts/src/'; @@ -106,10 +108,18 @@ function isAutoMergeAuthor(user) { return login.endsWith('[bot]') && login.toLowerCase().includes('praisonai-triage'); } +function isFirstTimeContributor(pr) { + return pr?.author_association === 'FIRST_TIME_CONTRIBUTOR'; +} + +/** Human / external authors not on the triage auto-merge allowlist. */ function maintainerOnlyAuthorReason(pr) { if (!pr?.user?.login) return 'maintainer-only author (missing login)'; // Trusted automation first — GitHub often marks bots as CONTRIBUTOR. if (isAutoMergeAuthor(pr.user)) return null; + if (isFirstTimeContributor(pr)) { + return `auto-merge disabled: first-time contributor (@${pr.user.login})`; + } if (MAINTAINER_ONLY_ASSOCIATIONS.has(pr.author_association)) { return `maintainer-only author (@${pr.user.login}, ${pr.author_association})`; } @@ -458,7 +468,7 @@ function finalClaudeCompletedOnSha(comments, headPushedAt) { } const FINAL_CLAUDE_REVIEW_BODY = - '@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Review changes in this PR. Python SDK: praisonaiagents, praisonai. TypeScript SDK: src/praisonai-ts/. Do NOT modify src/praisonai-rust. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.\n\n**MANDATORY READ (before reviewing):**\n- Always read src/praisonai-agents/AGENTS.md\n- If this PR touches src/praisonai-ts/, also read src/praisonai-ts/AGENTS.md §2.1.2 (TS triage + PR review checklist)\n\n**Phase 1: Review per AGENTS.md**\n1. Protocol-driven: check heavy implementations vs core SDK\n2. Backward compatible: ensure zero feature regressions\n3. Performance: no hot-path regressions\n4. SDK value: review in depth whether the change genuinely adds value to the SDK — never add features for the sake of adding them. It must strengthen the SDK (simpler, more user-friendly, robust, world-class, secure). If it does not clearly add value, request changes or recommend rejecting/closing rather than merging scope creep\n5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.\n6. Repo routing: agent-callable tools → PraisonAI-Tools; lifecycle plugins → PraisonAI-Plugins; optional sandbox backends → PraisonAI-Plugins (`praisonai.sandbox` entry point) — request changes if wrongly added to praisonaiagents/\n6b. **External tool examples (`examples/tools/external/**`):** If the diff is confined to that path, mark **SDK value** ❌ for monorepo merge — redirect the contributor to PraisonAI-Tools; do **not** Approve for merge unless the PR has the `maintainer-accept-example` label.\n\n**MANDATORY COMMENT FORMAT — include this Phase 1 table in your review comment:**\n#### Phase 1 — AGENTS.md review\n| Check | Result |\n|---|---|\n| Protocol-driven / no heavy impl in core | ✅ or ❌ + one-line rationale |\n| Backward compatible | ✅ or ❌ + one-line rationale |\n| Performance (hot path) | ✅ or ❌ + one-line rationale |\n| **SDK value** | ✅ or ❌ + one-line rationale (explicitly judge whether the change strengthens the SDK) |\n| No Agent param bloat | ✅ or ❌ + one-line rationale |\n| Repo routing | ✅ or ❌ + one-line rationale |\n\nFor TypeScript PRs (src/praisonai-ts/), also add:\n| TS types / parity / tests | ✅ or ❌ + one-line rationale (npm run build && npm test) |\n\n**Phase 2: FIX Valid Issues**\n7. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix\n8. Also independently identify and fix any gaps or issues you find in the changed code — do not rely only on prior reviewer feedback\n9. Push all code fixes directly to THIS branch (do NOT create a new PR)\n10. Comment a summary of exact files modified and what you skipped\n\n**Phase 3: Final Verdict**\n11. If all issues are resolved, approve the PR / close the Issue\n12. If blocking issues remain, request changes / leave clear action items'; + '@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Review changes in this PR. Python SDK: praisonaiagents, praisonai. TypeScript SDK: src/praisonai-ts/. Do NOT modify src/praisonai-rust. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.\n\n**MANDATORY READ (before reviewing):**\n- Always read src/praisonai-agents/AGENTS.md\n- If this PR touches src/praisonai-ts/, also read src/praisonai-ts/AGENTS.md §2.1.2 (TS triage + PR review checklist)\n\n**Phase 1: Review per AGENTS.md**\n1. Protocol-driven: check heavy implementations vs core SDK\n2. Backward compatible: ensure zero feature regressions\n3. Performance: no hot-path regressions\n4. SDK value: review in depth whether the change genuinely adds value to the SDK — never add features for the sake of adding them. It must strengthen the SDK (simpler, more user-friendly, robust, world-class, secure). If it does not clearly add value, request changes or recommend rejecting/closing rather than merging scope creep\n5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.\n6. Repo routing: agent-callable tools → PraisonAI-Tools; lifecycle plugins → PraisonAI-Plugins; optional sandbox backends → PraisonAI-Plugins (`praisonai.sandbox` entry point) — request changes if wrongly added to praisonaiagents/\n6b. **External tool examples (`examples/tools/external/**`):** If the diff is confined to that path, mark **SDK value** ❌ for monorepo merge — redirect the contributor to PraisonAI-Tools; do **not** Approve for merge unless the PR has the `maintainer-accept-example` label.\n6c. **New vendor `*_tools.py` in core (`src/praisonai-agents/praisonaiagents/tools/`):** If the PR **adds** a new `*_tools.py` for a third-party API/SaaS/dataset (e.g. FXMacroData), mark **Repo routing** ❌ and **SDK value** ❌ — redirect to MervinPraison/PraisonAI-Tools. Do **not** Approve because legacy bundled tools (Tavily/Exa/You.com/etc.) already in core are **not** precedent for new vendor modules. Request changes or recommend closing unless the PR has `maintainer-accept-core-tools`.\n\n**MANDATORY COMMENT FORMAT — include this Phase 1 table in your review comment:**\n#### Phase 1 — AGENTS.md review\n| Check | Result |\n|---|---|\n| Protocol-driven / no heavy impl in core | ✅ or ❌ + one-line rationale |\n| Backward compatible | ✅ or ❌ + one-line rationale |\n| Performance (hot path) | ✅ or ❌ + one-line rationale |\n| **SDK value** | ✅ or ❌ + one-line rationale (explicitly judge whether the change strengthens the SDK) |\n| No Agent param bloat | ✅ or ❌ + one-line rationale |\n| Repo routing | ✅ or ❌ + one-line rationale |\n\nFor TypeScript PRs (src/praisonai-ts/), also add:\n| TS types / parity / tests | ✅ or ❌ + one-line rationale (npm run build && npm test) |\n\n**Phase 2: FIX Valid Issues**\n7. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix\n8. Also independently identify and fix any gaps or issues you find in the changed code — do not rely only on prior reviewer feedback\n9. Push all code fixes directly to THIS branch (do NOT create a new PR)\n10. Comment a summary of exact files modified and what you skipped\n\n**Phase 3: Final Verdict**\n11. **Never** Approve or write “Approve for merge” if any Phase 1 row is ❌, if rule 6b/6c applies, or if the change belongs in PraisonAI-Tools/PraisonAI-Plugins. Use **Request changes**, redirect to the external repo, and recommend closing the monorepo PR when routing is wrong.\n12. Approve only when every Phase 1 row is ✅ (including **Repo routing** and **SDK value**) and blocking issues are resolved; otherwise request changes with clear action items'; async function getMergeState(github, owner, repo, prNumber) { const query = ` @@ -694,6 +704,11 @@ async function shouldSkipMergeGateDispatch(github, owner, repo, prNumber, core, return true; } const ctx = await loadPrContext(github, owner, repo, prNumber); + const authorBlock = maintainerOnlyAuthorReason(ctx.pr); + if (authorBlock) { + core?.info?.(`Skip merge gate dispatch for PR #${prNumber}: ${authorBlock}`); + return true; + } const pendingRuns = await countPendingMergeGateRuns(github, owner, repo); const reason = mergeGateDispatchBlockedReason({ labels: ctx.labels, @@ -738,6 +753,57 @@ function isExternalExampleOnlyChange(files) { return files.every((f) => f.filename.startsWith(EXTERNAL_EXAMPLE_PATH_PREFIX)); } +/** New third-party vendor modules must land in PraisonAI-Tools, not core (legacy bundled *_tools.py excepted). */ +function listAddedCoreVendorToolModules(files) { + return (files || []) + .filter((f) => f.status === 'added' && f.filename.startsWith(CORE_TOOLS_DIR_PREFIX)) + .filter((f) => /\/[^/]+_tools\.py$/.test(f.filename)) + .map((f) => f.filename); +} + +function newVendorToolModuleInCoreReason(files, labels = []) { + if (labels.includes(MAINTAINER_ACCEPT_CORE_TOOLS_LABEL)) return null; + const added = listAddedCoreVendorToolModules(files); + if (!added.length) return null; + return `new vendor tool module in core (${added.join(', ')}) — belongs in PraisonAI-Tools (add ${MAINTAINER_ACCEPT_CORE_TOOLS_LABEL} to opt in)`; +} + +function latestClaudeFinishedCommentOnHead(comments, headPushedAt) { + if (!headPushedAt) return null; + const headTime = new Date(headPushedAt).getTime(); + let latest = null; + let latestTime = 0; + for (const c of comments || []) { + if (!isClaudeFinalReplyComment(c)) continue; + const t = new Date(c.created_at).getTime(); + if (t < headTime - 60000) continue; + if (t > latestTime) { + latestTime = t; + latest = c; + } + } + return latest; +} + +function looksLikeFinalApproveForMerge(body) { + const b = (body || '').toLowerCase(); + if (b.includes('request changes')) return false; + if (b.includes('repo routing | ❌') || b.includes('repo routing| ❌')) return false; + return ( + b.includes('approve for merge') || + b.includes('verdict: ✅ approve') || + b.includes('verdict: approve') + ); +} + +/** Catches cases like #5661 where FINAL approved despite new vendor *_tools.py in core. */ +function wrongFinalApprovalForVendorToolInCoreReason(comments, headPushedAt, files, labels = []) { + if (!newVendorToolModuleInCoreReason(files, labels)) return null; + const finished = latestClaudeFinishedCommentOnHead(comments, headPushedAt); + if (!finished || !looksLikeFinalApproveForMerge(finished.body)) return null; + return 'FINAL approved vendor tool in core (wrong verdict) — re-trigger FINAL after routing rules'; +} + function isInternalPullRequestLink(link, owner, repo) { if (link?.base?.repo?.full_name === `${owner}/${repo}`) return true; const baseUrl = link?.base?.repo?.url || ''; @@ -1056,6 +1122,10 @@ async function loadPrContext(github, owner, repo, prNumber) { const headCommitDate = await getHeadCommitDate(github, owner, repo, prNumber); const headPushedAt = headCommitDate || pr.updated_at; + if (issue.author_association && !pr.author_association) { + pr.author_association = issue.author_association; + } + return { pr, issue, @@ -1141,6 +1211,17 @@ async function evaluatePipelineQuiescent(github, owner, repo, prNumber, core, op ); } + const vendorToolReason = newVendorToolModuleInCoreReason(pullFiles, ctx.labels); + if (vendorToolReason) reasons.push(vendorToolReason); + + const wrongFinalVendor = wrongFinalApprovalForVendorToolInCoreReason( + ctx.comments, + ctx.headPushedAt, + pullFiles, + ctx.labels + ); + if (wrongFinalVendor) reasons.push(wrongFinalVendor); + const agentChange = getAgentPyChangeFromFiles(pullFiles); const agentManual = manualReviewReasonForAgentPy(agentChange); if (agentManual) reasons.push(agentManual); @@ -1331,6 +1412,12 @@ module.exports = { EXTERNAL_EXAMPLE_PATH_PREFIX, EXTERNAL_EXAMPLE_LABEL, MAINTAINER_ACCEPT_EXAMPLE_LABEL, + listAddedCoreVendorToolModules, + newVendorToolModuleInCoreReason, + wrongFinalApprovalForVendorToolInCoreReason, + looksLikeFinalApproveForMerge, + CORE_TOOLS_DIR_PREFIX, + MAINTAINER_ACCEPT_CORE_TOOLS_LABEL, isInternalPullRequestLink, resolvePrNumberFromLinkedPullRequests, resolvePrNumberFromHeadBranch, diff --git a/.github/scripts/pipeline-status.js b/.github/scripts/pipeline-status.js index 8a8c9d842..b14dbc579 100644 --- a/.github/scripts/pipeline-status.js +++ b/.github/scripts/pipeline-status.js @@ -66,7 +66,12 @@ function reasonToBlockerLabel(reason) { if ( r.includes('manual') || r.includes('requires manual') || + r.includes('first-time contributor') || r.includes('maintainer-only author') || + r.includes('auto-merge disabled') || + r.includes('vendor tool module in core') || + r.includes('wrong verdict') || + r.includes('external example only') || r.includes('sensitive path') || r.includes('no-auto-merge') || r.includes('manual-only label') || diff --git a/.github/workflows/claude-merge-gate.yml b/.github/workflows/claude-merge-gate.yml index f36ffb339..2de7d3e16 100644 --- a/.github/workflows/claude-merge-gate.yml +++ b/.github/workflows/claude-merge-gate.yml @@ -319,12 +319,13 @@ jobs: 1. Read AGENTS.md and the PR diff on the current branch. 2. Read all PR comments and reviews (FINAL architecture reviewer / Lead Engineer must have run). 3. Confirm SDK value gate: change strengthens the relevant SDK (Python: praisonaiagents/praisonai; TypeScript: src/praisonai-ts/) — no scope creep. The aim is a LIGHTWEIGHT AND POWERFUL package — BLOCK changes that add params/modules/exports duplicating existing Agent capabilities (instructions/backstory/tools/hooks/memory), or add knobs/fields with no live consumer, i.e. scope creep for the sake of it. FINAL architecture review must include the Phase 1 table with an explicit **SDK value** row. - 4. Repo routing: BLOCK if agent-callable tools (→ PraisonAI-Tools), lifecycle plugins (→ PraisonAI-Plugins), or optional sandbox backends (→ PraisonAI-Plugins via `praisonai.sandbox`) were added to praisonaiagents/ instead of the external repo. + 4. Repo routing: BLOCK if agent-callable tools (→ PraisonAI-Tools), lifecycle plugins (→ PraisonAI-Plugins), or optional sandbox backends (→ PraisonAI-Plugins via `praisonai.sandbox`) were added to praisonaiagents/ instead of the external repo. BLOCK if the PR adds a new `src/praisonai-agents/praisonaiagents/tools/*_tools.py` vendor module (unless `maintainer-accept-core-tools`); existing Tavily/Exa-style files in core are not precedent. 5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params. 6. If agent.py adds >100 lines or new Agent __init__ params, respond MERGE_GATE_VERDICT: BLOCK (manual review required). 7. BLOCK if labels security/breaking-change/needs-manual-review/release, sensitive paths (.github/workflows, auth, pyproject.toml), secrets in diff, PR >800 lines or >30 files, or SDK changes without tests. Label `merge-gate-ci-only` exempts CI-only changes under `.github/workflows/`, `.github/actions/`, or merge-gate scripts. 8. Confirm no CHANGES_REQUESTED reviews and CI green on HEAD ${{ matrix.head_sha }}. - 9. If ready to merge: MERGE_GATE_VERDICT: APPROVE. Otherwise: MERGE_GATE_VERDICT: BLOCK with reasons. + 9. Author policy: MERGE_GATE_VERDICT: BLOCK if the PR author is a first-time contributor (`author_association: FIRST_TIME_CONTRIBUTOR`) or any human not on the auto-merge allowlist (app/praisonai-triage-agent, MervinPraison, github-actions[bot] CI-only). Fork PRs and external contributors always require maintainer manual merge — never APPROVE for gate auto-merge. + 10. If ready to merge: MERGE_GATE_VERDICT: APPROVE. Otherwise: MERGE_GATE_VERDICT: BLOCK with reasons. Do not approve or merge via GitHub UI/API — only post the verdict comment. disallowed_tools: | diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 6b811e30d..d5346a05e 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -302,7 +302,7 @@ jobs: STEP 1 — READ GUIDELINES: - Read AGENTS.md to understand the architecture rules. + Read src/praisonai-agents/AGENTS.md (especially §6.1 vendor tools → PraisonAI-Tools) and root AGENTS.md routing table. SCOPE: Python SDK (praisonaiagents, praisonai) and TypeScript SDK (src/praisonai-ts/) live in this monorepo. Do NOT modify src/praisonai-rust. For TS issues read src/praisonai-ts/AGENTS.md. AIM: This package must stay LIGHTWEIGHT AND POWERFUL. Do a CRITICAL REVIEW at each stage (issue triage, fix planning, PR review/implementation) and reject scope creep for the sake of adding features. Prefer existing Agent capabilities (instructions/backstory/tools/hooks/memory) over new params/modules/exports. Even when fixing a raised issue, keep the fix minimal and lightweight — do NOT expand the surface area or add knobs with no live consumer. @@ -311,7 +311,7 @@ jobs: - CORE vs WRAPPER vs TOOLS vs DOCS vs PLUGINS ROUTING: 1. Core SDK (praisonaiagents/): Only core protocols, base classes, decorators. No heavy implementations. 2. Wrapper (praisonai/): CLI, heavy implementations, optional dependencies. - 3. Tools → MervinPraison/PraisonAI-Tools: agent-callable integrations at runtime (Composio, Slack, API/DB connectors). Do NOT implement in praisonaiagents/ — use STEP 3-ALT. + 3. Tools → MervinPraison/PraisonAI-Tools: agent-callable integrations at runtime (Composio, Slack, API/DB connectors, new vendor APIs). Do NOT add new `praisonaiagents/tools/*_tools.py` modules in this repo — legacy bundled search tools (Tavily/Exa/You.com) are not precedent. Use STEP 3-ALT. 4. Documentation (PraisonAIDocs): Documentation pages, guides, API references. 5. Plugins → MervinPraison/PraisonAI-Plugins: framework lifecycle extensions (tracing, logging, metrics, hooks, guardrails). Not agent tools — use STEP 3-ALT. 6. Sandbox backends (optional/niche, e.g. Capsule) → PraisonAI-Plugins via `praisonai.sandbox` entry point; core keeps protocol/config/manager only. diff --git a/AGENTS.md b/AGENTS.md index 537da9e07..ec38f4223 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,7 @@ You are working on the PraisonAI project. | Python core SDK | `src/praisonai-agents/praisonaiagents/` | `src/praisonai-agents/AGENTS.md` | `pytest` in `src/praisonai-agents/tests/` | | Python wrapper / CLI | `src/praisonai/`, `src/praisonai-code/`, etc. | `src/praisonai-agents/AGENTS.md` | `pytest` under `src/praisonai/tests/` | | **TypeScript / JavaScript SDK** | **`src/praisonai-ts/`** | **`src/praisonai-ts/AGENTS.md`** | `cd src/praisonai-ts && npm run build && npm test` | -| Agent-callable tools | [PraisonAI-Tools](https://github.com/MervinPraison/PraisonAI-Tools) | — | repo tests | +| Agent-callable tools / new vendor `*_tools.py` | [PraisonAI-Tools](https://github.com/MervinPraison/PraisonAI-Tools) — **not** new modules under `praisonaiagents/tools/` (legacy bundled tools are not precedent) | — | repo tests | | Lifecycle plugins | [PraisonAI-Plugins](https://github.com/MervinPraison/PraisonAI-Plugins) | — | repo tests | | Documentation | [PraisonAIDocs](https://github.com/MervinPraison/PraisonAIDocs) | — | `nav-check` | | npm mirror (read-only for fixes) | [praisonai-js](https://github.com/MervinPraison/praisonai-js) | mirror of `src/praisonai-ts/AGENTS.md` | CI on praisonai-js | \ No newline at end of file diff --git a/src/praisonai-agents/AGENTS.md b/src/praisonai-agents/AGENTS.md index b2623f23d..3f07d7be4 100644 --- a/src/praisonai-agents/AGENTS.md +++ b/src/praisonai-agents/AGENTS.md @@ -606,6 +606,9 @@ class MyTool(BaseTool): > [!IMPORTANT] > **Agents only recognize parameters.** When creating tools, always expose all options as function parameters—agents cannot discover env vars or config files. +> [!IMPORTANT] +> **Vendor / third-party API tools:** New integrations (external APIs, datasets, SaaS wrappers) belong in **[PraisonAI-Tools](https://github.com/MervinPraison/PraisonAI-Tools)** as optional pip plugins — **not** as new `praisonaiagents/tools/*_tools.py` files in this repo. Core `praisonaiagents/tools/` holds SDK primitives (decorator, registry, schedule, shell, trust, subagent) and a small set of **legacy** bundled tools kept for backward compatibility. Do not treat legacy search tools (e.g. Tavily/Exa) as precedent for adding new vendor modules here. + ### 6.2 Hooks & Middleware ```python