Relocate the async split-pane TUI (async_tui.py) and InteractiveCore
(core.py) from the praisonai wrapper into praisonai-code so
`pip install praisonai-code` alone yields a full interactive chat/code
session with no wrapper required.
- Move async_tui.py + core.py impls into praisonai_code.cli.interactive;
leave identity-preserving back-compat shims at the old praisonai paths
(plus config/events shims so isinstance/monkeypatch hold across paths).
- Drop the hard-fail in chat.py; route interactive chat to the resident
AsyncTUI. Route interactive code to a resident AsyncTUI path
(_run_resident_code) when the wrapper is absent, keeping the richer
legacy dispatch when it is installed.
- Convert lazy wrapper-only imports (_async_bridge, integration.context_files)
to _wrapper_bridge with graceful fallback so no `praisonai` import
remains in the interactive package.
- Extend scripts/check_c7_imports.sh to gate interactive async_tui/core
at module load; C7 gate now reports 0 wrapper import lines.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: MervinPraison <[email protected]>
Move API, Docker, and cloud deployment from the wrapper into a standalone
praisonai-deploy package with backward-compat shims, CI/publish wiring,
and fixes for chat message forwarding, Docker build context, and CLI YAML merge.
Co-authored-by: Cursor <[email protected]>
Move sandbox backend implementations out of the wrapper into praisonai-sandbox,
preserve praisonai.sandbox shims, wire agents bridge/registry dispatch, and add
CI gates, publish slot, and backward-compat tests for the eight-package model.
Co-authored-by: Cursor <[email protected]>
- Fix ModuleNotFoundError: praisonai_mcp.cli.output — route
get_output_controller through the lazy praisonai_code bridge in
_configuration.py (resolves CI test_mcp_list, test_cli_shim_app_identity,
and test_get_command_resolves_mcp which failed because the command import
raised before resolution).
- Scope logging/setLevel to the actual running package logger tree derived
from __name__ (praisonai_mcp.mcp_server) instead of the legacy
praisonai.mcp_server shim namespace.
- Guarantee subprocess cleanup on TimeoutExpired (test) and KeyboardInterrupt
(stdio serve); always shut down MCP instances in sync/SSE via try/finally.
- Always clear temporary OAuth state/code verifier via finally.
- Remove redundant/broken assignment and unused var in check_c12_mcp_imports.sh.
Co-authored-by: Mervin Praison <[email protected]>
Move the heavy MCP server host out of the wrapper into praisonai-mcp with
backward-compat shims, _MCP_RESIDENT_COMMANDS routing, CI/publish wiring,
and regression gates so pip install praisonai keeps working.
Move extension bridge, CDP, and Playwright automation out of the wrapper with backward-compat shims, protocol bridge to agents-tier browser types, and full CI/release wiring.
Root cause of the CI failure and Greptile P1: praisonai_train.cli.commands.train
imported ..output.console but that module was never moved into the extracted
package, so every agents/list/show/apply command raised ModuleNotFoundError
before doing any work.
- Add self-contained praisonai_train.cli.output.console: delegates to
praisonai-code's OutputController when co-installed (via lazy _code_bridge),
falls back to a minimal rich/typer controller so `pip install praisonai-train`
works standalone. Fixes test_cli_show_displays_iterations.
- pyproject: `[llm]` extra now pulls praisonai-code (the llm command bridges into
the code CLI runner); register `setup-conda-env` entry point advertised by README.
- apply: resolve real agent name for the training profile and reuse the loaded
agent for --run instead of loading the file twice.
- Expand ~ in file/sqlite storage paths; open scenarios/vision configs as utf-8.
- check_c10_train_imports.sh: use POSIX `grep -Ev` for portability.
62 train unit tests pass; standalone agents --dry-run / list / show verified with
the fallback controller (no wrapper/code installed).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Mervin Praison <[email protected]>
Extract LLM fine-tuning (Unsloth) and agent training from the praisonai
wrapper into a new installable package src/praisonai-train (PyPI:
praisonai-train, import: praisonai_train), following the C9 praisonai-bot
playbook.
- Move praisonai/train/{llm,agents,_ollama}, train_vision.py,
upload_vision.py, cli/commands/train.py, and the conda setup scripts
into praisonai_train (git mv, history preserved)
- Wrapper keeps backward-compat shims: alias_package for praisonai.train,
sys.modules shims for the command/vision modules, setup-conda-env
delegate; all old import paths resolve to the same module objects
- praisonai-code routing: new _TRAIN_RESIDENT_COMMANDS + _train_bridge;
train removed from _WRAPPER_RESIDENT_COMMANDS; hidden on standalone
installs without praisonai-train
- Legacy dispatch (praison_ai.py) prefers praisonai_train, falls back to
wrapper shims
- Packaging: wrapper depends on praisonai-train>=0.0.1; extra
train = ["praisonai-train[llm]"] now actually installs the ML stack
- CI: 5-package install order, standalone train smoke, train test shard,
check_c10_train_imports.sh gate
- Release: agents -> code -> bot -> train -> wrapper across
_release_lib.py, bump_and_release.py (--train/--train-pin/--wait-train),
publish_all.py, pypi-release.yml
- Tests: test_c10_train_backward_compat.py (20 tests), unit tests moved
into src/praisonai-train/tests (62 tests, run standalone)
- Docs: PRAISONAI_TRAIN_MANIFEST.md, ARCHITECTURE.md five-package model,
AGENTS.md refresh, beginner-friendly package README
Co-Authored-By: Claude Fable 5 <[email protected]>
The ^ anchors only matched top-level imports, silently passing
function-level (indented) `from praisonai_code` imports — the common
pattern in this codebase. Comment lines are still stripped by the
existing grep -v filter.
Co-authored-by: Mervin Praison <[email protected]>
Route host_app bridges through the wrapper bridge, correct jobs.server paths, lazy-load praisonai_code from bot via _code_bridge, and document or gate wrapper-required CLI paths with CI coverage.
Co-authored-by: Cursor <[email protected]>
Split bots, gateway, channel CLI, and OS daemon into standalone praisonai-bot
package while preserving praisonai.* import paths via alias_package shims.
Adds four-tier PyPI publish workflow, CI gates, and migrated test suite.
Repatriate wrapper-heavy CLI commands and features to praisonai, route via
_WRAPPER_RESIDENT_COMMANDS, and normalise remaining touchpoints through
_wrapper_bridge so the standalone hot path stays PyPI-independent.
- check_c7_imports.sh: enforce the allowlist (flag any non-allowlisted
praisonai-code file carrying wrapper imports) instead of only printing
its presence (Greptile P1).
- c7_wrapper_import_allowlist.txt: add managed.py, commands/app.py,
performance_checks.py (pre-existing lazy/guarded wrapper imports) so
enforcement passes at 47/47.
- Consolidate duplicated _bots_config_schema() into _wrapper_checks.py
(bots_config_schema); import as alias in bot_checks/gateway_checks
to avoid drift (CodeRabbit).
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Mervin Praison <[email protected]>
- check_c7_imports.sh: use POSIX whitespace and match bare
`from praisonai import X` (was undercounting); robust self-location
via BASH_SOURCE; raise regression baseline to accurate 225.
- app.py: route AgentOS through _wrapper_bridge to satisfy strict gate.
- main.py: guard both _fw_validators_module() calls and the capabilities
dispatch against ImportError so standalone praisonai-code fails cleanly.
- recipe_creator.py: load praisonai.auto constants via optional_wrapper_attr
so recipe creation degrades gracefully without the wrapper.
- C7.1_BOUNDARIES.md: dedupe heading, document new baseline/regex.
Co-authored-by: Mervin Praison <[email protected]>
The regression-baseline step ran `rg` under `set -euo pipefail`, so on
runners/subprocesses without ripgrep on PATH the pipeline died with exit 127
before printing the count — failing the PR's own test_c7_import_gate_script_passes
and the new CI smoke gate. Prefer rg when present, fall back to portable
grep -r, and guard the no-match case against pipefail.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Mervin Praison <[email protected]>
Document three-tier ownership, route optional wrapper imports through
_wrapper_bridge, tighten the C7 import gate baseline to 211, and add
boundary tests plus doctor skip helpers for standalone praisonai-code.
Add scripts/check_c7_imports.sh with strict hot-path and regression baseline;
extend CI smoke to run it and verify standalone run does not hit wrapper imports.
* fix: move scripts folder from root to appropriate location (fixes#1659)
- Move all smoke test scripts from /scripts to src/praisonai/tests/integration/
- Update documentation in moved files to reflect new paths
- Per AGENTS.md architecture, these bot/BotOS integration tests belong in praisonai wrapper tests
- Preserves git history with git mv command
Co-authored-by: MervinPraison <[email protected]>
* fix: add __test__ = False to smoke test files to prevent pytest collection
- Prevents accidental pytest discovery in environments with different collection rules
- Follows Python testing best practices for non-test files in test directories
- Addresses Copilot's review feedback for explicit test exclusion
---------
Co-authored-by: praisonai-triage-agent[bot] <272766704+praisonai-triage-agent[bot]@users.noreply.github.com>
Co-authored-by: MervinPraison <[email protected]>
* feat(N4): inbound dead-letter queue for failed bot messages
Persist failed agent.chat() calls to a SQLite-backed DLQ so user
messages are never silently lost on transient LLM failures.
- praisonai/bots/_dlq.py: InboundDLQ + DLQEntry (sqlite3 stdlib only,
WAL mode, atomic writes via per-instance threading.Lock; TTL +
max_size eviction; async replay with success/failure callback).
- praisonai/bots/_session.py: BotSessionManager(dlq=) optional param;
chat() now enqueues on agent.chat() exception then re-raises (so
adapter still shows user a friendly error). Default OFF preserves
legacy behaviour bit-for-bit.
- praisonai/bots/__init__.py: lazy exports for InboundDLQ, DLQEntry,
BotSessionManager.
- praisonai/cli/commands/bot.py: 'praisonai bot dlq {list,replay,purge}'
subcommand group with --path / --limit / --yes flags.
- tests/unit/bots/test_dlq.py: 11 unit tests (basic/persistence/bounds/
TTL/replay/wired-failure-path).
- scripts/smoke_n4_real.py: real agentic E2E — patch agent.chat to fail
once, assert DLQ holds entry, replay through real LLM (anthropic/
claude-haiku-4-5) returns expected answer.
Test results:
11/11 DLQ unit tests pass
102/102 bot/session/gateway regression pass (no W1 here, single
pre-existing unrelated test deselected)
Real agentic: 'What is 2+2?' fails, lands in DLQ, replay -> '4'
Docs: features/inbound-dlq.mdx with mermaid (Dark Red agents / Teal
tools / white text), CardGroup, Tabs, ParamField, Expandable,
AccordionGroup, Tip/Warning/Info/Check/Badge per Mintlify.
Closes N4.
* fix(dlq): address critical P1/P2 issues from architecture review
- Fix non-atomic SQLite enqueue operations by using explicit transactions
- Fix event loop blocking by wrapping DLQ calls in run_in_executor
- Fix replay ordering to process oldest entries first (not newest)
- Fix CLI exit codes for user cancellation and failed replays
- Fix smoke test to fail fast when no supported API key is found
Resolves critical issues identified by Greptile, CodeRabbit, Gemini reviewers
Co-authored-by: Mervin Praison <[email protected]>
---------
Co-authored-by: Cascade <[email protected]>
Co-authored-by: praisonai-triage-agent[bot] <272766704+praisonai-triage-agent[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: praison <[email protected]>
* feat(W1): cross-platform mirror + unified per-user session
- Core SDK: IdentityResolverProtocol, IdentityLink, InMemoryIdentityResolver
- Core SDK: task-local SessionContext via contextvars (async-safe)
- Wrapper: BotSessionManager.identity_resolver param + _persist_key separation
- Wrapper: praisonai.bots.mirror_to_session() outbound delivery mirror
- Tests: 17 core SDK + 8 wrapper unit tests; 0 regressions on 146 session + 99 bot tests
- Real agentic smoke: anthropic/claude-haiku-4-5 recalled cross-platform fact
- Docs: features/cross-platform-mirror.mdx
Closes W1.
* feat(W1): wire identity_resolver through Bot/BotOS + persistent FileIdentityResolver
- FileIdentityResolver: JSON-backed persistent resolver (atomic writes, 0o600 perms)
- Bot(identity_resolver=...) constructor param + adapter splice
- BotOS(identity_resolver=...) propagates to all bots (shortcut + add_bot)
- BotSessionManager.chat() now sets task-local SessionContext (platform/chat/user/unified_user_id)
- ContextVars propagated into executor thread via copy_context()
- Telegram/Discord/Slack handlers pass chat_id + thread_id + user_name to chat()
- 5 new FileIdentityResolver tests + 7 Bot/BotOS wiring tests = 12 new tests
- 151 core SDK session tests + 106 wrapper bot/session tests pass
- Real agentic smoke (BotOS API): claude-haiku-4-5 recalled cross-platform 'darkwave'
- Docs updated with high-level BotOS API quickstart
Closes W1.
* fix(W1): hold agent_lock across full LLM call to prevent history leak
Pre-existing concurrency bug exposed by W1 robustness suite (T3):
agent_lock only protected the history swap, not the LLM call.
Concurrent users on a shared Agent could observe each other's
chat_history during the LLM round-trip.
Fix: scope agent_lock to cover the whole load+swap+chat+capture
sequence. Throughput on a shared agent is bounded by serial LLM
latency — correct, since chat_history is a mutable instance attr.
- New regression test test_no_history_leak_between_concurrent_users
- All 16 W1 unit tests pass; 5/5 W1 robustness real-LLM tests pass:
T1 3-platform unification | T2 restart persistence | T3 concurrent
users isolated | T4 SessionContext visible to tools | T5 self-
improving probe (correctly demonstrates W1 boundary vs W2)
* fix(review): address Qodo/Coderabbit/Gemini reviewer feedback on W1 PR
- memory_mixin: add -> bool return type to _add_to_chat_history_if_not_duplicate (Gemini)
- execution_mixin: add -> Optional[str] return type to arun (Gemini)
- chat_mixin: remove unused asyncio, threading, traceback, Callable, OrderedDict (Coderabbit/Qodo)
- execution_mixin: remove unused os, get_logger (Coderabbit/Qodo)
- memory_mixin: remove unused get_logger, List, Any (Coderabbit/Qodo)
- identity.py: fix TOCTOU race in FileIdentityResolver._flush() by adding _flush_lock
that serialises the full snapshot+disk-write sequence
- _mirror.py: clarify comment - _storage_key() is a duck-typing check, not bucket creation
All 151 core SDK + 16 W1 bot tests pass.
Agent-Logs-Url: https://github.com/MervinPraison/PraisonAI/sessions/a8f7b411-9c5e-426b-99ce-bcfea79deaaa
Co-authored-by: MervinPraison <[email protected]>
* fix(review): address Qodo/Coderabbit/Gemini reviewer feedback on W1 PR
Critical fixes for race conditions and robustness:
P1 Race Condition Fixes:
- FileIdentityResolver._flush: Hold _lock across entire write operation to prevent TOCTOU race where concurrent link() calls could cause data loss during os.replace()
- mirror_to_session: Add thread-safe _add_mirror_entry_sync() method to BotSessionManager that properly coordinates with asyncio locks used by chat()
P2 Robustness Fixes:
- Session context cleanup: Use try/finally in chat() to ensure clear_session_context() is always called, even on agent exceptions
- Variable shadowing: Fix reset() method to use distinct storage_key/persist_key variables instead of reusing 'key'
- Model identifiers: Update smoke tests to use valid model names (claude-3-5-haiku-latest, gemini-1.5-flash)
All fixes maintain backward compatibility and follow AGENTS.md architecture guidelines.
Co-authored-by: Mervin Praison <[email protected]>
* fix(review): address Qodo/Coderabbit/Gemini reviewer feedback on W1 PR
Comprehensive fixes for race conditions and code quality issues:
P1 Race Condition Fixes:
- Fixed mirror_to_session sync path race: added per-user threading locks
when no event loop is running to prevent concurrent history corruption
- Reserved field protection in mirror entries: filter metadata to prevent
callers from overwriting role/mirror/timestamp invariants
P2 Code Quality Fixes:
- Enhanced session context cleanup logging for debugging
- Use UTC timestamps in mirror entries for consistency
- Remove unused imports from _add_mirror_entry_sync
- Fix f-string literals without placeholders (Ruff F541)
- Fix hardcoded developer paths in smoke test docstrings
- Fix integration test skip condition to require explicit RUN_REAL_AGENTIC opt-in
All fixes maintain backward compatibility and follow AGENTS.md principles.
🤖 Generated with Claude Code
* fix(mirror): replace process-wide global lock with per-call/per-manager lock
@claude: The module-level _mirror_lock = threading.RLock() serialised
mirror_to_session() calls across ALL BotSessionManager instances in the process.
Slow disk I/O for one bot would block mirror ops for every other bot.
Now accepts optional 'lock' param (caller supplies their own per-manager lock)
or falls back to a fresh per-call RLock — never shared across bot instances.
---------
Co-authored-by: Cascade <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: praisonai-triage-agent[bot] <272766704+praisonai-triage-agent[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: praison <[email protected]>