Compare commits

...
Author SHA1 Message Date
praisonai-triage-agent[bot] ce0a38d723 Release v4.6.159 2026-08-01 18:16:53 +00:00
praisonai-triage-agent[bot] 17091e1426 Merge pull request #3583 from MervinPraison/claude/issue-3582-20260801-1615
fix: remove orphaned legacy AutoGen tool-wrapper dead code
2026-08-01 17:14:40 +00:00
praisonai-triage-agent[bot]andMervin Praison 0b569f8427 fix: remove orphaned legacy AutoGen tool-wrapper dead code (fixes #3582)
Delete create_autogen_tool_function() and the 17 generated autogen_<Tool>
symbols plus their __all__ from inbuilt_tools/autogen_tools.py. Their only
consumer, ToolRegistry.register_builtin_autogen_adapters(), was removed in
the #1590 fix; the canonical AutoGen path is framework_adapters/autogen_adapter.py.

Keeps the praisonai_tools availability probe that feeds PRAISONAI_TOOLS_AVAILABLE
and the release `import *` smoke test.

Co-authored-by: Mervin Praison <[email protected]>
2026-08-01 16:16:56 +00:00
praisonai-triage-agent[bot] 2485e65fea Merge pull request #3579 from MervinPraison/claude/issue-3578-20260801-0914
fix: launch registered plugin channels via registry seam
2026-08-01 10:30:19 +00:00
praisonai-triage-agent[bot]andMervinPraison 92da64a23d fix: launch registered plugin channels via registry seam (fixes #3578)
Route WebSocketGateway._create_bot through the shared platform registry
(resolve_adapter) instead of a hardcoded if/elif over the seven built-ins.
Any channel the registry resolves — built-in, register_platform(), or a
praisonai.channels entry point — is now instantiated and started, with
ch_cfg passed through generically (mirroring probe_channels). An
unresolvable or unconstructable platform is recorded as a degraded channel
(visible in health/doctor) rather than a silent skip. Per-platform token
env-var fallbacks (email/AgentMail/Linear) are preserved.

Co-authored-by: MervinPraison <[email protected]>
2026-08-01 09:19:57 +00:00
praisonai-triage-agent[bot] e27d128f21 Merge pull request #3577 from MervinPraison/claude/issue-3576-20260801-0816
fix: close silent data/correctness gaps in praisonai wrapper
2026-08-01 09:13:41 +00:00
praisonai-triage-agent[bot]andMervin Praison 5a8e9ccbd6 fix: prevent agent_config leak on shared agents; warn on legacy chroma metric
- agent_invoke: _apply_agent_config now rejects overrides on non-isolatable
  (shared registry) agents instead of mutating a shared object, preventing
  config from leaking across concurrent/subsequent requests. Drop the
  never-settable `temperature` key from the whitelist so the surface is honest.
- vector_stores: warn (once per collection) when an existing/legacy Chroma
  collection uses a non-cosine distance metric, surfacing incomparable scores
  without a destructive auto-migration of stored vectors.

Co-authored-by: Mervin Praison <[email protected]>
2026-08-01 08:28:24 +00:00
praisonai-triage-agent[bot]andMervin Praison 13844802ad fix: close silent data/correctness gaps in praisonai wrapper (fixes #3576)
- ChromaVectorStore: centralise namespace->collection resolution so ad-hoc
  namespaces keep the cosine metric; return the stored embedding (not the
  query vector) from query(); scope delete_all to the caller's namespace.
- agent_invoke: honour agent_config overrides against the isolated clone
  via a whitelist, rejecting unknown/unsettable keys with 400 (route) or a
  clean error dict (standalone) instead of silently ignoring them.
- a2u_server.publish_sync: use get_running_loop, track the scheduled task
  (WeakSet) so it can't be GC'd and surface its exceptions; expose
  last_publish_task() for the real delivered count.
- push/client + acp/server: replace deprecated asyncio.get_event_loop()
  with get_running_loop()/to_thread inside coroutines.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-08-01 08:21:00 +00:00
MervinPraison 1fb210296b docs: auto-update documentation parity trackers [skip ci] 2026-08-01 08:12:49 +00:00
praisonai-triage-agent[bot] dd9b819190 Merge pull request #3574 from MervinPraison/claude/issue-3573-20260801-0715
fix: guardrail fail-closed, failover locking, tool-output run isolation
2026-08-01 08:12:18 +00:00
Mervin Praison 45b19a39d4 Merge pull request #3575 from MervinPraison/ci/scope-release-app-token
ci(release): scope the release app token to this repository
2026-08-01 08:35:45 +01:00
MervinPraisonandClaude Opus 5 138d2fcfce ci(release): scope the release app token to this repository
Both create-github-app-token steps omitted `repositories:`, so the run log
read "creating token for all repositories for given owner MervinPraison" --
the token carried write access to every repo under the account while the
job only ever touches PraisonAI.

Verified single-repo before narrowing: the workflow makes no cross-repo
call, and bump_and_release.py's only gh invocation is `gh release create`
against this repo, with all git operations on origin.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 08:35:25 +01:00
praisonai-triage-agent[bot]andMervin Praison 12e7304586 fix: run failover callbacks outside lock; fix second Gap-3 run-id typo
- failover.py: snapshot next_profile + callbacks under the RLock, then
  invoke callbacks after releasing it. User callbacks may block or take
  external locks; running them under the shared credential-pool lock could
  stall every concurrent agent and risk lock-ordering deadlocks (Greptile).
- chat_mixin.py: _run_id -> _current_run_id at the second tool-output
  truncation call site the PR missed; previously passed None into
  get_tool_output_store, defeating the run isolation Gap 3 restores.

Co-authored-by: Mervin Praison <[email protected]>
2026-08-01 07:25:36 +00:00
praisonai-triage-agent[bot]andMervinPraison f56c25bd78 fix: guardrail fail-closed, failover locking, tool-output run isolation (fixes #3573)
- LLMGuardrail.__call__ now fails closed on ambiguous LLM replies, matching
  _llm_validate() and the class's documented fail-closed contract.
- FailoverManager gains a threading.RLock guarding all _profiles reads/mutations
  and AuthProfile status transitions, since it is a shared credential pool by design.
- Fix _run_id -> _current_run_id typo that silently disabled tool-output
  run-scoped isolation; harden get_tool_output_store so a None run_id no longer
  adopts the first run's process-wide store.
- Add regression tests asserting both guardrail entry points fail closed.

Co-authored-by: MervinPraison <[email protected]>
2026-08-01 07:20:02 +00:00
Mervin Praison d8225b2285 Merge pull request #3572 from MervinPraison/fix/release-single-commit-bot-identity
ci(release): single commit per release, authored by praisonai-triage-agent[bot]
2026-08-01 07:34:32 +01:00
MervinPraison 466995f50d Release v4.6.158 2026-08-01 05:40:26 +00:00
MervinPraison 474d31a7e6 Bump praisonai-deploy to 0.0.2 2026-08-01 05:40:21 +00:00
MervinPraison d6ace26571 Bump praisonai-sandbox to 0.0.8 2026-08-01 05:40:15 +00:00
MervinPraison df27278f21 Bump praisonai-mcp to 0.0.10 2026-08-01 05:40:09 +00:00
MervinPraison 64b91aea2a Bump praisonai-browser to 0.0.10 2026-08-01 05:40:04 +00:00
MervinPraison d23124b0b0 Bump praisonai-train to 0.0.14 2026-08-01 05:39:58 +00:00
MervinPraison d44576cb1a Bump praisonai-bot to 0.0.43 2026-08-01 05:39:52 +00:00
MervinPraison ccd1e4d13a Bump praisonai-code to 0.0.58 2026-08-01 05:39:45 +00:00
MervinPraison 257c7ea615 Bump praisonaiagents to 1.6.162 2026-08-01 05:39:07 +00:00
praisonai-triage-agent[bot]andMervin Praison 146a0ed980 fix(deploy): harden compose Postgres defaults and fix Railway starter
- docker-compose: require POSTGRES_PASSWORD (no known fallback) and bind
  Postgres to loopback by default (POSTGRES_BIND) — resolves GitGuardian
  finding and the default-credentials exposure P1.
- railway starter: ship a Dockerfile so railway.json's DOCKERFILE build
  and start command reference real files (fixes missing-file P1).

Co-authored-by: Mervin Praison <[email protected]>
2026-08-01 05:33:31 +00:00
MervinPraisonandClaude Opus 5 327f5c3d42 ci(release): single commit per release, authored by the triage bot
A full pypi-release run landed 9 separate commits and 9 pushes on main --
one per package -- all authored as MervinPraison.

Collapse to one commit: delete the 8 per-package "Commit <pkg> version
bump" steps. They were redundant, since the wrapper step already calls
bump_and_release.py --no-add-all whose release_files list is a superset
of every file those steps staged, so all bumps now land in the script's
single "Release v<x.y.z>" commit. That needs --force, because the tree is
now dirty when the script runs and its pre-flight guard exits 1 under
--no-add-all; --no-add-all still restricts staging to the explicit list.

A trailing "Persist any uncommitted version bumps" step covers what the
single commit cannot: a package failing midway (those versions are
already live on PyPI, so the bumps must not be lost), skip_wrapper, or a
wrapper failure. It is a no-op on a clean run, and uses `git add -u` so
untracked build output stays out.

Attribute the release to praisonai-triage-agent[bot] by minting an
installation token from CLAUDE_APP_ID/CLAUDE_APP_PRIVATE_KEY -- the app
already behind that bot in claude.yml, claude-merge-gate.yml and
pipeline-status-sync.yml. GH_TOKEN is exported via $GITHUB_ENV, so the
commit, the tag push and gh release create are all the bot's;
secrets.GH_TOKEN is no longer referenced.

Two details this depends on: app tokens expire after 1h and this job can
exceed that (9 packages x up to a 600s PyPI wait each), so the token is
re-minted immediately before the wrapper release. And checkout sets
persist-credentials: false -- otherwise its http.extraheader would
outrank the remote URL and pin the first, expiring token.

Requires the App to be able to push to main (contents: write, plus a
ruleset bypass entry if main requires PRs).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-01 05:32:11 +00:00
Mervin Praison 27b85d1e86 Merge pull request #3563 from MervinPraison/feat/deploy-infra-relocation
Relocate deploy infra and expand praisonai-deploy surfaces
2026-08-01 06:30:48 +01:00
MervinPraison d0ed1a808a docs: auto-update feature parity trackers [skip ci] 2026-08-01 05:30:36 +00:00
Mervin Praison 888db30ea6 Merge pull request #3570 from MervinPraison/claude/issue-3566-20260731-1718
perf: guard BEFORE_LLM/AFTER_LLM hook payloads behind has_hooks() (hot-path)
2026-08-01 06:30:09 +01:00
Mervin Praison 89eb38dc65 Merge pull request #3571 from MervinPraison/claude/issue-3568-20260731-1719
fix: extract shared tool-argument hashing helper (#3568)
2026-08-01 06:29:53 +01:00
MervinPraison 1e30e9b06b docs: auto-update documentation parity trackers [skip ci] 2026-07-31 18:23:02 +00:00
praisonai-triage-agent[bot] 8074ce1d99 Merge pull request #3569 from MervinPraison/claude/issue-3567-20260731-1718
fix: dedupe rag/budget context-window table via canonical budgeter (fixes #3567)
2026-07-31 18:21:57 +00:00
praisonai-triage-agent[bot]andMervin Praison d3c15e9969 test: add parity regression tests for shared hash_tool_args (#3568)
Locks the tool-call identity contract shared by ApprovalRegistry and
DoomLoopDetector: sorted-key canonicalisation, default=str, 16-char
digest, None/empty equivalence, and the 'unhashable' fallback.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 17:29:08 +00:00
praisonai-triage-agent[bot]andMervin Praison 15f58fb7a5 fix: guard rag/budget extras against silently shadowing canonical table
Add the same overlap-guard assertion used in eval/tokens.py so RAG-specific
extras can never silently shadow canonical MODEL_LIMITS entries and re-introduce
the drift that #3567 fixed.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 17:27:55 +00:00
praisonai-triage-agent[bot]andMervinPraison eb37789745 fix: extract shared tool-argument hashing helper (fixes #3568)
Deduplicate the canonical tool-argument identity scheme
(json.dumps(sort_keys=True, default=str) -> sha256[:16]) that was
independently re-implemented in the approval registry and doom-loop
detector. Both safety subsystems now delegate to a single
hash_tool_args() helper in approval/utils.py, removing the drift risk
between approval de-duplication and doom-loop detection. Behaviour is
byte-for-byte identical (verified against the original scheme).

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 17:22:59 +00:00
praisonai-triage-agent[bot]andMervinPraison f89c9472d1 perf: build BEFORE_LLM/AFTER_LLM hook payloads only when a hook is registered (fixes #3566)
Guard the BEFORE_LLM and AFTER_LLM payload construction with the existing
registry.has_hooks() primitive, matching the idiom already used at the
AFTER_TOOL/BEFORE_TOOL/AFTER_AGENT/BEFORE_AGENT sites. Also skip the
str(result) stringification when the trace emitter is a disabled NoOp by
guarding on _trace_emitter.enabled. Behaviour is identical whenever a hook
or emitter is registered; zero cost on the hot path otherwise.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 17:21:31 +00:00
praisonai-triage-agent[bot]andMervinPraison 07767fea08 fix: source rag/budget context windows from canonical budgeter table (fixes #3567)
Deduplicate the model->context-window data by sourcing exact values from
context/budgeter.MODEL_LIMITS (the canonical table) and layering only
RAG-specific extras underneath, mirroring eval/tokens.py. This removes the
drift where gpt-4.1/gemini-1.5-pro resolved to different windows in RAG vs
the rest of the SDK. The get_model_context_window wrapper (None guard,
normalisation, prefix/heuristic fallbacks) is unchanged.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 17:21:22 +00:00
praisonai-triage-agent[bot] bc00ad8092 Merge pull request #3565 from MervinPraison/claude/issue-3564-20260731-1616
refactor: consolidate duplicated argv flag/value walk in praisonai CLI router
2026-07-31 17:01:48 +00:00
praisonai-triage-agent[bot]andMervinPraison 38c8dda69c refactor: consolidate duplicated argv flag/value walk in praisonai CLI router (fixes #3564)
Extract a single _iter_argv_tokens classifier as the one source of truth for
flag/value-consumption semantics. _find_first_command, _flag_names and
_build_run_argv now all consume it, so routing and rewrite can no longer
diverge. _find_first_command accepts the shared value_opts (defaulting to the
historical narrow static set) rather than a separate hardcoded VALUE_FLAGS.
Behaviour-preserving internal DRY refactor; no CLI surface change.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 16:19:17 +00:00
praisonai-triage-agent[bot]andMervin Praison 93ad8c5aca fix(deploy): resolve reviewer findings in C14 deploy surfaces
CLI (cli/features/deploy.py):
- extract compose up|down action before generic parse so `compose up`
  without --file no longer sets file="up"
- drop duplicate `-r` key (F601) so --region short flag works again
- route `doctor --provider fly|railway|render` via provider registry
- wrap the four new handlers in the class try/except convention
- thread --force into create scaffolding

compose.py:
- _ensure_postgres_password now resolves the *effective* (last) value,
  handling quoted-empty and inline-comment cases
- restrict generated project .env to 0600 on POSIX
- report the effective host API port (runtime env → .env → default)
- add 600s timeouts to docker compose up/down

helm.py: add 600s timeout to helm upgrade

starters.py: refuse to overwrite existing files unless force=True

Helm agents-api deployment.yaml:
- pass agents/port/serverFile via env vars (no Python-source injection)
- include POSTGRES_PASSWORD in DATABASE_URL via k8s $(VAR) interpolation

starters: railway.json/render.yaml use the prebuilt GHCR image instead of
a nonexistent Dockerfile/api_server.py; fix compose+helm README manifest links.

Adds regression tests (160 passed).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 13:07:56 +00:00
praisonai-triage-agent[bot]andMervin Praison 1c14207af9 fix(deploy): resolve GitGuardian false-positives on secret-like test literals
Split the "POSTGRES_PASSWORD:-praisonai" and "change-me" string literals in
the compose security regression tests so GitGuardian no longer flags them as
hardcoded secrets. The assertions still guard the exact same behaviour (no
default password baked into compose; generated password differs from the old
placeholder). Also replace the static "change-me" placeholder in the
agents-api Helm README with an openssl-generated example.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 12:21:49 +00:00
praisonai-triage-agent[bot]andMervin Praison 7aa1b9f18e fix(deploy): remove hardcoded compose DB password and stop exposing Postgres
- docker-compose.yml: drop `:-praisonai` default password (GitGuardian);
  require POSTGRES_PASSWORD via `:?` and bind Postgres to 127.0.0.1 by default
- .env.example: ship empty POSTGRES_PASSWORD (no repo-known credential) + POSTGRES_BIND
- compose.py: auto-generate a strong POSTGRES_PASSWORD into project .env when empty
- README + tests: document security defaults and guard against regressions

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 12:18:42 +00:00
MervinPraisonandCursor b536e4fc37 Relocate deploy infra under package trees and expand C14 deploy surfaces.
Move gateway Helm to praisonai-bot/infra, compose/starters/agents-api Helm to
praisonai-deploy/infra (not PyPI), add central path resolver, compose/helm/create
CLI, optional Fly/Railway/Render providers, and CI helm gates with 145 deploy tests.

Co-authored-by: Cursor <[email protected]>
2026-07-31 13:11:02 +01:00
Mervin Praison ce3fd23f4a Merge pull request #3515 from MervinPraison/claude/issue-3514-20260730-0716
fix: three silent-failure bugs in praisonaiagents core
2026-07-31 12:36:00 +01:00
Mervin Praison 1aa8c34d46 Merge pull request #3538 from MervinPraison/claude/issue-3537-20260730-1713
fix: remove dead/redundant imports in tools and agent modules
2026-07-31 12:35:26 +01:00
Mervin Praison cd6b8db527 Merge pull request #3539 from MervinPraison/claude/issue-3536-20260730-1712
fix: share workflow step-loop between execute and aexecute
2026-07-31 12:35:10 +01:00
MervinPraison 9963eaa9fc docs: auto-update documentation parity trackers [skip ci] 2026-07-31 11:33:33 +00:00
Mervin Praison 0c5f550c2f Merge pull request #3551 from MervinPraison/claude/issue-3550-20260731-0854
fix: unify permission presets onto one PermissionMode model
2026-07-31 12:32:59 +01:00
praisonai-triage-agent[bot] 6b5a5803b3 Merge pull request #3562 from MervinPraison/claude/issue-3559-20260731-0946
fix: keep tool_call/result pairs intact during context compaction
2026-07-31 11:22:18 +00:00
MervinPraison 6b4c136aca docs: auto-update documentation parity trackers [skip ci] 2026-07-31 11:12:36 +00:00
praisonai-triage-agent[bot] 36dace2c0e Merge pull request #3561 from MervinPraison/claude/issue-3560-20260731-0947
fix: serve last-good tool availability on transient probe failure
2026-07-31 11:12:03 +00:00
MervinPraison c7bdada813 docs: auto-update documentation parity trackers [skip ci] 2026-07-31 10:55:57 +00:00
praisonai-triage-agent[bot] 29550ed32a Merge pull request #3556 from MervinPraison/claude/issue-3554-20260731-0918
fix: add gateway doctor --fix to mint a strong auth token and re-validate
2026-07-31 10:55:25 +00:00
praisonai-triage-agent[bot] ffcfe8c36d Merge pull request #3555 from MervinPraison/claude/issue-3553-20260731-0917
fix: fail fast on unresolved tools at gateway start
2026-07-31 10:49:50 +00:00
praisonai-triage-agent[bot] 9887d14842 Merge pull request #3552 from MervinPraison/claude/issue-3549-20260731-0854
fix: wire subtree AGENTS.md context hook into praisonai run
2026-07-31 10:43:50 +00:00
praisonai-triage-agent[bot] 36fa8b1c39 Merge pull request #3548 from MervinPraison/claude/issue-3547-20260731-0818
fix: AgentOS /chat session isolation + drop call.py import-time dotenv side effect
2026-07-31 10:38:10 +00:00
praisonai-triage-agent[bot]andMervin Praison f303babc15 fix: keep tool pairs intact in TRUNCATE compaction (fixes #3559)
TRUNCATE is the default compaction strategy but did not preserve
tool_calls/result pairs: the recent-window slice could orphan a tool
result, and the token-budget pop loop could drop an assistant
tool_calls message while leaving its tool result behind. Snap the
recent boundary and drop leading tool pairs atomically so strict
providers never receive an orphaned tool message.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:58:10 +00:00
praisonai-triage-agent[bot]andMervin Praison c79740e894 fix: evict stale availability state on tool replacement (#3560)
When register(..., overwrite=True) replaces a tool under the same name,
evict the previous tool's availability cache and last-success timestamp so
a broken replacement can't be served as available on its first failing
probe via the inherited grace window.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:56:39 +00:00
praisonai-triage-agent[bot]andMervinPraison 893b7128cc fix: keep tool_call/result pairs intact during context compaction (fixes #3559)
Compaction strategies chose their recent/older boundary purely by token or
message count, which could split an assistant tool_calls message from its
matching tool result. The resulting orphaned tool message made strict
providers (OpenAI/Anthropic/Azure) reject the transcript with a 400,
wedging long-lived gateway/bot sessions on every subsequent turn.

Add ContextCompactor._snap_to_pair_boundary() which moves a chosen boundary
outward so a tool pair is never separated, and apply it in _sliding_window,
_summarize, _prune, _llm_summarize and _llm_summarize_async. Behaviour-only,
backward compatible, no new knobs.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 09:52:03 +00:00
praisonai-triage-agent[bot]andMervinPraison 7524cbd211 fix: serve last-good tool availability on transient probe failure (fixes #3560)
Track last-success timestamp per tool in ToolRegistry. On a probe
exception within a grace window of a recent success, serve the last-good
True and skip caching a durable negative, so a flaky availability check
no longer strips a healthy tool from a long-lived agent. Sustained
failures beyond the grace window still mark the tool unavailable.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 09:49:55 +00:00
praisonai-triage-agent[bot]andMervin Praison 319452c1a7 fix: stop AgentOS chat tests leaking a global achat monkeypatch
The new TestAgentOSChatSessionIsolation tests replaced Agent.achat at the
class level (`type(template).achat = _fake_achat`) and never restored it,
so the stub leaked into test_async_gemini_fix.py where the real achat is
called with a `tools=` kwarg the stub did not accept.

Use pytest's monkeypatch fixture (auto-restore) and accept *args/**kwargs
in the stub so it matches the real achat signature.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:30:58 +00:00
praisonai-triage-agent[bot]andMervin Praison 2a12f78c5b fix: load persisted env in tool preflight; skip self-suggest typos
Addresses reviewer feedback on #3555:
- Greptile P1: _preflight_tools now loads ~/.praisonai/.env before resolving
  so a local tools.py enabled via PRAISONAI_ALLOW_LOCAL_TOOLS in that file is
  not falsely rejected in strict mode (mirrors GatewayHandler.start).
- CodeRabbit: describe_unresolved excludes the exact name from difflib typo
  candidates so a mapped-but-unloadable tool yields an install/generic hint
  instead of a useless "Did you mean '<same name>'?".
- Add regression tests for both.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:29:59 +00:00
praisonai-triage-agent[bot]andMervin Praison 7f8a2d0802 fix(gateway): rewrite explicit weak YAML auth_token during doctor --fix
An explicit (non-${ENV}) weak gateway.auth_token in gateway.yaml wins over
GATEWAY_AUTH_TOKEN at both startup (GatewayConfig.auth_token) and doctor
re-validation, so the env-only repair left the weak YAML value active and
falsely reported success. The repair now also rewrites the YAML token in
place when it holds an explicit weak value, while preserving ${ENV}
references. Fixes Greptile P1 on #3556.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:29:39 +00:00
MervinPraison 89adc132f9 docs: auto-update api.md [skip ci] 2026-07-31 09:23:52 +00:00
praisonai-triage-agent[bot]andMervinPraison d081519054 fix: add gateway doctor --fix to mint a strong auth token and re-validate (fixes #3554)
The degraded registry's retry_hint advertised `praisonai gateway doctor --fix`,
but no such flag existed — a dead-end on the gateway's primary recovery path.
Add `--fix`/`--dry-run` to `gateway doctor` that mints a strong GATEWAY_AUTH_TOKEN
when weak/missing, persists it to ~/.praisonai/.env (same store as onboard), and
re-validates the finding cleared. Align the core retry_hint docstring so the
advertised command is guaranteed to exist.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 09:23:24 +00:00
Mervin Praison 09c85f1bd1 Merge pull request #3546 from MervinPraison/feat/c14-praisonai-deploy
feat(c14): extract praisonai-deploy as tier-2 package
2026-07-31 10:23:19 +01:00
praisonai-triage-agent[bot]andMervinPraison c974f212da fix: fail fast on unresolved tools at gateway start (fixes #3553)
Add a start-time tool pre-flight gate so a mistyped, uninstalled, or
gated tool named in gateway.yaml is surfaced with a per-name reason and
fix hint instead of being silently skipped. Strict by default (mirrors
the credential pre-flight); --no-strict-tools / strict_tools: false
preserve today's skip-and-continue.

- tool_resolver.py: add describe_unresolved() (difflib "did you mean" +
  local-tools/dependency hints) and a module-level wrapper.
- gateway start: add --strict-tools/--no-strict-tools and a
  _preflight_tools() gate reusing the existing validate_yaml_tools.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 09:23:06 +00:00
praisonai-triage-agent[bot]andMervin Praison 30017afee5 fix(c14-deploy): correct CLI/YAML merge, azure update, scheduler robustness
- cli/features/deploy.py: API & Cloud shortcut commands now honor deploy.api
  and deploy.cloud YAML when CLI flags are unset (defaults changed to None
  sentinels; explicit CLI still overrides). Fixes YAML being silently ignored.
- providers/azure.py: create->update fallback now builds a proper
  `az containerapp update` command (previous `cmd[1]='update'` produced the
  invalid `az update containerapp`); env vars passed under a single --env-vars
  flag so later pairs no longer override earlier ones.
- scheduler/deployment.py: replace buggy nested DeployArgs (dead self-ref,
  missing attrs) with SimpleNamespace carrying all fields handle_deploy reads;
  derive success from SystemExit code instead of always True; interruptible
  retry wait via _stop_event so stop() works; drop unused time import.
- main.py: replace `assert docker_cfg` with explicit ValueError (assert is
  stripped under python -O).
- _wrapper_bridge.py: optional_wrapper_attr now returns default when attr is
  missing, not just on ImportError.
- docker.py: prepare_docker_build_context validates agents file before writing
  api_server.py; docker_container_name sanitizes invalid chars.
- tests: add regression tests for API and Cloud YAML merge precedence.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:11:58 +00:00
praisonai-triage-agent[bot]andMervin Praison 2f44441a31 fix: C7-compliant subtree hook import + propagate --no-rules everywhere
- Route the optional subtree-context helper through praisonai_bot (canonical
  home) with a praisonai wrapper-shim fallback, removing the module-/function-
  level ``from praisonai`` import that tripped the C7 hot-path import gate
  (fixes smoke: test_c7_import_gate_script_passes). Feature now also works on
  installs shipping praisonai_bot without the full wrapper.
- Propagate --no-rules to the custom-agent and profiled prompt paths
  (_run_custom_agent, _run_prompt_profiled) so the opt-out is honoured on every
  non-interactive Agent construction site, not just _run_prompt.
- Add an execution-path test asserting all three paths accept/forward no_rules.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:10:04 +00:00
praisonai-triage-agent[bot]andMervin Praison 8e23806604 fix(permissions): make ACCEPT_EDITS auto-approve edit tools; correct resolver docstring
- ACCEPT_EDITS previously set _permission_mode but the decision resolver
  deferred it (no-op), so advertised auto-accept-edits behaviour never
  applied. Add an ACCEPT_EDITS branch that auto-approves edit-class tools
  (write/edit/append/create/save/patch/mkdir) via a new _is_edit_tool
  heuristic, deferring destructive/exec/external tools to normal flow.
- Remove the misleading `read_only`-as-mode line from PermissionMode.resolve
  docstring (read_only is a deny-set preset and resolves to None).
- Tests: auto-approve edit tools, defer non-edit tools, auto_edit alias.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 09:06:30 +00:00
praisonai-triage-agent[bot]andMervinPraison bbe4fdd25a fix: wire subtree AGENTS.md context hook into praisonai run (fixes #3549)
The interactive REPL lazily attaches a subdirectory's AGENTS.md/CLAUDE.md the
first time the agent reads/edits a file under it, but the scriptable
`praisonai run` path built Agent(**agent_config) without it. In a monorepo,
`praisonai run "refactor packages/foo/bar.py"` therefore never picked up
packages/foo/AGENTS.md while `praisonai chat` in the same repo did.

Reuse the existing subtree hook (praisonai.integration.context_files) and the
existing Agent(hooks=...) seam via a small `_wire_subtree_context_hook` helper,
registered on a fresh session-scoped registry at all three run.py Agent sites.
Gated by the existing --no-rules / PRAISON_NO_RULES off-switch and honouring the
shared PRAISON_CONTEXT_BUDGET character budget. No new Agent params, no new core
module, no agent.py changes — keeping the surface area unchanged.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 09:00:51 +00:00
praisonai-triage-agent[bot]andMervinPraison 53089306b6 fix: unify permission presets onto one PermissionMode model (fixes #3550)
Add PermissionMode.resolve() as the single mapper from historical mode
spellings (AutonomyMode/ApprovalMode/CLI-flag aliases) onto the canonical
PermissionMode enum, and route the existing Agent(approval=<preset>) string
branch through it. Agent(approval='plan'|'bypass'|'accept_edits'|'dont_ask')
(plus aliases like yolo/auto_edit/reject/full_auto) now resolve to one
coherent model. Deny-set presets (safe/read_only/full/off/default) keep
their exact behaviour. No new Agent params or exports.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 08:59:39 +00:00
praisonai-triage-agent[bot]andMervin Praison 21adfa4702 fix: refresh call.py env globals after dotenv + guard AgentOS clone when handoffs configured
- call.py: module globals (OPENAI_API_KEY, CALL_SERVER_TOKEN, NGROK_AUTH_TOKEN,
  rate limits) were frozen at import, before main()'s explicit load_dotenv(),
  so a .env-only key was silently ignored. Add _refresh_env_globals() invoked
  after load_dotenv() (also refreshes the n8n router's CALL_SERVER_TOKEN).
- agentos.py: clone_for_channel intentionally drops handoffs; agents with
  handoffs now stay on the shared template so delegation is never silently lost.
- test: cover the handoffs-not-cloned path (9 passed).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 08:58:43 +00:00
MervinPraison e3e1134387 docs: auto-update feature parity trackers [skip ci] 2026-07-31 08:29:08 +00:00
praisonai-triage-agent[bot] 9a0950cd1a Merge pull request #3545 from MervinPraison/claude/issue-3544-20260731-0711
fix: permission scope bypass, guardrail fail-open, and fake delegator cancellation
2026-07-31 08:28:36 +00:00
praisonai-triage-agent[bot]andMervinPraison 6f3b872b18 fix: AgentOS /chat session isolation + drop call.py import-time dotenv side effect (fixes #3547)
Gap 1: /chat now clones a per-request/session agent (reusing the existing
_supports_session_isolation / _clone_agent helpers from api/agent_invoke.py)
so concurrent callers no longer share mutable chat_history, and session_id is
bound to the clone instead of merely echoed. Plain mocks fall back to the
shared instance for backward compat.

Gap 2 (minimal): api/call.py no longer calls load_dotenv() unconditionally at
import time; it is gated behind PRAISONAI_CALL_LOAD_DOTENV and loaded
explicitly in main() so the CLI keeps working. Importing the module no longer
mutates os.environ.

Gap 3 rejected as scope creep (breaking public-API churn with a deprecation
window; deferred per the issue).

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 08:23:22 +00:00
praisonai-triage-agent[bot]andMervin Praison 3a780fcb0e fix(c14-deploy): harden generated API server + align GHSA codegen test
- Docker deploy no longer disables auth by default; falls back to the
  secure APIConfig() default (auth_enabled=True, token auto-generated)
  instead of exposing an unauthenticated /chat on 0.0.0.0 (Greptile P1).
- Write the generated API server into a private per-invocation mkdtemp
  (mode 0700) instead of a predictable shared tmp path, preventing
  local replacement before launch (Greptile P1).
- Update pre-existing GHSA deploy-codegen test to assert the genuine
  security property (repr-escaped path, no raw injection) rather than the
  old implementation-coupled `PraisonAI(agent_file=...)` string; the PR
  intentionally forwards the chat message via the wrapper `run(..., cli_config)`
  entrypoint since `PraisonAI.run()` takes no args.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 07:54:09 +00:00
praisonai-triage-agent[bot]andMervin Praison 4d9832ff85 fix(guardrail): init logger before LLM init and use is-None check; add scope regression test
- llm_guardrail: assign self.logger before _initialize_llm so unsupported/
  string-fail/dict-fail paths can log and fail closed instead of raising
  AttributeError (CodeRabbit major).
- llm_guardrail: __call__ now checks `self.llm is None` (matches _llm_validate)
  instead of truthiness (CodeRabbit minor).
- tests/permissions: lock the scoped-approval bypass fix — an agent-scoped
  approval must reject an unnamed (agent_name=None) caller.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 07:44:47 +00:00
praisonai-triage-agent[bot]andMervin Praison 7928a090b2 fix(delegator): correct cancellation semantics for CI + reviewer feedback
- cancel_task now cancels any non-terminal task (PENDING or RUNNING),
  fixing test_cancel_task regression and Greptile P1: queued/PENDING
  delegations no longer escape cancel_all.
- delegate() re-raises external CancelledError (Greptile P1) and only
  swallows delegator-initiated cancels into a result, so wait_for /
  cooperative shutdown behave correctly.
- _execute_task and the semaphore-guarded path early-return when a cancel
  landed before execution, so a cancelled task never runs.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 07:39:32 +00:00
MervinPraisonandCursor c7ad408ba9 feat(c14): extract praisonai-deploy as tier-2 package
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]>
2026-07-31 08:37:21 +01:00
praisonai-triage-agent[bot] fff8336c70 Merge pull request #3543 from MervinPraison/claude/issue-3542-20260731-0635
feat: add praisonai skills add <url> command
2026-07-31 07:35:07 +00:00
MervinPraison 82f19e0b36 docs: auto-update documentation parity trackers [skip ci] 2026-07-31 07:29:14 +00:00
praisonai-triage-agent[bot] a04abb943a Merge pull request #3541 from MervinPraison/claude/issue-3540-20260731-0614
fix: unify @tool(approval=...) and launch(protocol="mcp") with SDK conventions
2026-07-31 07:28:40 +00:00
praisonai-triage-agent[bot]andMervinPraison a938e7356c fix: close permission scope bypass, guardrail fail-open, and fake delegator cancellation (fixes #3544)
- permissions/rules.py: PersistentApproval.matches now rejects agent-scoped
  approvals for callers that can't prove identity (including agent_name=None),
  closing the short-circuit bypass while leaving unscoped approvals unaffected.
- guardrails/llm_guardrail.py: LLMGuardrail.__call__ now fails closed on a
  missing/unsupported LLM, matching its docstring and sibling _llm_validate.
- agents/delegator.py: cancel_task/cancel_all now propagate cancellation to the
  real asyncio.Task; _execute_task no longer clobbers a CANCELLED status with a
  late COMPLETED assignment.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 07:16:37 +00:00
praisonai-triage-agent[bot]andMervinPraison cc50461158 feat: add praisonai skills add <url> alias (fixes #3542)
Add a `skills add` subcommand as a thin alias over the existing
`skills install` path so `praisonai skills add https://...` works,
mirroring the familiar `npx skills add <url>` verb. Reuses existing
install/remote-fetch machinery; no new deps, modules, or core params.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 06:38:46 +00:00
praisonai-triage-agent[bot]andMervin Praison 860d332994 fix: warn on explicit requires_approval=False and handle late MCP transport ImportError
- @tool(requires_approval=False) now emits DeprecationWarning (any use of the
  deprecated spelling nudges migration); use a sentinel to tell "omitted" from
  explicit False. approval= still wins for the resolved value.
- Agent/PraisonAIAgents launch(protocol="mcp") now keep the serve_agents() call
  inside the ImportError guard, so a praisonai-mcp installed without its
  transport extras yields one actionable install message instead of an uncaught
  traceback.
- Tests: explicit-False-warns, omitted-no-warn, both-set-warns, and
  missing-transport-extras for single- and multi-agent launch.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 06:28:41 +00:00
praisonai-triage-agent[bot]andMervinPraison f31ca0d01e fix: unify @tool(approval=...) and launch(protocol="mcp") with SDK conventions (fixes #3540)
- @tool now accepts canonical approval= (mirrors Agent(approval=...));
  requires_approval= kept as a deprecated alias with a DeprecationWarning,
  approval= wins when both set. Both funnel to the same ApprovalRegistry.
- PraisonAIAgents.launch(protocol="mcp") and Agent.launch(protocol="mcp")
  now both delegate to praisonai_mcp.serve_agents (lazy import, clear
  "pip install praisonai-mcp" error). Replaces the bespoke single-agent SSE block.
- Add praisonai_mcp naming constants list_sessions / awaiting_approval.
- http launch behaviour untouched.

Co-authored-by: MervinPraison <[email protected]>
2026-07-31 06:21:07 +00:00
praisonai-triage-agent[bot]andMervin Praison 4bdba3757a fix: halt workflow on loop stop-on-error and checkpoint completed loop steps
A stop-on-error failure inside a loop_over step now aborts the whole
workflow instead of only the inner item iteration, and a completed
loop_over step now persists a checkpoint so resume does not re-run every
loop item. Both fixes live in the shared _run_workflow_loop generator so
they apply to sync execute() and async aexecute() alike.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 17:25:42 +00:00
praisonai-triage-agent[bot] 2ebbafb0c6 Merge pull request #3535 from MervinPraison/claude/issue-3533-20260730-1618
fix: wire praisonai unified to bundled ui_dashboard preset
2026-07-30 17:24:11 +00:00
praisonai-triage-agent[bot]andMervinPraison a744836735 fix: share workflow step-loop between execute and aexecute (fixes #3536)
Extract the duplicated step-loop from execute() and aexecute() into a single
sans-io generator (_run_workflow_loop) that owns all orchestration:
condition-skip, loop_over iteration, checkpoint save/resume, branch_condition/
next_steps routing, early-stop and on_error handling.

execute() drives it with the sync _execute_single_step; aexecute() drives the
same generator with a new async _aexecute_single_step that awaits async
executors / agent.achat / async handlers (true-async preserved).

This restores loop_over, branch, and checkpoint/resume parity to the async
path and adds checkpoint/resume params to aexecute. Public signatures and
return shapes are unchanged.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 17:19:13 +00:00
praisonai-triage-agent[bot] 73fcbdcf2c Merge pull request #3534 from MervinPraison/claude/issue-3532-20260730-1617
fix: remove dead adapter-loader functions in registry.py
2026-07-30 17:19:04 +00:00
praisonai-triage-agent[bot]andMervinPraison 1d709e6773 fix: remove dead/redundant imports in tools and agent modules (fixes #3537)
- tools/base.py: drop unused annotation_to_json_schema, get_parameter_requirements
- tools/decorator.py: drop unused annotation_to_json_schema, get_parameter_requirements
- agent/handoff.py: remove duplicate import contextvars

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 17:14:19 +00:00
praisonai-triage-agent[bot] 624da31af3 Merge pull request #3531 from MervinPraison/claude/issue-3528-20260730-1539
feat: first-class serve_agents() MCP path + memory/agent adapter fixes
2026-07-30 16:45:30 +00:00
MervinPraison 11d2c9fbd6 docs: auto-update documentation parity trackers [skip ci] 2026-07-30 16:40:04 +00:00
praisonai-triage-agent[bot] 45c6a71647 Merge pull request #3530 from MervinPraison/claude/issue-3529-20260730-1540
feat: add @tool(requires_approval=...) declaration
2026-07-30 16:39:29 +00:00
praisonai-triage-agent[bot]andMervin Praison 2912b1f08c fix: route bundled aiui preset load failures to host_app fallback
Catch import errors in _load_bundled_dashboard_app so that when the
bundled ui_dashboard preset is unavailable, the loader returns None and
the existing build_host_app fallback runs, instead of the exception
escaping to the outer handler and dropping aiui to the standard dashboard.

Addresses Greptile (P1) and CodeRabbit (Major) review findings on #3535.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 16:25:13 +00:00
praisonai-triage-agent[bot]andMervinPraison 811df19f7d fix: wire praisonai unified to bundled ui_dashboard preset (fixes #3533)
Route _run_aiui_dashboard through the bundled ui_dashboard/default_app.py
preset so the documented 9-page unified dashboard actually ships, making
the preset the single source of truth instead of a divergent hardcoded
5-page list. Falls back to the previous build_host_app defaults if the
preset cannot be loaded. Adds the missing ui_dashboard/__init__.py for
consistency with the other bundled UI presets.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 16:20:29 +00:00
praisonai-triage-agent[bot]andMervinPraison 5b37214dcb fix: remove five unreferenced adapter-loader functions in registry.py (fixes #3532)
Co-authored-by: MervinPraison <[email protected]>
2026-07-30 16:18:13 +00:00
praisonai-triage-agent[bot]andMervin Praison c55ae27e86 fix: isolate agent sessions, prevent tool-name collisions & bad transport
- Namespace per-session transcripts by tool name so reusing a client
  session_id across different ask_* agents no longer leaks history.
- Serialize each session's load->run->save under a per-session lock to
  stop concurrent turns clobbering each other's completed turn.
- Disambiguate agents whose names normalize to the same tool suffix so a
  later registration never silently shadows an earlier agent.
- Raise ValueError on unknown serve_agents() transport instead of
  silently falling back to http-stream.
- Add regression tests for all four cases.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 15:51:37 +00:00
praisonai-triage-agent[bot]andMervin Praison 3e19b1e73a fix: fail closed and validate risk level in @tool(requires_approval)
Address reviewer P1 security findings on PR #3530:

- Fail closed: if registering the approval requirement raises, the
  decorator now re-raises RuntimeError instead of logging and handing
  back an executable but ungated tool.
- Validate risk-level strings against ("critical","high","medium","low")
  so a typo like requires_approval="critial" is rejected up front rather
  than silently treated as non-critical.

Adds regression tests for both cases.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 15:50:02 +00:00
praisonai-triage-agent[bot]andMervinPraison 15ebe6951e feat: add serve_agents() MCP path + fix memory adapter & throwaway agent proxy (fixes #3528)
- praisonai-mcp: new serve_agents() + agent_adapter publishing ask_{name}
  per agent and list_agents, with per-call session_id minting and in-adapter
  per-session transcript continuity, running over the existing spec-compliant
  http-stream transport. Server-side agents only; no client-set instructions.
- Fix Defect C: rebind memory adapter to the real core API
  (store_short_term/search/get_all_memories/reset_all); the old bindings
  (get_session/get_all/clear_session/clear_all/list_sessions/add) never existed.
- Drop client-controllable `instructions` from praisonai.agent.chat/run so the
  connecting client can no longer rewrite the persona.
- Tests for per-agent tools, session continuity, no-client-instructions, and
  memory adapter against the real API.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 15:44:21 +00:00
praisonai-triage-agent[bot]andMervinPraison 6dc871c75a feat: add @tool(requires_approval=...) declaration (fixes #3529)
Adds a one-place approval declaration to the @tool decorator that
registers the tool with the existing global ApprovalRegistry at
definition time. `requires_approval=True` maps to the "high" risk
level; a string sets the risk level explicitly. No behaviour change
when unset. Backward compatible.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 15:42:45 +00:00
praisonai-triage-agent[bot] 688d76a18f Merge pull request #3525 from MervinPraison/claude/issue-3522-20260730-0933
feat: add minimal praisonai-gateway Helm chart
2026-07-30 10:47:27 +00:00
MervinPraison ed0f420c26 docs: auto-update documentation parity trackers [skip ci] 2026-07-30 10:43:01 +00:00
praisonai-triage-agent[bot] 411c63341f Merge pull request #3527 from MervinPraison/claude/issue-3526-20260730-0946
fix: honour wall-clock cron in standalone schedulers
2026-07-30 10:42:29 +00:00
praisonai-triage-agent[bot] a64c3c86a3 Merge pull request #3521 from MervinPraison/claude/issue-3519-20260730-0919
fix: age-gate durable-queue dead-lettering to survive transient outages
2026-07-30 10:42:20 +00:00
MervinPraison 6007e13749 docs: auto-update feature parity trackers [skip ci] 2026-07-30 10:38:30 +00:00
praisonai-triage-agent[bot] e14c411575 Merge pull request #3520 from MervinPraison/claude/issue-3518-20260730-0918
fix: add unified degraded-capability registry for gateway
2026-07-30 10:38:05 +00:00
praisonai-triage-agent[bot]andMervin Praison 0022a4d81d fix: persist current cron slot & warn when croniter missing (#3526 review)
Addresses two valid reviewer findings on PR #3527:

- Stale anchor: the sync & async loops advanced `_last_run_at` *after*
  `_execute_with_retry` persisted daemon state, so a restart restored the
  prior slot and replayed an already-completed run/delivery. Mark the
  wall-clock anchor *before* executing so the state write records this slot.
- Silent degrade: without the optional `croniter` engine a `cron:` schedule
  reverted to the pre-#3526 process-relative interval with no signal. Emit a
  one-time actionable warning (matching core `scheduler.due`) instead.

Tests: new default-install warning + state-persistence cases (run without
croniter); ticker cron tests gated per-class so they no longer skip the
whole module. Scheduler suite: 259 passed (3 pre-existing dotenv env
failures unrelated).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 10:06:09 +00:00
praisonai-triage-agent[bot]andMervinPraison fdaf0e2772 fix: honour wall-clock cron in standalone schedulers (fixes #3526)
The AgentScheduler / AsyncAgentScheduler wrapper loops collapsed cron
expressions to a coarse integer interval anchored to process start, so a
"daily 09:00 brief" fired at whatever o'clock the daemon launched, re-phased
on restart, and silently dropped runs across downtime/dormancy.

Add a lightweight, wrapper-local ScheduleTicker that reuses core's croniter
engine to sleep until the next real wall-clock occurrence, catch up a missed
slot exactly once on resume, and persist last_run_at in the existing daemon
state file so restarts don't re-phase. Plain intervals (hourly, */30m, raw
seconds) keep identical behaviour. No new core surface, exports, or params.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 09:56:06 +00:00
praisonai-triage-agent[bot]andMervin Praison e45cdfbaf5 fix: correct gateway auth secret wiring in Helm chart
- Always inject the env var as GATEWAY_AUTH_TOKEN (the only name the gateway
  reads); auth.secretKey now only selects the Secret data key.
- validateAuth now fails fast whenever auth.enabled is true without a token
  source, not only when ingress is also enabled — the default install
  previously referenced a Secret that was never created.
- Update README security note to match the stronger validation.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 09:42:38 +00:00
praisonai-triage-agent[bot] 85b1e0765a Merge pull request #3517 from MervinPraison/claude/issue-3516-20260730-0832
fix: repair approval config crash, async-loop safety, dropped agent flags
2026-07-30 09:40:33 +00:00
praisonai-triage-agent[bot]andMervin Praison 9adcc9a749 fix: keep age-gated dead-lettering on older core via local fallback policy
The bot's dependency floor (praisonaiagents>=1.6.152) admits core releases
that predate AttemptAndAgeDeadLetterPolicy (first shipped 1.6.161). On those
installs the import guard previously bound None and both durable queues
silently reverted to attempt-only dead-lettering, re-introducing the #3519
transient message loss. Add a dependency-free LocalDeadLetterPolicy in
_resilience (mirroring core semantics: attempt+age gate, permanent-error
short-circuit, min_age=0 legacy) and bind it as the import fallback so the
age gate holds on any allowed core version. Adds older-core coverage tests.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 09:39:14 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy dfa0035dab feat: add minimal praisonai-gateway Helm chart (fixes #3522)
Ship a single, self-contained Helm chart under deploy/helm/praisonai-gateway
that reuses the existing GHCR image (no new build pipeline, no core code
change). Grounded in real gateway behaviour: port 8765, /health probes, and
GATEWAY_AUTH_TOKEN via a Kubernetes Secret. Includes optional ingress with
WebSocket-friendly annotations and an optional CPU HPA. Chart refuses to render
if the gateway would be exposed via ingress without an auth token.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-30 09:37:08 +00:00
praisonai-triage-agent[bot]andMervin Praison 1d05e81e7a fix: enforce degraded vocabularies + wire live producer (PR #3520)
- Enforce closed OWNER_KINDS/DEGRADED_STATES in DegradedOwner.__post_init__
  so unsupported values can never reach operator-facing records (Greptile P2).
- Route the existing channel-credential degradation path through new
  gateway helpers _mark_degraded_owner/_clear_degraded_owner so the shared
  _degraded_registry has a genuine live producer feeding degraded_owners,
  not just an empty registry read by health() (Greptile P1).
- Drop unused dataclasses.field import; add vocabulary-rejection tests.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 09:30:34 +00:00
praisonai-triage-agent[bot]andMervinPraison c5a2809281 fix: age-gate durable-queue dead-lettering to survive transient outages (fixes #3519)
Dead-lettering decided on attempt-count alone burned the default five
attempts in ~45s of channel outage, permanently dropping deliverable
inbound/outbound messages during routine transient incidents.

Add a core DeadLetterPolicyProtocol + default AttemptAndAgeDeadLetterPolicy
in praisonaiagents/gateway that requires BOTH attempt-exhaustion AND a
minimum wall-clock age (default 6h) before dead-lettering, while known
permanent errors (credential/permanent_target) still short-circuit. The
bot durable queues (OutboundQueue.drain, InboundJournal redelivery/replay)
consume the policy where they previously tested attempts >= max_attempts,
gaining a dead_letter_min_age knob. min_age=0 restores legacy behaviour.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 09:28:56 +00:00
praisonai-triage-agent[bot]andMervinPraison f616d86970 fix: add unified degraded-capability registry for gateway (fixes #3518)
Adds a small, process-local DegradedCapabilityRegistry + DegradedOwner
contract in core (praisonaiagents/gateway/degraded_state.py), mirroring the
existing gateway policy-protocol + default-impl pattern. Any owner (channel,
provider, capability, route, gateway) records degradation with a consistent,
redacted, actionable shape.

Wires the bot gateway health() as a live consumer: it aggregates existing
channel degradation facts (plus any provider/capability/route degradation
recorded into a shared registry) into a single degraded_owners surface, so a
degraded provider or unresolved secret-backed capability is no longer
classified-but-invisible. The channel-only surface stays for backward compat.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 09:23:15 +00:00
praisonai-triage-agent[bot]andMervin Praison ac6079c03a fix: translate wrapper int autonomy level to core preset (fixes #3516)
The wrapper YAML schema types `autonomy` as an int 0-10 but core
Agent only accepts bool/str/dict/AutonomyConfig; forwarding the raw
int hit core's disable branch and silently ignored a configured
level. Map the numeric level onto core's string presets (0 => off,
1-3 => suggest, 4-7 => auto_edit, 8-10 => full_auto) and pass
bool/str/dict through unchanged.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 08:48:04 +00:00
praisonai-triage-agent[bot]andMervinPraison 0e72285fb4 fix: repair approval config crash, async-loop safety, dropped agent flags (fixes #3516)
- praisonai_adapter._resolve_agent_approval: map the wrapper approval dict
  onto the real ApprovalConfig fields (approve_all_tools->all_tools, resolve
  string backend) instead of passing extra keys into the dataclass, which
  raised TypeError on every --trust/--approve-* run against the native adapter.
- praisonai_adapter.run + persistence sync stores + async TUI: route through
  the existing run_sync_or_offload helper instead of run_sync, so the flagship
  sync praisonai.run(...) API and sync persistence hooks no longer crash from
  inside a running loop (FastAPI, async test, notebook).
- praisonai_adapter._build_agents_and_tasks: forward agent-level fields the
  core Agent already accepts (planning, reflection, guardrails, web, autonomy,
  skills) instead of silently dropping them.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 08:40:03 +00:00
praisonai-triage-agent[bot]andMervin Praison 7f4de3d4bd fix: restore class-level Handoff._semaphore_lock contract
The per-instance async semaphore fix (correctly) enforces each Handoff's
own max_concurrent, but moved _semaphore_lock to instance level, breaking
the architectural test that asserts Handoff._semaphore_lock is a single
shared class attribute. Restore it as a class-level threading.Lock guarding
lazy semaphore creation while keeping the semaphore itself per-instance.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 07:33:53 +00:00
praisonai-triage-agent[bot]andMervinPraison 167908928c fix: three silent-failure bugs in praisonaiagents core (fixes #3514)
- llm.py: add LLMResponseError and re-raise instead of swallowing a
  mid-tool-loop error and returning "" as if the call succeeded, so the
  existing try/except in chat_mixin.py can surface the real failure.
- memory.py: make adapter search/reset/delete gates symmetric with the
  adapter-agnostic store path (any configured memory_adapter, not just
  the hardcoded sqlite/in_memory providers). Also make store_long_term
  adapter-agnostic to match store_short_term so adapter-stored memories
  (e.g. "dakera") remain findable.
- handoff.py: make the concurrency semaphore instance-level (created once
  per Handoff, rebound if the running event loop changes) instead of a
  class-level singleton, so per-handoff max_concurrent limits no longer
  override each other and multiple asyncio.run() lifecycles don't crash.

Co-authored-by: MervinPraison <[email protected]>
2026-07-30 07:25:12 +00:00
praisonai-triage-agent[bot] 266a1c9fec Merge pull request #3513 from MervinPraison/claude/issue-3512-20260729-1624
fix: add missing code-side feature bridges for eval/persistence/background/ollama
2026-07-30 04:26:12 +00:00
praisonai-triage-agent[bot]andMervinPraison 0ee0b108f7 fix: add missing code-side feature bridges for eval/persistence/background/ollama (fixes #3512)
Co-authored-by: MervinPraison <[email protected]>
2026-07-29 16:26:05 +00:00
Mervin Praison 2e5632c202 Merge pull request #3511 from Hore01/fix/windows-file-locking
fix: preserve Windows file lock length during save
2026-07-29 14:06:37 +01:00
praisonai-triage-agent[bot]andMervin Praison 61de56b83f fix: propagate Windows lock length through load() release
load() acquired the exclusive lock over max(file_size, 1) bytes on
Windows but discarded the returned length, so _release_exclusive_lock
fell back to unlocking only 1 byte. For session files larger than one
byte this left the remaining range locked until file close, blocking
concurrent access. Pass the acquired lock_length to the release call
to unlock the full range, mirroring save().

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 12:06:38 +00:00
MervinPraison 230a222c85 docs: auto-update documentation parity trackers [skip ci] 2026-07-29 11:58:47 +00:00
Mervin Praison 77185b2bc1 Merge pull request #3471 from MervinPraison/claude/issue-3469-20260728-0914
fix: enrich gateway WS stream relay + accepted/final ack
2026-07-29 12:58:10 +01:00
Mervin Praison ea49535cb4 Merge pull request #3510 from Hore01/fix/workspace-path-serialization
fix: serialize workspace paths consistently across platforms
2026-07-29 12:57:42 +01:00
Hore01 30e473063d fix: preserve Windows file lock length during save 2026-07-29 12:01:35 +01:00
Hore01 fbc120e318 fix: serialize workspace paths consistently across platforms 2026-07-29 11:48:51 +01:00
Mervin Praison 4717e8eab6 Merge pull request #3398 from MervinPraison/claude/issue-3397-20260726-0715
fix: session_id collisions, concurrent handoff corruption, async retry hook crash
2026-07-29 11:42:53 +01:00
Mervin Praison 206b7212b1 Merge pull request #3437 from MervinPraison/claude/issue-3427-20260727-0902
fix: publish agents.yaml JSON Schema + wire editor autocomplete/validation
2026-07-29 11:42:17 +01:00
Mervin Praison ca8f8be99b Merge pull request #3441 from MervinPraison/claude/issue-3440-20260727-0930
fix: make gateway reload-scope classification canonical in core (#3440)
2026-07-29 11:41:50 +01:00
Mervin Praison 2cccd773f5 Merge pull request #3442 from MervinPraison/claude/issue-3438-20260727-0929
fix: make gateway reliability safe by default (#3438)
2026-07-29 11:41:22 +01:00
praisonai-triage-agent[bot]andMervin Praison 2b6bf40455 fix: persist new stream frames, terminate missing-agent turns, order final after stream
- Persist reasoning/tool-progress/stream-error frames for reconnect replay (CodeRabbit)
- Missing agent now resolves terminally (final+error) instead of a dangling accepted ack (Greptile P1)
- Drain relay futures before final frame so final never overtakes trailing stream events (Greptile P1)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 10:41:20 +00:00
praisonai-triage-agent[bot]andMervinPraison f7ac3e1cc9 fix: enrich gateway WS stream relay + accepted/final ack (fixes #3469)
Forward a closed set of structured progress events (reasoning, tool
progress, stream errors) to WS clients instead of dropping everything
but text/tool-call/end, and disambiguate the overloaded response frame
with status: "accepted" (provisional) vs status: "final" (with a
structured outcome).

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 10:41:20 +00:00
Mervin Praison bfdc58974b Merge pull request #3452 from Hore01/fix/conftest-pytest-plugins-error
fix: Remove pytest_plugins from conftest to resolve pytest error
2026-07-29 11:40:44 +01:00
Mervin Praison ec1dfb36a9 Merge pull request #3456 from MervinPraison/claude/issue-3455-20260727-1716
fix: remove duplicate BEFORE_TOOL/AFTER_TOOL hook firing in legacy async path
2026-07-29 11:40:17 +01:00
Mervin Praison 441ce71da7 Merge pull request #3458 from MervinPraison/claude/issue-3457-20260728-0714
fix: MCP per-call timeout, wire workflow context into prompt, fix parallel loop idx
2026-07-29 11:40:03 +01:00
Mervin Praison be0ff63ec6 Merge pull request #3472 from MervinPraison/claude/issue-3467-20260728-0912
fix: cancel/time-bound in-flight gateway agent turns
2026-07-29 11:39:18 +01:00
Mervin Praison 21b15f0384 Merge pull request #3489 from MervinPraison/claude/issue-3483-20260728-1714
fix: route MCP URL transport selection through shared get_transport_type
2026-07-29 11:38:44 +01:00
Mervin Praison e25ab00722 Merge pull request #3507 from MervinPraison/claude/issue-3505-20260729-0943
fix: scope scheduler automations & suggestions per identity
2026-07-29 11:37:59 +01:00
Mervin Praison 566ce4b4a0 Merge pull request #3497 from MervinPraison/claude/issue-3494-20260729-0852
fix: route auxiliary LLM calls to configured small_model
2026-07-29 11:37:26 +01:00
MervinPraison d7e3858386 docs: auto-update documentation parity trackers [skip ci] 2026-07-29 10:36:32 +00:00
Mervin Praison 02b69bd07f Merge pull request #3502 from MervinPraison/claude/issue-3498-20260729-0914
fix: add durable SQLite backend for gateway push delivery store
2026-07-29 11:35:55 +01:00
Mervin Praison 9c0dfe1076 Merge pull request #3508 from MervinPraison/claude/issue-3506-20260729-0943
fix: consume markdown_dialect capability with core dialect converter
2026-07-29 11:35:47 +01:00
praisonai-triage-agent[bot] c40b9118a9 Merge pull request #3503 from MervinPraison/claude/issue-3500-20260729-0921
fix: sandbox USERPROFILE in rules path-safety test for Windows
2026-07-29 10:31:24 +00:00
praisonai-triage-agent[bot] ee67a9d826 Merge pull request #3504 from MervinPraison/claude/issue-3501-20260729-0921
fix: instruct bot shell agent to report command stdout
2026-07-29 10:29:59 +00:00
MervinPraison ed84d68863 docs: auto-update documentation parity trackers [skip ci] 2026-07-29 10:22:40 +00:00
praisonai-triage-agent[bot] e34a9fac13 Merge pull request #3496 from MervinPraison/claude/issue-3495-20260729-0852
fix: declarative remote skill sources that stay synced
2026-07-29 10:21:59 +00:00
praisonai-triage-agent[bot]andMervin Praison 1134398e17 fix: extend principal ownership boundary to name-based mutations & suggestion admission
Closes the two P1 gaps flagged in review: name-based schedule lookups/removals
had no principal check (a gateway user could read/delete another's automation by
guessing its name), and suggestion admission caps/dedup were measured globally
(one tenant could starve another's suggestions).

- store.py / config_store.py: get_by_name/remove_by_name gain optional principal
  filter; a cross-owner match is skipped. principal=None stays global.
- protocols.py: ScheduleStoreProtocol get_by_name/remove_by_name updated.
- suggestion_store.py: add() scopes the pending cap & dedup window to the
  suggestion's principal; principal=None keeps the global pool.
- tests: +6 cases for name-based mutation ownership and per-principal caps/dedup.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 09:54:56 +00:00
praisonai-triage-agent[bot]andMervin Praison d88af8a81a fix: consume markdown_dialect in core send seam & fix plain-text fallback
Wire BasePlatformAdapter.format_message() (the existing deliver() seam) to
call format_for_dialect(text, caps.markdown_dialect) so the capability is
actually consumed in core — Telegram replies are MarkdownV2-escaped and Slack
gets mrkdwn. Default "markdown" dialect keeps existing adapters unaffected.

Fix strip_markdown to only unwrap *paired* emphasis/code spans so literal
identifiers (svc_1), globs (*.py) and arithmetic (a*b) are no longer corrupted.

Adds regression tests for both fixes.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 09:54:55 +00:00
praisonai-triage-agent[bot]andMervinPraison e495c5d850 fix: consume markdown_dialect capability with core dialect converter (fixes #3506)
Add a pure, stdlib-only format_for_dialect() in praisonaiagents/bots/format.py
that finally consumes the declared markdown_dialect capability, returning
(rendered_text, parse_mode) so adapters can escape/convert agent replies to the
target platform's flavour (Telegram MarkdownV2, Slack mrkdwn, Discord
passthrough, safe plain-text fallback) — preventing dropped Telegram messages
from unescaped specials.

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 09:46:43 +00:00
praisonai-triage-agent[bot]andMervinPraison af9f314fb0 fix: scope scheduler automations & suggestions per identity (fixes #3505)
Add an optional `principal` owner key to the core scheduler data model so
a multi-user gateway isolates each user's automations and suggestions
instead of sharing one global, single-tenant store.

- Suggestion.principal + SuggestionStore.list_pending/accept/dismiss gain
  an optional principal filter that rejects cross-owner access.
- ScheduleJob.principal round-trips through to_dict/from_dict; FileScheduleStore
  and ConfigYamlScheduleStore .list() gain an optional principal filter.
- ScheduleStoreProtocol.list signature updated.

principal=None preserves the current global behaviour, so single-user
deployments are unaffected (fully backward compatible).

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 09:46:15 +00:00
praisonai-triage-agent[bot]andMervin Praison 6711bf72fd fix: inject shell stdout directive even when prompt already names execute_command
The bare-tool-name guard skipped the stdout-reporting instruction for
preconfigured agents whose own system prompt mentions execute_command,
leaving the "no output" bug reachable. Guard on a stable marker phrase
instead, keeping injection idempotent. Strengthen assertions and add
regression coverage for the preconfigured-prompt and duplicate paths.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 09:30:30 +00:00
praisonai-triage-agent[bot]andMervin Praison 55a22cdf80 fix: persist push-delivery recipient so restart replay actually redelivers
Addresses the durable at-least-once guarantee gaps flagged in review:
- Persist the recipient client_id alongside each pending event and
  reconstruct _pending_acks on startup, so replayed events are scheduled
  for retry/reconnect redelivery instead of being silently dropped.
- Evict acknowledged events from the SQLite store (and in-memory cache)
  so acked rows are not resurrected after a restart.
- Backfill client_id column for pre-existing stores; strengthen tests to
  assert redeliverability after restart and ack-eviction.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 09:28:09 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy 9d828e5529 fix: instruct bot shell agent to report command stdout (fixes #3501)
Strengthen the shell-tool instruction in enable_shell_tools so the
gateway agent actually invokes execute_command and returns its stdout
verbatim, instead of intermittently replying "there was no output".
This addresses the flaky E2E sandbox marker check (E2E_SANDBOX_OK).

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-29 09:24:39 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy 5a2cd2b20e fix: sandbox USERPROFILE so rules path-safety test passes on Windows (fixes #3500)
Path.home() resolves via USERPROFILE on Windows, not HOME. The fixture
only set HOME, so on Windows the tool wrote to the real user profile and
the positive test asserted a file under tmp_path that was never created.
Set USERPROFILE alongside HOME so the fake home is honored on all
platforms and no writes escape the sandbox.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-29 09:23:58 +00:00
praisonai-triage-agent[bot] 763500259b Merge pull request #3493 from MervinPraison/claude/issue-3492-20260729-0822
fix: close three cross-cutting wrapper-layer gaps (#3492)
2026-07-29 09:21:48 +00:00
praisonai-triage-agent[bot]andMervinPraison d3e5ba0996 fix: add durable SQLite backend for gateway push delivery store (fixes #3498)
Make the gateway's at-least-once push delivery guarantee durable by default
without an external Redis server. DeliveryConfig.store_backend now accepts
"sqlite" (new default), "redis" and "memory", validated in core. The wrapper
gains a SqlitePushStore mirroring the existing OutboundQueue pattern (WAL,
stdlib sqlite3, TTL eviction) at ~/.praisonai/state/push_delivery.sqlite, so
pending un-acked events survive a restart and replay on reconnect. "memory"
stays an explicit ephemeral opt-out; "redis" stays for multi-process fan-out.

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 09:20:47 +00:00
praisonai-triage-agent[bot]andMervin Praison 14a30e55a9 fix: wire declarative remote skills into discovery, fix root-skill double-count and project config
- discovery.py: auto-include synced remote-skill cache (`current` aliases) in
  default skill dirs so agents pick up `skills sync` output without install;
  scan now treats a returned dir that is itself a skill (root-level SKILL.md)
  as a single skill.
- remote.py: return the fetched dir as-is (never its parent) so a root-level
  skill is not double-counted alongside its cache `current` alias.
- skills.py (CLI): `sync` reuses discover_skills (no re-implemented scan / no
  double-count); no-URL sync now reads project praisonai.yaml/.yml as well as
  the user-global config.
- test_remote.py: regression test for root-level SKILL.md repo discovered once.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 09:05:44 +00:00
praisonai-triage-agent[bot]andMervin Praison 9fa0f9999e fix: Task guardrail must prefer configured llm_instance over bare model string
Task._setup_guardrail selected `agent.llm or agent.llm_instance`; since
agent.llm is always a non-empty model-name string it always won, discarding
the configured LLM instance (base_url/api_key/auth) and authenticating against
the wrong backend. Reorder to `llm_instance or llm`, matching
Agent._setup_guardrail. small_model routing still applies only to the bare
string case. Adds Task guardrail routing/instance-preference tests.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 09:05:19 +00:00
praisonai-triage-agent[bot]andMervinPraison 8d8dc36685 fix: route auxiliary LLM calls to configured small_model (fixes #3494)
Internal, non-user-facing LLM calls (context compaction/summarisation and
LLM guardrail validation) always ran on the primary agent model. Thread the
existing get_small_model resolver through these live auxiliary call sites so
a configured small_model is used, while leaving it unset preserves today's
behaviour (unset -> primary model).

- agent._create_llm_summarize_fn: resolve the summariser model via
  get_small_model(primary_model=<agent model>) instead of hardcoding self.llm.
- Agent/Task LLM guardrail setup: when the guardrail LLM would default to the
  bare primary model-name string, route it through get_small_model.

Change is strictly additive and backward-compatible: an explicit LLM instance
or per-call model always wins.

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 08:57:07 +00:00
praisonai-triage-agent[bot]andMervinPraison 5128bfda8c fix: add declarative remote skill sources that stay synced (fixes #3495)
Introduce an opt-in RemoteSkillSourceProtocol and a default git-backed
implementation that syncs skills into a versioned local cache with atomic
swaps and offline-safe fallback to the last-good cache. Wired into
discover_skills via a new sources= param (backward compatible, zero
import-time cost) and surfaced through a `praisonai skills sync` CLI
command reading skills.urls / skills.sources from config.

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 08:57:02 +00:00
praisonai-triage-agent[bot]andMervin Praison 3141a24c61 fix: isolate capability cache per-registry & scope AgentOps teardown (#3492)
Addresses two P1 reviewer findings on the wrapper-layer PR:

- registry.py: move the capability cache off a process-global dict onto the
  FrameworkAdapterRegistry instance so two registries that register different
  adapters under the same name no longer read each other's flags.
- observability/hooks.py: record which AgentOps teardown a run owns
  (per-session vs legacy singleton). A run whose start_session returned no
  usable handle now ends nothing instead of falling back to the package-global
  end_session and cross-finalizing a concurrent run.
- agents_generator.py: keep the "cannot verify" refusal for genuinely unknown
  frameworks while treating known built-ins (DEFAULT_PRIORITY / registered)
  whose adapter can't be constructed as unsupported, preserving the historical
  "not supported for framework=..." message.

Adds regression tests for all three behaviours.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 08:42:09 +00:00
praisonai-triage-agent[bot]andMervinPraison 63b9e1e8f4 fix: close three cross-cutting wrapper-layer gaps (fixes #3492)
Gap 1: scope AgentOps to each ObservabilityRun (per-run start_session
handle + lock) instead of the process-global singleton so concurrent
runs don't cross-contaminate tags or cross-finalize sessions.

Gap 2: add run_sync_or_offload() to _async_bridge as the single
sync-or-offload driver; delete the duplicated copies in auto.py, use it
in PersistenceOrchestrator._sync (was silently raising inside a running
loop), and replace deprecated get_event_loop().run_in_executor with
asyncio.to_thread in api/agent_invoke.py.

Gap 3: add adapter_capability() and route SUPPORTS_RUNTIME_FEATURES /
SUPPORTS_WORKFLOW decisions through it, removing the
str(framework)=="praisonai" fallbacks so third-party adapters aren't
silently demoted on transient resolution failures.

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 08:31:40 +00:00
MervinPraison e22dc0d170 docs: auto-update feature parity trackers [skip ci] 2026-07-29 08:13:19 +00:00
praisonai-triage-agent[bot] dd69b5ea95 Merge pull request #3491 from MervinPraison/claude/issue-3490-20260729-0715
fix: undo file resurrection, skill-approval race, and once-scope permission expiry
2026-07-29 08:12:48 +00:00
praisonai-triage-agent[bot]andMervin Praison 7e0d9939a4 fix: preserve ignored files (.env) on snapshot restore-all
The restore-all prune loop deleted every project file absent from the
target commit, silently destroying ignored/excluded files (.env, venv,
node_modules) that the snapshot never tracked. Mirror _sync_files()'s
ignore rules in restore so only would-be-tracked files are pruned.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 07:26:13 +00:00
praisonai-triage-agent[bot]andMervinPraison 8ac5a3bbec fix: mirror deletions in undo, lock skill-approval store, consume once-scope permissions (fixes #3490)
- snapshot: prune shadow files removed from the project in _sync_files() and
  restrict restore() "restore all" to the target commit's tree (removing files
  not in it), so undo() cannot resurrect deleted files or leak files from a
  later snapshot.
- skills: guard the pending-store load-mutate-save cycle in _stage_pending/
  approve/reject with a threading.Lock so concurrent proposals no longer
  silently overwrite each other.
- permissions: consume a scope="once" approval/denial on first match in
  _check_flat so it no longer becomes permanent for the process lifetime.

Co-authored-by: MervinPraison <[email protected]>
2026-07-29 07:19:33 +00:00
MervinPraison e3e0135876 docs: auto-update documentation parity trackers [skip ci] 2026-07-28 18:54:32 +00:00
praisonai-triage-agent[bot] ed4c63f141 Merge pull request #3488 from MervinPraison/claude/issue-3485-20260728-1714
fix: remove orphaned hooks/query_protocol.py dead code
2026-07-28 18:53:38 +00:00
MervinPraison 6b91970049 Release v4.6.157 2026-07-28 18:50:30 +00:00
MervinPraison a8ec2f15a3 Bump praisonai-sandbox to 0.0.7 2026-07-28 18:50:24 +00:00
MervinPraison 52d5320699 Bump praisonai-mcp to 0.0.9 2026-07-28 18:50:19 +00:00
MervinPraison fcab98a2aa Bump praisonai-browser to 0.0.9 2026-07-28 18:50:12 +00:00
MervinPraison 2055ecf05d Bump praisonai-train to 0.0.13 2026-07-28 18:50:05 +00:00
MervinPraison 20bc67ae82 Bump praisonai-bot to 0.0.42 2026-07-28 18:49:59 +00:00
MervinPraison b1a3cda2a9 Bump praisonai-code to 0.0.57 2026-07-28 18:49:51 +00:00
MervinPraison 878c212f18 Bump praisonaiagents to 1.6.161 2026-07-28 18:49:14 +00:00
praisonai-triage-agent[bot] 0e5fd5416d Merge pull request #3487 from MervinPraison/claude/issue-3484-20260728-1714
fix: remove dead deprecated _classify_error_and_should_retry_legacy
2026-07-28 18:38:15 +00:00
MervinPraison f079b0266a docs: auto-update documentation parity trackers [skip ci] 2026-07-28 18:31:27 +00:00
praisonai-triage-agent[bot] dac4248669 Merge pull request #3486 from MervinPraison/claude/issue-3482-20260728-1713
fix: restore retry tuning and compaction_strategy in ExecutionConfig.from_dict
2026-07-28 18:30:44 +00:00
Hore01 37cea31ea9 fix: resolve pytest_plugins error with pytest 9 2026-07-28 18:32:08 +01:00
praisonai-triage-agent[bot]andMervinPraison 6863b13474 fix: route MCP URL transport selection through shared get_transport_type (fixes #3483)
Delegate mcp.py's inline SSE-vs-HTTP URL check to the existing
mcp_transport.get_transport_type() helper so there is a single source of
truth for URL->transport classification. No behaviour change: /sse URLs
still use SSE and all other HTTP URLs use Streamable HTTP.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 17:16:33 +00:00
praisonai-triage-agent[bot]andMervinPraison 19d410aa2d fix: remove orphaned hooks/query_protocol.py dead code (fixes #3485)
HooksQueryProtocol had zero importers, was not exported in
hooks/__init__.py __all__ or _LAZY_GROUPS. Consumers use
registry.list_hooks_for_api directly. No behaviour change.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 17:16:05 +00:00
praisonai-triage-agent[bot]andMervinPraison c954072257 fix: remove dead deprecated _classify_error_and_should_retry_legacy (fixes #3484)
Co-authored-by: MervinPraison <[email protected]>
2026-07-28 17:16:01 +00:00
praisonai-triage-agent[bot]andMervinPraison e3c5cb18bb fix: restore retry tuning and compaction_strategy in ExecutionConfig.from_dict (fixes #3482)
Sync from_dict with to_dict so retry_initial_delay, retry_backoff_factor,
retry_jitter and compaction_strategy survive a to_dict/from_dict round-trip.
Also align code_sandbox_mode fallback with the dataclass default ("sandbox").

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 17:15:30 +00:00
praisonai-triage-agent[bot] cb8a49fd11 Merge pull request #3481 from MervinPraison/claude/issue-3480-20260728-1621
fix: remove dead code noop and sanitize_agent_name_for_autogen_v4
2026-07-28 17:12:05 +00:00
praisonai-triage-agent[bot]andMervinPraison 0206e9dbc4 fix: remove dead code noop and sanitize_agent_name_for_autogen_v4 (fixes #3480)
Both helpers in the praisonai wrapper's agents_generator.py were defined
but referenced nowhere (no callers, no tests, not exported). Also drops
the now-unused `import keyword` used only by the removed function.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 16:22:02 +00:00
praisonai-triage-agent[bot] 508fab9598 Merge pull request #3478 from MervinPraison/claude/issue-3476-20260728-1012
fix: bot --browser uses praisonai-browser local automation
2026-07-28 12:34:28 +00:00
praisonai-triage-agent[bot] f0e62296ac Merge pull request #3477 from MervinPraison/claude/issue-3475-20260728-1011
fix: ASCII-safe safe_print() for Windows cp1252 playwright banners
2026-07-28 11:52:16 +00:00
MervinPraison 6b77c8758f docs: auto-update feature parity trackers [skip ci] 2026-07-28 11:10:38 +00:00
praisonai-triage-agent[bot] 23d8607376 Merge pull request #3474 from MervinPraison/claude/issue-3473-20260728-0947
fix: add isolated tool-calling bridge contract for code execution
2026-07-28 11:10:05 +00:00
praisonai-triage-agent[bot] f8760fd680 Merge pull request #3470 from MervinPraison/claude/issue-3468-20260728-0913
fix: validate gateway route/binding targets against agents map
2026-07-28 11:04:06 +00:00
praisonai-triage-agent[bot] 7b60380b79 Merge pull request #3466 from MervinPraison/claude/issue-3462-20260728-0850
fix: route free-text prompts with run-supported flags to the modern engine (fixes #3462)
2026-07-28 10:56:57 +00:00
praisonai-triage-agent[bot] f978b5a6ba Merge pull request #3465 from MervinPraison/claude/issue-3463-20260728-0850
fix: warm runtime hosts stateful per-session agents
2026-07-28 10:50:15 +00:00
praisonai-triage-agent[bot] 5141da6826 Merge pull request #3464 from MervinPraison/claude/issue-3461-20260728-0850
fix: interruptible interactive CLI turns via cooperative cancellation
2026-07-28 10:24:58 +00:00
praisonai-triage-agent[bot]andMervin Praison b866d76a8b fix: verify Playwright runtime and stop advertising unsupported browser profile
- browser_available() now requires the playwright runtime importable, not just
  praisonai_browser, so a base install without the Playwright extra falls back
  to the cloud BrowserBaseTool instead of selecting a local tool that fails at
  invocation (Greptile P1).
- create_browser_tool no longer advertises profile=X as active; PlaywrightBrowserAgent
  has no profile param and uses a fresh context, so the value is now logged as
  informational-only rather than misreported (Greptile P1).
- Add unit test covering the missing-Playwright fallback path.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 10:23:07 +00:00
praisonai-triage-agent[bot]andMervin Praison 7209b6d685 fix: support flush kwarg in safe_print for print drop-in parity
Addresses Greptile review: safe_print() advertised as a drop-in print
replacement but rejected flush=True. Add flush passthrough (guarded) plus
a regression test.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 10:19:56 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy 3eeee776d3 fix: bot --browser uses praisonai-browser local automation (fixes #3476)
BotHandler._build_tools() now prefers praisonai-browser's local Playwright
automation (navigate/snapshot/click) over cloud-only BrowserBaseTool when
capabilities.browser is set, honouring --browser-headless / --browser-profile.
Falls back to BrowserBaseTool only when praisonai-browser is unavailable.

Adds a lazy _browser_bridge (mirroring _code_bridge) and an agent-callable
browser_automate tool wrapping PlaywrightBrowserAgent.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-28 10:17:04 +00:00
praisonai-triage-agent[bot] 942814d785 Merge pull request #3460 from MervinPraison/claude/issue-3459-20260728-0828
fix: harden managed_local write_file, pip install, and API key handling
2026-07-28 10:16:52 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy 2db514a372 fix: add ASCII-safe safe_print() for Windows cp1252 playwright banners (fixes #3475)
Adds safe_print() to praisonai_bot.gateway.unicode_utils so E2E harnesses and
console reporters can echo Playwright's "playwright install" banner (drawn with
box chars like U+2551) without crashing on default Windows cp1252 consoles.
Falls back to safe_error_message() sanitization only when the stream encoding
rejects the text, keeping the actionable hint readable instead of masking it
behind a secondary UnicodeEncodeError.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-28 10:14:53 +00:00
praisonai-triage-agent[bot]andMervin Praison a51945a8c8 fix: forward invocation policy and limits across CodeToolBridge boundary
The CodeToolBridge.run_code(code) contract dropped the caller's per-run
allow-list, registry, timeout and max_output_size, so a transport could
only gate isolated tool calls by bridge-owned defaults — a weaker path
than the in-process executor and contrary to the "never a weaker path"
guarantee. Forward the invocation policy and limits to run_code so the
transport gates each call by exactly what the caller authorised.

- CodeToolBridge.run_code now takes allowed_tools/registry/timeout/
  max_output_size as keyword-only params (new protocol, no external
  implementers — fully backward compatible for existing callers).
- execute_code_with_tools forwards the invocation context to the bridge.
- Tests: recording bridge now uses only forwarded policy; added coverage
  for policy/limit propagation and forwarded-allow-list enforcement.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:58:42 +00:00
praisonai-triage-agent[bot]andMervinPraison 5d775542f8 fix: add isolated tool-calling bridge contract for code execution (fixes #3473)
Add a transport-agnostic CodeToolBridge protocol and parent-side
serve_tool_call helper in core, plus a backward-compatible bridge=
option on execute_code_with_tools. When a bridge is supplied, code runs
under isolation and reaches tools over the bridge (same allow-list +
approval gate); omitting it preserves today's in-process behaviour.

Concrete per-backend transports remain a follow-up in the sandbox layer;
core only defines the contract to stay lightweight.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 09:52:06 +00:00
praisonai-triage-agent[bot]andMervin Praison aa379152e8 fix: reach + isolate + settle gateway per-turn timeout/abort (#3467)
Address three P1 gaps in the gateway cancellation/timeout work:

- Timeout was unreachable: add per_turn_timeout to the bot GatewayServerSchema
  (extra="forbid" was rejecting it) and stamp it onto self.config in
  start_with_config so the documented YAML knob actually takes effect.
- Turn isolation: pass the InterruptController per-turn as the entry point's
  cancel_token instead of mutating the shared agent.interrupt_controller, so
  overlapping sessions on one Agent instance no longer interrupt each other.
  Legacy agents without a cancel_token kwarg fall back to the shared attribute.
- Cancellation honesty: interrupt cooperatively first and wait a bounded grace
  window (_ABORT_GRACE_SECONDS) for the turn — including a sync agent.chat in a
  worker thread that cannot be force-killed — to unwind before the serial
  session queue advances; hard task.cancel() only as a fallback.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:31:28 +00:00
praisonai-triage-agent[bot]andMervin Praison a9e47e7ba6 fix: reject blank route/binding targets in gateway validation
Empty-string targets were skipped by the `if target` truthiness check,
retaining the silent fallback/misroute this validation prevents. Skip
only None (omitted) so every supplied string target is validated.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:23:24 +00:00
praisonai-triage-agent[bot]andMervinPraison 8cbc4f4f19 fix: cancel/time-bound in-flight gateway agent turns (fixes #3467)
Wire per-turn abort + timeout into the gateway so a runaway turn can no
longer wedge the serial per-session queue:

- Advertise the `abort` method (+ `message_abort` event) in the hello
  capability handshake instead of the "abort not implemented" placeholder.
- Handle `abort`/`message_abort` WS frames and a portable `/stop` chat
  command; both drive the existing InterruptController and cancel the
  driving asyncio task via a new `_active_turns` registry.
- Run each turn under an optional `gateway.per_turn_timeout` (YAML/config
  knob, 0 = disabled) via `_drive_turn`, normalising cancelled/timed-out
  turns to a typed terminal message instead of leaving them hanging.

Reuses core's InterruptController (already checked by the agent run loop)
and `agent.interrupt_controller`; no new agent params.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 09:20:12 +00:00
praisonai-triage-agent[bot]andMervinPraison 3cf410c82f fix: validate gateway route/binding targets against agents map (fixes #3468)
Cross-check every channel's routes/routing targets (including default) and
bindings.agent against the declared agents: map in the canonical schema
validator. A typo now fails fast at load time (and in gateway doctor, which
loads via this schema) with the channel, bad target, and closest valid agent
id — instead of a silent logger.warning + misroute. Only enforced when
agents: is declared, so single-bot configs stay backward-compatible.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 09:18:22 +00:00
praisonai-triage-agent[bot]andMervin Praison d5d4ed1f08 fix: stub _get_session_agent in warm-runtime session event test
A run with session_id now routes to the stateful per-session agent
(_get_session_agent), not _get_agent. The test only stubbed _get_agent,
so it built a real Agent with no LLM backing and start() returned ''.
Stub the session builder too so the event fan-out contract is exercised
without a live LLM.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:10:01 +00:00
praisonai-triage-agent[bot]andMervin Praison fff67f0664 fix: value-aware flag classification so dash-prefixed option values route to modern engine
Fixes Greptile P1: a value-taking run option whose separated value begins
with a dash (e.g. `--session -abc`, `--output -json`) was mis-classified by
`_flag_names` as an unsupported flag, diverting an otherwise fully
run-supported prompt to the legacy engine and losing session continuity,
--output modes, the credential gate and permissions.

`_flag_names` now accepts the `value_opts` set and skips the token consumed
by a value-taking option (with `--opt=value` handled inline). `_looks_like_
bare_prompt` passes `run`'s value-taking options in, and short-circuits the
no-dash case before the (potentially heavy) run-option introspection.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:06:10 +00:00
praisonai-triage-agent[bot]andMervin Praison abef6d3ed9 fix: separate attach event id from session identity; guard model/continuity in warm runtime
Address 3 P1 review issues on the stateful warm-runtime session path:

- Attach id no longer replaces session identity: `run.py` passes the
  persistence/conversation id as `session_id` and the `--attach` label as a
  distinct `event_id`. A `--no-save --attach <id>` run streams events to the
  attach id but stays on the isolated anonymous path (no persistence).
- Model override rebuilds the session agent: the per-session warm agent is now
  keyed by the resolved model, so a later turn with a different model no longer
  silently runs the previous provider/model.
- Continuity-wiring failure is not cached: when session-store wiring fails, the
  turn runs one-shot but the unwired agent is not retained, so a later turn
  retries wiring instead of permanently serving an uncoupled agent.

Wrapper-only (praisonai-code); no core SDK changes, no new Agent params, no new
deps. Adds tests for model override, continuity-failure, and event/session id
separation; updates the attach mock to accept `event_id`.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:05:30 +00:00
praisonai-triage-agent[bot]andMervin Praison c8f28d96d1 fix: wire primary TUI Ctrl-C to cancellation and guard abandoned worker
Address Greptile P1 findings on the interruptible-turn wrapper:

- Primary prompt-toolkit path now requests cooperative cancellation on
  Ctrl-C when a turn is in flight (previously only reset the input
  buffer), and clears any stale request at the start of each background
  turn so a fresh turn is not immediately interrupted.
- _execute_prompt_interruptible refuses to start a new turn (and to clear
  the shared controller) while a prior abandoned worker is still alive,
  preventing the abandoned turn from being un-cancelled and resuming
  against the warm session.
- Added test_abandoned_worker_blocks_new_turn.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 09:02:26 +00:00
praisonai-triage-agent[bot]andMervinPraison 7cb8f71f82 fix: route free-text prompts with run-supported flags to the modern engine (fixes #3462)
The CLI router treated any -/-- flag as a signal to fall back to the legacy
argparse engine, so common cases like `praisonai "fix the bug" --model gpt-4o`,
`--continue`, or `--output json` silently bypassed the modern `run` engine and
lost session continuity, --output modes, the credential gate and permissions.

_looks_like_bare_prompt now derives the run-supported option names by
introspecting the run command's Click parameters and routes a bare prompt to
`run` when every flag present is one run accepts; genuinely legacy-only flags
(and .yaml/.yml workflows) still fall back to legacy, now with a one-line
notice so the fallback is never silent. _build_run_argv reconstructs the
prompt + flags into a single `run "<prompt>" <flags>` invocation.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 08:58:10 +00:00
praisonai-triage-agent[bot]andMervinPraison 447eb8db4e fix: warm runtime hosts stateful per-session agents (fixes #3463)
The warm runtime was a cold-start cache only: every /run cleared history
and --continue/--session runs bypassed the warm path, paying cold-start
each turn. Add a per-session warm agent registry keyed by session id that
rehydrates history once (via the existing apply_cli_session_continuity
wiring) and retains it across turns, while the anonymous path stays
isolated. Relax runtime_eligible so --continue/--session route to the warm
stateful path (fork/isolated/thinking/tool runs stay in-process).

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 08:56:01 +00:00
praisonai-triage-agent[bot]andMervinPraison 6b849b4c40 fix: wire interactive TUI Ctrl-C to cooperative cancellation (fixes #3461)
Attach the core InterruptController to the interactive agent and run each
turn in a worker thread so the main thread stays responsive. Ctrl-C during
a turn now requests cooperative cancellation; the core chat loop honours it
at the next step boundary, returns partial output, and keeps the warm agent
and session intact. Wrapper-only change reusing the existing core primitive.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 08:54:44 +00:00
praisonai-triage-agent[bot]andMervinPraison cc6994764d fix: harden managed_local write_file, pip install, and API key handling (fixes #3459)
- write_file compute bridge: replace heredoc with base64-decoded stdin so
  content can no longer terminate the heredoc early (silent truncation) or
  inject host commands.
- LocalCompute._install_packages: validate pip specifiers against the strict
  allowlist and shlex.quote each token before host execution.
- LocalManagedAgent._ensure_agent: pass api_key/base_url directly to the inner
  Agent instead of os.environ.setdefault, preventing process-wide credential
  pollution and subprocess env leakage across tenants.

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 08:31:21 +00:00
praisonai-triage-agent[bot]andMervin Praison de5a95d549 fix: preserve workflow _execution_context across task retries
Do not clear task._execution_context inside _build_execution_context.
The run_task/arun_task retry loops re-enter this helper on guardrail /
completion failures; clearing stripped the upstream output and validation
feedback the retry needs (Greptile P1). The Process engine already owns
this field's lifecycle (re-set before each yield, reset to None before
selecting the next task), so no cross-task leak.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-28 07:24:29 +00:00
praisonai-triage-agent[bot]andMervinPraison 36da0007e6 fix: MCP per-call timeout, wire workflow context into prompt, fix parallel loop idx (fixes #3457)
- mcp.py: wrap session.call_tool/read_resource/get_prompt in asyncio.wait_for
  so a hung server fails one request without wedging the runner loop forever
- agents.py: fold task._execution_context (inter-task context + validation
  feedback built by Process._build_task_context) into the prompt builder, and
  clear it after consumption so it doesn't leak into later runs
- workflows.py: track future->idx map in parallel loop so error attribution
  survives exceptions instead of using an unbound/stale idx

Co-authored-by: MervinPraison <[email protected]>
2026-07-28 07:18:39 +00:00
praisonai-triage-agent[bot] b43688ad95 Merge pull request #3454 from MervinPraison/claude/issue-3453-20260727-1618
fix: make tools discover resolver-first, manual scan as fallback
2026-07-27 17:40:01 +00:00
praisonai-triage-agent[bot]andMervin Praison a900a5cc1d fix: remove duplicate BEFORE_TOOL/AFTER_TOOL hook firing in legacy async path (fixes #3455)
The legacy async tool loop in _achat_completion fired BEFORE_TOOL/AFTER_TOOL
inline and then again inside execute_tool_async, double-firing hooks when
registered and building hook inputs (os.getcwd/time.time) with no consumer
when none are. Rely on the single guarded dispatch in execute_tool_async,
which already handles blocking, arg mutation and after-context aggregation.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 17:18:44 +00:00
praisonai-triage-agent[bot]andMervin Praison 482c0781b1 fix: remove unused --entrypoints flag from tools discover
The --entrypoints option was documented and parsed into use_entrypoints
but never wired to any discovery behavior. Removed the dead flag and
updated the docstring to reflect the actual --include-only interface.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 16:26:41 +00:00
praisonai-triage-agent[bot]andMervinPraison 98f2cc440b fix: make tools discover resolver-first, manual scan as fallback (fixes #3453)
action_discover now reads built-in/external/registered/local from the
canonical ToolResolver.list_available_sources() in a single authoritative
walk, matching the resolver-first pattern already used by _get_builtin_tools
and templates/tools_doctor.py. The original praisonai_tools + TOOL_MAPPINGS
scan is preserved as an explicit offline fallback (_legacy_manual_scan) for
environments without praisonai-code. --include/--entrypoints flags and
grouped output are unchanged.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 16:20:41 +00:00
Hore01 02c1c87d58 fix: Remove pytest_plugins from conftest to resolve pytest error 2026-07-27 14:30:07 +01:00
MervinPraison 30c44e3cce docs: auto-update documentation parity trackers [skip ci] 2026-07-27 11:22:40 +00:00
praisonai-triage-agent[bot] 80e53f1398 Merge pull request #3451 from MervinPraison/claude/issue-3450-20260727-1020
fix: resolve BaseTool instances in async tool dispatch (fixes #3450)
2026-07-27 11:22:06 +00:00
praisonai-triage-agent[bot] 2011cf2edf Merge pull request #3449 from MervinPraison/claude/issue-3444-20260727-0945
fix: make scheduled-job delivery continuable by default
2026-07-27 11:09:40 +00:00
praisonai-triage-agent[bot] 11b564461e Merge pull request #3436 from MervinPraison/claude/issue-3431-20260727-0903
fix: bootstrap praisonai-mcp sibling for MCP wrapper unit tests
2026-07-27 11:08:40 +00:00
MervinPraison db738fb465 docs: auto-update documentation parity trackers [skip ci] 2026-07-27 11:01:40 +00:00
praisonai-triage-agent[bot] c806bc9ebb Merge pull request #3448 from MervinPraison/claude/issue-3445-20260727-0945
fix: add memory-aware gateway admission control (#3445)
2026-07-27 11:01:05 +00:00
praisonai-triage-agent[bot] d4359d70d4 Merge pull request #3433 from MervinPraison/claude/issue-3428-20260727-0903
fix: replace emoji with ASCII status tags in terminal-bench smoke script
2026-07-27 10:53:17 +00:00
praisonai-triage-agent[bot] 3a55c7876e Merge pull request #3447 from MervinPraison/claude/issue-3446-20260727-0946
fix: make outbound reply delivery crash-safe by default (#3446)
2026-07-27 10:52:55 +00:00
MervinPraison eaab4cba09 docs: auto-update documentation parity trackers [skip ci] 2026-07-27 10:41:06 +00:00
praisonai-triage-agent[bot] 7a96c092cc Merge pull request #3443 from MervinPraison/claude/issue-3439-20260727-0930
fix: typed gateway-runtime contract for channel adapters
2026-07-27 10:40:34 +00:00
praisonai-triage-agent[bot]andMervin Praison 3bfcd189f2 fix: carry BaseTool resolution through async execution + aliased names
Downstream _execute_tool_async_impl matched only on __name__ and called
func(**args) directly, so a BrowserBaseTool-style BaseTool instance
(resolved by .name in dispatch) returned "not found" / never ran. Mirror
the robust sync resolution (BaseTool.name, FunctionTool .name alias, class
name) and invoke func.run() for BaseTool instances.

Also fix the short-circuiting `or` chain in async dispatch so an aliased
.name that differs from __name__ resolves instead of being dropped.

Adds regression tests exercising the real (unmocked) execute_tool_async
for a BaseTool instance and an aliased callable name.

Fixes #3450

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 10:32:45 +00:00
praisonai-triage-agent[bot]andMervin Praison 2f2713718a fix: skip MCP wrapper tests cleanly when praisonai-mcp source is unavailable
Address CodeRabbit review: when neither the monorepo praisonai-mcp sibling
nor an installed praisonai_mcp.mcp_server is available, the C12 shim cannot
resolve. Convert the resulting bare ModuleNotFoundError collection error into
a clean module-level pytest.skip. Guard find_spec against ModuleNotFoundError/
ValueError for an absent/broken parent, mirroring praisonai._bootstrap.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 10:30:16 +00:00
praisonai-triage-agent[bot] 4321d5c203 Merge pull request #3432 from MervinPraison/claude/issue-3425-20260727-0854
fix: skip MCP wrapper unit tests cleanly when praisonai-mcp absent
2026-07-27 10:26:56 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy b13a7c4bfb fix: resolve BaseTool instances in async tool dispatch (fixes #3450)
Bot --browser wired BrowserBaseTool (a BaseTool instance without
__name__), causing async tool dispatch to raise
'BrowserBaseTool' object has no attribute '__name__'. Harden the
lookup in _achat_completion to resolve by __name__, .name, or class
name so all BaseTool subclasses dispatch safely, and drop the ad-hoc
__name__ monkey-patch in bots_cli.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-27 10:24:40 +00:00
praisonai-triage-agent[bot] 7b4ee9b058 Merge pull request #3434 from MervinPraison/claude/issue-3426-20260727-0900
feat: add opt-in transcript redaction to session export
2026-07-27 10:20:39 +00:00
praisonai-triage-agent[bot] 4505776fb3 Merge pull request #3435 from MervinPraison/claude/issue-3430-20260727-0904
fix: map box-drawing chars in bot error sanitizer for cp1252 (#3430)
2026-07-27 10:07:37 +00:00
praisonai-triage-agent[bot]andMervin Praison edef7d0468 fix: harden memory-aware admission (Windows import, production wiring)
- Guard Unix-only ``resource`` import so _admission.py loads on Windows;
  sampler self-disables gracefully when unavailable (Greptile P1 #1).
- Wire ``max_rss_mb`` through BotOS + gateway.yaml via a single-knob
  build_memory_pressure_policy() so the feature has a live production
  consumer instead of a dormant param (Greptile P1 #3).
- Surface max_rss_mb in admission stats; document resource-only soft-queue
  degradation honestly rather than silently misleading (Greptile P1 #2).
- Correct MemoryPressurePolicy docstring to reference the real config key.
- Add tests: Windows-safe sampler, single-knob policy, BotOS wiring, stats.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 10:04:22 +00:00
praisonai-triage-agent[bot]andMervin Praison ce285a8e96 fix: preserve schedule_add positional arg order for backward compat
Move the new continuable param to the end of schedule_add() so the
pre-existing 9th positional slot still binds accept_suggestion, avoiding
a silent behaviour change for positional callers (Greptile P1).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:59:54 +00:00
praisonai-triage-agent[bot]andMervin Praison 7755da50a4 fix: recover outbound DLQ init on transient storage failure (#3446)
A transient DLQ-init failure no longer latches _outbound_resilience_ready,
so a later delivery re-attempts initialization once storage recovers,
instead of permanently degrading to retry-only and silently dropping
permanently-failed replies. Adds a regression test.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:59:43 +00:00
praisonai-triage-agent[bot]andMervin Praison 410d169d28 fix: make exception text ASCII-safe with ascii(e) in smoke script
Runtime exception messages could contain non-cp1252 characters that
would re-trigger UnicodeEncodeError on Windows consoles when printed.
Wrap exception interpolation in ascii() for all 7 failure messages.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:58:54 +00:00
praisonai-triage-agent[bot] 09cf8f8d11 Merge pull request #3429 from MervinPraison/claude/issue-3423-20260727-0852
fix: replace emoji with ASCII tags in terminal_bench smoke script for Windows cp1252
2026-07-27 09:55:28 +00:00
MervinPraison 9adf9f3c25 docs: auto-update documentation parity trackers [skip ci] 2026-07-27 09:53:40 +00:00
praisonai-triage-agent[bot] 112e61c4b3 Merge pull request #3326 from MervinPraison/claude/issue-3307-20260723-1028
fix: async loop expansion, tool-tracking race, MCP skill-gate (#3307)
2026-07-27 09:52:19 +00:00
praisonai-triage-agent[bot]andMervinPraison ae592fc111 fix: make scheduled-job delivery continuable by default (fixes #3444)
A delivered automated brief now seeds a resumable session so the user's
reply in the same chat resumes the job's conversation with full context,
instead of landing as a contextless new turn.

- core: add declarable DeliveryTarget.continuable field (opt-out only,
  round-tripped in to_dict/from_dict) as the 3-way surface contract
- wrapper: gateway _deliver_scheduled_result seeds the reply session via
  the existing mirror_to_session path when continuable
- tool/CLI: thread continuable through schedule_add + a --no-continuable
  flag for fire-and-forget notices

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:51:54 +00:00
praisonai-triage-agent[bot]andMervinPraison a62c671d62 fix: add memory-aware gateway admission control (fixes #3445)
Gateway admission was concurrency/CPU-scaled only and blind to memory, so a
burst of concurrent turns on a small always-on host drives RSS up until the
OOM killer fires — observed only post-mortem. This adds a resource-pressure
policy that queues under soft RSS pressure and sheds under hard pressure,
reusing the existing admission seam.

Core (praisonaiagents/gateway): ResourceSample, ResourcePressurePolicyProtocol
and a stdlib-first MemoryPressurePolicy (pure decision, no heavy imports),
sitting beside the concurrency / rate-limit / scale-to-zero policy family.

Wrapper (praisonai_bot/bots/_admission.py): a lightweight _RssSampler
(psutil-optional, resource.getrusage fallback, self-disables on unsupported
platforms) and AdmissionGate(resource_policy=...) wiring that folds the
resource decision into admit() by escalating to the more restrictive outcome.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:51:46 +00:00
praisonai-triage-agent[bot]andMervinPraison 5c80362d6b fix: make outbound reply delivery crash-safe by default (fixes #3446)
Mirror the durable inbound journal on the outbound side: when no
outbound DLQ path is configured, default to the canonical per-platform
store (~/.praisonai/state/<platform>/outbound_dlq.sqlite) so a
permanently-failed or exhausted reply is parked (auditable + replayable)
instead of silently dropped. Escape hatch: outbound_resilience.enabled=false.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:50:21 +00:00
praisonai-triage-agent[bot] 574c060b0a Merge pull request #3422 from MervinPraison/claude/fix-praisonai-yaml-config-name-20260727
fix: use canonical praisonai.yaml as project config name (with praison.yaml fallback)
2026-07-27 09:48:40 +00:00
praisonai-triage-agent[bot]andMervin Praison 9dcddf1b19 fix: gateway-runtime contract falls back to legacy splices on older core
The wrapper permits a range of praisonaiagents versions (>=1.6.152), but
_attach_gateway_runtime imported GatewayRuntimeSeams/GatewayAdapterContractError
unconditionally — symbols only present in current core. On an older-but-allowed
core that import raised ImportError on every start()/probe()/health() (Greptile
P1). Guard the import and fall back to the pre-contract duck-typed splices so
those installs keep wiring identity resolution, delivery routing, admission
control, and cross-platform turn locking. The no-seams path now returns before
any import, staying a pure no-op independent of core version.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:48:01 +00:00
praisonai-triage-agent[bot] 61e8c1ec56 Merge pull request #3421 from MervinPraison/claude/issue-3420-20260727-0822
fix: scheduler async-drift, unlocked template cache, scheduled-YAML tool bypass (fixes #3420)
2026-07-27 09:46:05 +00:00
praisonai-triage-agent[bot]andMervin Praison becf0f30fd fix: recognize all loopback bind forms in reliability default (#3438)
Classify loopback numerically via ipaddress so 127.0.0.2,
127.255.255.255, and expanded IPv6 ::1 keep the snappy loopback drain
instead of the 15s production window. Addresses Greptile review feedback.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:45:18 +00:00
praisonai-triage-agent[bot]andMervin Praison 785f361ded fix: harden gateway reload classifier for empty channel name + core version skew (#3440)
- classify_reload now rejects empty channel names (channels., channels..enabled)
  and falls through to the fail-safe FULL restart instead of restarting channel ""
- wrapper _build_reload_plan gracefully degrades to full restart if an older
  supported praisonaiagents lacks classify_reload, instead of crashing the reload
- add regression tests for malformed channel paths

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:45:07 +00:00
praisonai-triage-agent[bot]andMervinPraison db15240a11 fix: give channel adapters a typed gateway-runtime contract (fixes #3439)
Replace the four duck-typed private-attribute splices in Bot._build_adapter
(identity resolver, delivery router, admission gate, per-turn lock map) with an
explicit core Protocol. A missing contract now fails loudly instead of silently
dropping admission control, delivery routing and cross-platform turn locking.

- core: add GatewayRuntimeSeams, SupportsGatewayRuntime, GatewayAdapterContractError
- praisonai-bot: BotSessionManager.attach_gateway_runtime implements the contract
- praisonai-bot: Bot._attach_gateway_runtime calls the typed seam once

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:36:11 +00:00
praisonai-triage-agent[bot]andMervinPraison 03b0d931dc fix: make gateway reliability safe by default (fixes #3438)
The unset (None) reliability posture now resolves to a backpressured
deployment — bounded admission ceiling + fair wait queue + graceful drain —
instead of the old no-admission one. It is bind-aware: a non-loopback bind
(a real deployment) resolves to the full production window, loopback keeps a
snappy 5s drain. reliability="off" opts back into today's immediate-teardown
behaviour; explicit reliability="default" keeps the legacy no-ceiling posture.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:35:53 +00:00
praisonai-triage-agent[bot]andMervinPraison 57dc4b115f fix: make gateway reload-scope classification canonical in core (fixes #3440)
Add a pure, side-effect-free ReloadScope/classify_reload registry to the
core SDK so hot-appliable vs channel-scoped vs agents vs full-restart is
classified identically by every runtime, instead of being duplicated
ad-hoc in the wrapper. The wrapper's _build_reload_plan now delegates to
core, keeping the existing scoped per-channel restart behaviour while the
contract "grows" in the authoritative layer. Backward-compatible.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:35:12 +00:00
praisonai-triage-agent[bot]andMervin Praison ab13eea127 fix: align published agents schema with runtime contract + log header failures
Addresses reviewer feedback on PR #3437:

- Greptile P1: the published editor schema was stricter than the runtime.
  generate_agents_schema() now relaxes AgentConfig (drops required
  role/goal/backstory, which the runtime auto-fills or maps from
  'instructions') and allows list-form roles/agents (runtime _list_to_dict),
  so editors no longer flag valid, executable YAML. The strict YAMLConfig used
  by ConfigValidator is unchanged.
- Greptile P2: replace the silent `except Exception: pass` around the
  yaml-language-server header write with a debug log so a dropped directive is
  diagnosable.
- Regenerate agents.schema.json; add a runtime-parity guard test.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:32:02 +00:00
praisonai-triage-agent[bot]andMervin Praison baa1222dc1 fix: close redaction gaps in session export sanitise (#3426)
- Legacy-only sessions now honour --sanitise instead of returning a raw
  verbatim transcript, closing a secret-leak gap.
- Enforce --redact-level contract: validate against REDACT_LEVELS (standard|
  strict), reject typos at the CLI, and give strict a real effect (masks
  bearer tokens and PEM private-key blocks).
- Path matcher now covers single-segment POSIX (/tmp), C:/ Windows, and UNC
  (\\server\share) paths; the cwd is masked as a stable path placeholder so it
  is no longer half-masked as a secret leaving a dangling suffix.
- Add tests for single-segment/UNC paths, cwd suffix, strict mode, invalid
  level, and exported REDACT_LEVELS.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:24:38 +00:00
praisonai-triage-agent[bot]andMervinPraison fda4d2424d fix: publish agents.yaml JSON Schema + wire editor autocomplete (fixes #3427)
Derive a JSON Schema from YAMLConfig (generate_agents_schema), publish it as
a committed agents.schema.json artefact, expose it via `praisonai validate
schema --agents/--output`, and prepend a `# yaml-language-server: $schema=`
header when auto.py scaffolds agents.yaml so editors give autocomplete /
inline validation out of the box. Authoring-time only; runtime parsing and
execution are unchanged (a leading YAML comment is ignored by safe_load).

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:08:39 +00:00
praisonai-triage-agent[bot]andMervin Praison 3cd823d4e2 fix: probe praisonai_mcp.mcp_server submodule and report skip reason
Address CodeRabbit review on MCP test conftest:
- Check the shim's required praisonai_mcp.mcp_server submodule instead of only
  the top-level package, so a partial/incompatible install can't pass the guard
  while collection still fails.
- Emit a pytest_report_header when MCP tests are skipped so contributors see why
  and how to install praisonai-mcp.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:08:35 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy ba1e97cdbb fix: map box-drawing chars in bot error sanitizer for cp1252 (fixes #3430)
Playwright's "playwright install" banner uses box-drawing frame characters
(U+2551 etc.). On Windows cp1252 consoles these could clutter the sanitized
error text with '?' placeholders, obscuring the actionable hint. Map the
common frame characters to spaces in safe_error_message's symbol table so the
hint stays readable while remaining ASCII-safe.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-27 09:06:58 +00:00
praisonai-triage-agent[bot]andMervinPraison d1b6d38b75 feat: add opt-in transcript redaction to session export (fixes #3426)
Add a lightweight, deterministic redactor so `praisonai session export
<id> --sanitise` (alias `--sanitize`) replaces secrets, absolute paths,
the working directory, and embedded file contents with stable
`[redacted:<category>:<n>]` placeholders. Default export is unchanged.

- new redact.py helper with stable placeholder map (stdlib only)
- wire redact/redact_level through export_session (Python: redact=True)
- wire --sanitise/--sanitize + --redact-level CLI flags, default off
- unit tests over a seeded secret, absolute path, and stable placeholders

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 09:05:09 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy e474e0cd5c fix: skip MCP wrapper unit tests cleanly when praisonai-mcp absent (fixes #3425)
Add tests/unit/mcp/conftest.py that restores the monorepo dev layout via
ensure_praisonai_mcp() and uses collect_ignore_glob to skip the directory
when praisonai_mcp is neither installed nor present as a sibling checkout,
turning a ModuleNotFoundError collection error into a clean no-op.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-27 08:56:59 +00:00
praisonai-triage-agent[bot]andDhivya-Bharathy d4e3461d37 fix: replace emoji with ASCII tags in terminal_bench smoke script for Windows cp1252 (fixes #3423)
The basic smoke script crashed with UnicodeEncodeError on Windows
default consoles (cp1252) because print() statements embedded emoji
(U+1F9EA, U+2705, U+274C, U+1F389) that cannot be encoded to stdout.

Replace all emoji with ASCII status tags ([TEST], [OK], [FAIL]) so the
script runs on any terminal encoding without decoration loss.

Co-authored-by: Dhivya-Bharathy <[email protected]>
2026-07-27 08:54:06 +00:00
praisonai-triage-agent[bot]andMervin Praison a8d73265c6 test: cover .yml extensions and canonical-over-legacy precedence for project config
Addresses CodeRabbit nitpick: add praisonai.yml / legacy praison.yml
discovery tests and a precedence test asserting canonical praisonai.yaml
wins over legacy praison.yaml when both are present.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 08:53:16 +00:00
praisonai-triage-agent[bot]andLeebana e4179b412d fix: add canonical praisonai.yaml as project config name
The praisonai-code resolver only searched for `praison.yaml` at the
project root, which is inconsistent with the agents SDK loader
(`praisonaiagents/config/loader.py`) that uses the canonical
`praisonai.yaml`. Add `praisonai.yaml`/`praisonai.yml` as the primary
project-root names while retaining `praison.yaml`/`praison.yml` for
backward compatibility, and update the docstring reference. Adds
regression tests covering both the canonical and legacy names.

Co-authored-by: Leebana <[email protected]>
2026-07-27 08:47:09 +00:00
praisonai-triage-agent[bot]andMervin Praison d15657ba21 fix(skills): read MCP server registry live to avoid stale STRICT gate
CapabilityValidator cached the MCP server snapshot once, so servers that
connected after the first validation stayed invisible under STRICT
enforcement. Read the process-level registry live each call (cheap
set-copy under lock); tool cache is unchanged. (#3307)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 08:44:31 +00:00
praisonai-triage-agent[bot]andMervin Praison b19e4da70b fix: async loop expansion, tool-tracking race, MCP skill-gate (fixes #3307)
Gap 1: port loop-task pre-expansion from workflow() into aworkflow() so
async workflows with a CSV-driven loop start task expand per-row instead
of running once.

Gap 2: guard the per-turn _turn_tools_used buffer with the same
AsyncSafeState lock that protects chat_history, routing all sites through
_reset/_record/_drain helpers so concurrent chat()/achat() turns on one
Agent no longer corrupt hook/self-improve tool data. Backward-compatible
_turn_tools_used property retained.

Gap 3: track namespaced MCP server names in a process-level registry
(MCP.list_active_server_names(), populated in with_tool_prefix) and read
it from CapabilityValidator._get_available_servers so MCP-server-gated
skills can pass STRICT validation instead of always failing closed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 08:44:31 +00:00
MervinPraison 54b43340f5 docs: auto-update api.md [skip ci] 2026-07-27 08:43:41 +00:00
Leebana febdd8ec6e Merge pull request #3419 from MervinPraison/claude/issue-3418-20260727-0714
fix: shared-port endpoints, async memory init, MongoDB short-term embeddings
2026-07-27 09:42:48 +01:00
praisonai-triage-agent[bot]andMervin Praison b3349e1ce1 fix(handoff): isolate handoff chain per parallel task (Greptile P1)
parallel_handoffs runs children via asyncio.gather, which copies the
context per task. A copied ContextVar binding still references the same
parent list object, so when parallel_handoffs runs inside a non-empty
parent handoff chain, sibling tasks mutated a shared list and corrupted
cycle/depth tracking. Rebind each task's chain to a fresh per-task copy
at _run_one entry so siblings are fully isolated.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 08:42:34 +00:00
praisonai-triage-agent[bot]andMervinPraison c79d640e82 fix: session_id collisions, concurrent handoff corruption, async retry hook crash (fixes #3397)
- memory_mixin: append per-instance uuid suffix to default session_id so
  same-named agents can no longer collide and bleed chat history
- handoff: replace threading.local() with contextvars.ContextVar so handoff
  chain/depth is isolated per asyncio.Task under parallel_handoffs
- hooks/runner: add HookRunner.execute_async alias so async retry-with-backoff
  no longer crashes with AttributeError

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 08:42:34 +00:00
Leebana 1a372f6e41 Merge pull request #3417 from MervinPraison/claude/issue-3415-20260726-1713
fix: defer eager import json in _logging.py to structured-logging call site
2026-07-27 09:42:27 +01:00
Leebana cd56c59551 Merge pull request #3399 from Hore01/fix-stop-project-config-home-walkup
fix: stop project config discovery at home directory
2026-07-27 09:41:54 +01:00
Leebana ebd27167a7 Merge pull request #3396 from MervinPraison/feat/praisonai-train-mtp
feat(train): MTP fast-inference for Gemma-4 (self-speculative decoding, +1.40x measured)
2026-07-27 09:40:59 +01:00
Leebana 02631d69d6 Merge pull request #3394 from MervinPraison/claude/issue-3392-20260725-1712
fix: remove dead import logging from ~110 core modules
2026-07-27 09:40:11 +01:00
Leebana 2ce4228e3d Merge pull request #3371 from MervinPraison/claude/issue-3368-20260725-0716
fix: async-safe handoff chain, session read-error data safety, per-agent approval scoping
2026-07-27 09:39:35 +01:00
Leebana 3b7e2c8875 Merge pull request #3367 from MervinPraison/feat/praisonai-train-robustness
feat(train): non-developer robustness — clean errors, preflight, export command, Ollama/GGUF/HF failure handling
2026-07-27 09:39:13 +01:00
Leebana 2bb18e8e59 Merge pull request #3366 from MervinPraison/claude/issue-3364-20260724-1713
refactor: extract duplicate MCP to_openai_tool() into shared helper
2026-07-27 09:38:54 +01:00
Leebana b047d92040 Merge pull request #3365 from MervinPraison/claude/issue-3363-20260724-1712
fix: reuse canonical token heuristic in compaction fallback
2026-07-27 09:38:37 +01:00
Leebana 8d4b8d15a4 Merge pull request #3357 from MervinPraison/claude/issue-3355-20260724-1419
fix: root /undo at the bot workspace, not process cwd (#3355)
2026-07-27 09:38:19 +01:00
praisonai-triage-agent[bot]andMervin Praison f0c733710c fix: close cache put/clear race and async zero-budget false start (#3420)
Address reviewer-flagged concurrency gaps in the scheduler + template cache:

- TemplateCache locks are now process-wide (class-level, keyed by path) so two
  independent instances over the same dir coordinate; get() reads under the
  per-key lock so it never observes the intermediate two-rename window; put()/
  invalidate() take root+key locks and clear() takes the root lock, so a
  concurrent clear() can no longer rmtree a half-written entry. put() stages
  into a reserved .staging subdir (same fs, atomic os.replace) that clear()
  skips, eliminating the put-vs-clear FileNotFoundError.
- AsyncAgentScheduler.start() no longer reports a successful start (and no
  longer spins up a background task) when the immediate run trips the budget
  brake (e.g. max_cost=0), matching the actually-stopped state.

Verified: 4 writer/clearer + 2 reader concurrency smoke test -> 0 races;
zero-budget start returns False with no task; 335 scheduler+template tests pass.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 08:38:02 +00:00
Leebana 9f08e27d15 Merge pull request #3353 from MervinPraison/claude/issue-3352-20260724-0942
fix: prompt-cache-stability contract for the gateway
2026-07-27 09:37:49 +01:00
MervinPraison 6507559279 docs: auto-update feature parity trackers [skip ci] 2026-07-27 08:37:28 +00:00
Leebana 33584899a9 Merge pull request #3343 from Dhivya-Bharathy/fix/e2e-examples-batch4
fix: resolve 4 remaining E2E example failures after batch-3 merge
2026-07-27 09:36:58 +01:00
Leebana cbfff02451 Merge pull request #3342 from MervinPraison/feat/gateway-diagnostics-upgrade
feat(gateway): tiered diagnostics for runtime, inbound, and duplicates
2026-07-27 09:36:43 +01:00
MervinPraison 8b675d3ed0 docs: auto-update api.md [skip ci] 2026-07-27 08:35:55 +00:00
Leebana f21ec569a5 Merge pull request #3319 from MervinPraison/claude/issue-3307-20260723-1021
fix: aworkflow loop expansion, concurrent turn-tool race, MCP skill-gate discovery
2026-07-27 09:35:29 +01:00
praisonai-triage-agent[bot]andMervinPraison 9d831532ab fix: close scheduler async-drift, cache race, scheduled-YAML tool gaps (fixes #3420)
- Async scheduler now honours the intentional-silence marker on delivery
  (shared _should_suppress_delivery on _BaseAgentScheduler); removes the
  duplicate budget guard, replacing both with a single _budget_exceeded()
  helper that treats max_cost=0 as a real zero budget.
- TemplateCache.put()/invalidate() now stage into a sibling temp dir and
  atomically os.replace() under a per-key lock, so concurrent readers never
  observe a half-populated or mid-rmtree cache entry (multi-agent/interprocess).
- Scheduled agents.yaml tools now resolve through the canonical ToolResolver
  (same path as `praisonai run`), instead of dropping everything but a
  hardcoded search_tool — keeping CLI/YAML/Python behaviour identical.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 08:28:18 +00:00
praisonai-triage-agent[bot]andMervin Praison 0729bd5c47 fix: prevent async event-loop block on failed memory init; refresh OpenAPI cache on shared-port launch
- agents.py: _build_execution_context gains skip_memory_init; aexecute_task
  passes True so a failed initialize_memory_async() no longer falls through
  to the synchronous initialize_memory() on the event-loop thread.
- execution_mixin.py: reset app.openapi_schema after registering a shared-port
  route so later launch() calls appear in /openapi.json and /docs.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 07:27:09 +00:00
praisonai-triage-agent[bot]andMervinPraison eed2ada270 fix: shared-port endpoints, async memory init, MongoDB short-term embeddings (fixes #3418)
- Agent.launch(): register every path (not only first per port) and move the
  keep-alive loop outside _server_lock so a second agent on a shared port is
  no longer silently dropped and the process-wide lock isn't held forever.
- aexecute_task(): initialize memory via initialize_memory_async() to avoid
  blocking the shared event loop on synchronous Memory() construction.
- MongoDBMemoryAdapter: factor embedding logic into shared _store/_search
  helpers so short-term memory also gets/uses embeddings when
  use_vector_search=True, matching the long-term tier.

Co-authored-by: MervinPraison <[email protected]>
2026-07-27 07:20:36 +00:00
praisonai-triage-agent[bot]andMervinPraison f51f8ecdab fix: remove dead import logging from ~110 core modules (fixes #3392)
These modules log exclusively via get_logger and never reference the
logging. namespace; the standalone import logging is dead code left over
from the get_logger migration. Removed it only where logging. is never
referenced (111 files); files that genuinely use logging. are untouched.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 17:58:20 +00:00
MervinPraison f2ff1c8f8c docs: auto-update documentation parity trackers [skip ci] 2026-07-26 17:56:32 +00:00
praisonai-triage-agent[bot] ceebb5d8e6 Merge pull request #3416 from MervinPraison/claude/issue-3414-20260726-1713
fix: remove orphaned FastContext dead code (file_watcher.py + search_strategy.py)
2026-07-26 17:56:01 +00:00
praisonai-triage-agent[bot] 2c57dc4559 Merge pull request #3413 from MervinPraison/claude/issue-3412-20260726-1623
fix: remove dead duplicate get_available_integrations() in registry.py
2026-07-26 17:23:34 +00:00
praisonai-triage-agent[bot]andMervin Praison 48579bde51 fix: defer eager import json in _logging.py to structured-logging call site (fixes #3415)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 17:14:50 +00:00
praisonai-triage-agent[bot]andMervin Praison 2f11a6a53e fix: remove orphaned FastContext dead code (fixes #3414)
Delete two unreachable modules under context/fast/ that are never
imported, exported, or referenced anywhere in the SDK, tests, examples,
or docs:
- indexer/file_watcher.py (FileWatcher, IncrementalIndexer, ...)
- search_strategy.py (SearchStrategy, SearchState, SearchPhase)

Grep confirms only the definition sites matched; no importers exist.
Live FastContext path (fast_context, search_backends, parallel_executor,
indexer/file_indexer, symbol_indexer) is unchanged. No __init__.py edits
needed since neither module is exported.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 17:14:31 +00:00
praisonai-triage-agent[bot]andMervin Praison 2c469c5a60 docs: drop stale get_available_integrations() mention from registry docstring
Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 16:28:19 +00:00
praisonai-triage-agent[bot]andMervinPraison ce7ce9f047 fix: remove dead duplicate get_available_integrations() in registry.py (fixes #3412)
The registry.py copy of get_available_integrations() was unreferenced dead
code duplicating the canonical base.py implementation. The public symbol is
exported from integrations/__init__.py and lazily resolved via
_unified_registry.py, which binds to the base.py version. No importer, no
__all__ entry, and no internal caller referenced the registry.py copy.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 16:24:28 +00:00
MervinPraison a5ecf28b8e docs: auto-update api.md [skip ci] 2026-07-26 11:36:49 +00:00
praisonai-triage-agent[bot] 866913581c Merge pull request #3405 from MervinPraison/claude/issue-3403-20260726-0852
fix: structured NDJSON stream events for YAML/AgentTeam runs
2026-07-26 11:36:22 +00:00
praisonai-triage-agent[bot] c010e0c07b Merge pull request #3411 from MervinPraison/claude/issue-3410-20260726-0946
fix: wire opt-in event-loop liveness watchdog into gateway
2026-07-26 11:01:46 +00:00
MervinPraison bc35bbb78e docs: auto-update api.md [skip ci] 2026-07-26 10:44:33 +00:00
praisonai-triage-agent[bot] b56a78eed7 Merge pull request #3409 from MervinPraison/claude/issue-3407-20260726-0914
fix: SQLite-backed transcript store for concurrent gateways
2026-07-26 10:44:10 +00:00
praisonai-triage-agent[bot]andMervin Praison 6299a03459 fix: wire prompt-cache metrics, clear stale signatures, detect tool schema drift (#3352)
Address three P1 review findings on the prompt-cache-stability contract:

- Wire GatewayMetrics into per-bot sessions via a new _stamp_metrics splice
  (mirrors _stamp_admission_gate/_stamp_identity_resolver), called from both
  start_channels and hot-reload, so prompt_cache_invalidations_total actually
  increments in production instead of staying zero.
- Clear _prefix_sig in every session-clear path (_clear_session_data,
  reap_stale, reset_all) so a reopened session establishes a fresh baseline
  instead of emitting a false PROMPT_PREFIX_INVALIDATED against the old one.
- Fingerprint the full provider-visible tool schema (name + description +
  parameters for dict tools, name + docstring for callables) instead of only
  tool names, so a same-name schema edit is detected. Best-effort; never raises.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 10:39:42 +00:00
praisonai-triage-agent[bot]andMervinPraison 751998e36e fix: add prompt-cache-stability contract for the gateway (fixes #3352)
Core (praisonaiagents): new advisory HookEvent.PROMPT_PREFIX_INVALIDATED
and a pure prompt_prefix_signature(agent) that fingerprints only the
cache-relevant prefix (model + sorted tool names + system-prompt fp),
excluding volatile per-turn data. Kept out of agent.py to avoid bloat.

Wrapper/bot: BotSessionManager computes the signature after its per-turn
tool/model swaps, meters drift via an optional prompt_cache_invalidations_total
GatewayMetrics counter, and fires the advisory hook so silent provider
prompt-cache misses on long-lived conversations become auditable.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 10:39:42 +00:00
MervinPraison c9cdedfb61 docs: auto-update feature parity trackers [skip ci] 2026-07-26 10:36:10 +00:00
praisonai-triage-agent[bot] dd39391090 Merge pull request #3408 from MervinPraison/claude/issue-3406-20260726-0914
fix: add canonical RunOutcome terminal-outcome for agent runs
2026-07-26 10:35:46 +00:00
praisonai-triage-agent[bot]andMervin Praison 5df9114444 fix: emit terminal run.error on failed AgentTeam stream-json run
When team.astart() raises during a YAML/AgentTeam `--output stream-json`
run, the adapter now emits a terminal run.error event (best-effort,
without masking the original exception) before detaching the bridge,
matching the single-agent path's contract so consumers can distinguish
a failed run from an incomplete/still-running one. Fixes greptile P1.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 10:30:48 +00:00
praisonai-triage-agent[bot]andMervinPraison f4690e2fdd fix: emit per-agent NDJSON stream events for YAML/AgentTeam runs (fixes #3403)
AgentTeam now exposes a lazy aggregate stream_emitter that fans in member
agents' StreamEventEmitter events, tagging each with the emitting agent's
agent_id. The PraisonAI adapter attaches the CLI stream-json bridge to this
team emitter around team.astart(), so `--output stream-json` on a YAML/team
run emits the same per-agent, per-step NDJSON stream as single-agent runs.
Both paths are zero-overhead no-ops outside structured output mode.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 10:30:48 +00:00
praisonai-triage-agent[bot] acdfc4189c Merge pull request #3404 from MervinPraison/claude/issue-3402-20260726-0852
fix: CLI session continuity for YAML/AgentTeam runs
2026-07-26 10:27:49 +00:00
praisonai-triage-agent[bot]andClaude 0c72663ea8 fix: expose --watchdog flags on active Typer gateway start command (#3410)
The event-loop liveness watchdog flags were only registered on the legacy
argparse parser in cli/features/gateway.py, which the real
`praisonai gateway start` Typer entrypoint (cli/commands/gateway.py) never
uses — so `--watchdog` / `--watchdog-timeout` were rejected at the primary
opt-in surface. Add both options to the Typer command and forward them to
GatewayHandler.start using the same None-means-fall-back-to-YAML convention
as the other store_true flags. `restart` already replays them via the
persisted start-flags. Adds 3 CLI-surface tests.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-26 10:01:36 +00:00
praisonai-triage-agent[bot]andMervinPraison d745fde198 fix: wire opt-in event-loop liveness watchdog into gateway (fixes #3410)
Arm the existing core LoopWatchdog (#3385) around the gateway serving loop
so a frozen event loop dumps all-thread stacks and hard-exits with the
restart exit code, letting systemd/launchd/Docker relaunch the process.
Opt-in via gateway.watchdog YAML block and --watchdog/--watchdog-timeout
CLI flags; zero cost when disabled. No systemd unit change needed since it
reuses GATEWAY_RESTART_EXIT_CODE (75).

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 09:53:42 +00:00
praisonai-triage-agent[bot] 3f29794da9 Merge pull request #3401 from MervinPraison/claude/issue-3400-20260726-0822
fix: harden wrapper adapters + DRY bootstrap (fixes #3400)
2026-07-26 09:32:04 +00:00
praisonai-triage-agent[bot]andMervin Praison c8bb248ee3 fix: atomic cross-process RMW + legacy JSON migration for SQLite transcript store
- Make add_message/_modify_session_locked run the whole read-modify-write
  inside a single BEGIN IMMEDIATE transaction so concurrent gateway
  processes cannot lose appends (the process-local RLock alone did not
  serialize across processes). Fixes Greptile P1 lost-update.
- Import legacy per-session JSON transcripts once when the SQLite store
  first opens beside them, so upgrading to the sqlite default preserves
  durable/resumable history. Fixes Greptile P1 legacy-invisibility.
- Wire the YAML session.store key through MultiChannelGatewayConfig.from_dict
  so store: file|sqlite is actually honoured.
- Add concurrent-writer and legacy-migration tests.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 09:28:25 +00:00
praisonai-triage-agent[bot]andMervin Praison c169bc73e2 fix: authoritative hard_timeout + honour external cancellation in RunOutcome
Addresses two P1 review findings on the RunOutcome terminal-outcome contract:

- Nested operation timeouts no longer misreported as run-budget hard_timeout.
  RunOutcome.from_exception no longer promotes a bare asyncio.TimeoutError to
  hard_timeout; the run-level budget is now the sole authoritative source of
  hard_timeout, enforced explicitly in _astart_with_outcome via a task+wait so
  only our own budget expiry maps to hard_timeout (inner TimeoutErrors -> failed).
- External asyncio.CancelledError is re-raised instead of being swallowed into a
  benign RunOutcome, so cooperative cancellation / host shutdown is honoured.

Updates tests accordingly and adds coverage for nested-timeout->failed and
external-cancellation-propagates.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 09:25:25 +00:00
praisonai-triage-agent[bot]andMervinPraison 5352aa67fb fix: add SQLite-backed transcript store for concurrent gateways (fixes #3407)
Implement SqliteTranscriptStore(DefaultSessionStore) storing session
transcripts as one row per session in a WAL SQLite DB (concurrent readers,
transactional single-row writes, indexed lookups) instead of per-session JSON
files under a cross-process FileLock. It overrides only the persistence
primitives, inheriting all retention/compaction, message API, search scoring,
bookends and lineage-dedup logic unchanged.

Directory scans (list/search/gateway routing) are replaced with indexed
SELECTs. The gateway now defaults to this store when persistence is enabled,
selectable via a new `session.store` config key (`sqlite` | `file`).

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 09:20:59 +00:00
praisonai-triage-agent[bot]andMervinPraison 4ad4c85451 fix: add canonical RunOutcome terminal-outcome for agent runs (fixes #3406)
Adds a small, closed RunOutcome result type in core plus an opt-in
return_outcome=True on run()/astart() so long-running hosts (gateways/bots)
can decide delivery/retry/DLQ from one field instead of inferring the
terminal state from exception identity. Distinguishes
completed|hard_timeout|cancelled|aborted|failed. String return unchanged.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 09:19:01 +00:00
praisonai-triage-agent[bot]andMervin Praison 2a81e48638 fix: restore team conversation history for YAML session continuity
Core save/restore_session_state only persist team._state, not per-agent
chat_history, so resumed/forked YAML team runs did not actually continue
the prior conversation (Greptile P1). Add wrapper-only capture/rehydrate
helpers that stash each agent's chat_history into team state on save and
re-inject it on restore — parity with the single-agent path, no core
change and no new Agent/AgentTeam params.

Also replace the source-text arun test with a behavioral call-order test
and add roundtrip/no-duplicate coverage for the chat-history helpers.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 09:07:02 +00:00
praisonai-triage-agent[bot]andMervinPraison 0d6e07b2f0 fix: CLI session continuity for YAML/AgentTeam runs (fixes #3402)
Route YAML/team runs through the same --continue/--session/--fork/--no-save
continuity the single-agent prompt path uses, via existing core APIs.

- praisonai_adapter.arun(): resolve resume_session/auto_save from cli_config,
  force-enable shared memory when a session is active, restore_session_state
  before astart() and save_session_state after (save never fails a run).
- praison_ai._extract_cli_config_for_yaml(): thread resume_session/auto_save
  into cli_config for `run agents.yaml`.

Wrapper-only; no new params/deps/core changes. Adds regression tests.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 09:00:07 +00:00
praisonai-triage-agent[bot]andMervin Praison baa86920fa fix: lazy-register default readers at call time + guard bootstrap find_spec
Address final-review P1s on #3401:
- Composite readers (AutoReader/DirectoryReader/GlobReader) now idempotently
  wire the default readers into the core registry on first load(), so they no
  longer silently return [] when register_default_adapters() was never called.
  Keeps imports side-effect free (wrapper does heavy wiring at call time).
- _ensure_sibling() guards importlib.util.find_spec against ImportError/
  ValueError from a discoverable-but-broken installed sibling, falling back to
  the monorepo checkout instead of crashing.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 08:33:50 +00:00
praisonai-triage-agent[bot]andMervinPraison f84842ea86 fix: harden wrapper adapters + DRY bootstrap (fixes #3400)
- Remove import-time auto-registration in adapters/{retrievers,rerankers,
  readers}.py so importing them no longer mutates core-SDK singletons;
  add idempotent, thread-safe register_default_adapters() single edge
  (mirrors vector_stores.py policy).
- Make aretrieve()/arerank() genuinely async via asyncio.to_thread so the
  blocking provider call no longer freezes the caller's event loop.
- Collapse the six copy-pasted ensure_praisonai_* functions in
  _bootstrap.py into one _ensure_sibling() helper + table, fixing the
  sys.path double-insert race with a lock.

Co-authored-by: MervinPraison <[email protected]>
2026-07-26 08:26:50 +00:00
praisonai-triage-agent[bot]andMervin Praison 6ac733e74c fix: align home-boundary docstring and add regression tests
Update _load_project_config docstring to reflect that home is now
excluded from project config discovery, and add two regression tests
covering the home-directory walk-up boundary.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 08:20:41 +00:00
Hore01 62827f708c fix: stop project config discovery at home directory 2026-07-26 09:14:43 +01:00
praisonai-triage-agent[bot]andMervin Praison 4b6bf44630 fix(train): local GGUF export, correct llama.cpp binary lookup, disk preflight
Address reviewer P1s on MTP fast-inference PR:
- export gguf now produces a LOCAL .gguf (needed by serve/--mtp-draft) and
  only additionally pushes to the Hub when --hf is given (was Hub-only).
- find_llama_binary no longer returns a differently-named executable when
  LLAMA_CPP_BIN points at one binary and a sibling is requested; falls through
  to PATH / raises instead of launching e.g. llama-cli with server flags.
- Ollama disk preflight only enforces the 1.5x requirement when the source
  size is known; skips (no false-positive block) for Hub-backed FROM.

Adds 6 tests (binary-lookup mismatch cases, gguf local/push dispatch,
unknown-source disk skip); full praisonai-train unit suite 118 passed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-26 00:42:13 +00:00
MervinPraisonandClaude Opus 4.8 8355b7ca49 feat(train): MTP fast-inference support (Gemma-4 self-speculative decoding)
Adds Multi-Token Prediction (MTP) support so a fine-tuned Gemma-4 model can be
served with lossless self-speculative decoding via llama.cpp --spec-type draft-mtp,
using the matching STOCK drafter (no drafter retraining needed).

New (additive):
- train/_mtp.py       resolve_drafter()/fetch_drafter() -> unsloth gemma-4 MTP
                      drafter GGUF (E2B/E4B/12B, verified on the Hub)
- train/_llamacpp.py  find_llama_binary/build_mtp_cmd/serve/benchmark +
                      parse_llama_timings (models _ollama.py error style)
- cli/commands/serve.py  'praisonai-train serve --gguf ... [--benchmark]',
                      auto-fetches drafter, clean fallback for non-Gemma-4
- tests/unit/train/test_mtp.py  22 tests (resolver, download, flag assembly,
                      binary-missing, timing parse)

Wiring (minimal edits):
- cli/commands/train.py  'export --mtp-draft' fetches the drafter alongside GGUF
- train/llm/trainer.py   KNOWN_KEYS += mtp_draft/mtp_draft_repo/mtp_draft_file/
                         spec_draft_n_max
- cli/app.py             register serve subcommand

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-26 01:23:55 +01:00
MervinPraison 631d2e90b0 docs: auto-update documentation parity trackers [skip ci] 2026-07-25 18:08:49 +00:00
praisonai-triage-agent[bot] 1f1df1f5d4 Merge pull request #3395 from MervinPraison/claude/issue-3393-20260725-1713
fix: remove dead code helpers in config/parse_utils.py
2026-07-25 18:08:12 +00:00
MervinPraison 316893a91e fix(release): 3-day patch cadence and explicit PyPI __token__ auth
Extend release-gate dedupe from daily to every 3 days and configure uv publish with UV_PUBLISH_USERNAME=__token__ per PyPI API token guidance.
2026-07-25 18:24:10 +01:00
MervinPraison aa0b7dcfcc Release v4.6.156 2026-07-25 17:23:45 +00:00
MervinPraison 7b01d4c5c8 Bump praisonai-sandbox to 0.0.6 2026-07-25 17:23:39 +00:00
MervinPraison bc794bd686 Bump praisonai-mcp to 0.0.8 2026-07-25 17:23:33 +00:00
MervinPraison 8c8f4285e6 Bump praisonai-browser to 0.0.8 2026-07-25 17:23:28 +00:00
MervinPraison ec4fb7cf0d Bump praisonai-train to 0.0.12 2026-07-25 17:23:22 +00:00
MervinPraison e9c2876b39 Bump praisonai-bot to 0.0.41 2026-07-25 17:23:16 +00:00
MervinPraison 4cdf68fdd5 Bump praisonai-code to 0.0.56 2026-07-25 17:23:09 +00:00
MervinPraison c7db22aee1 Bump praisonaiagents to 1.6.160 2026-07-25 17:23:01 +00:00
praisonai-triage-agent[bot]andMervinPraison 7e49f3a167 fix: remove dead code helpers in config/parse_utils.py (fixes #3393)
Remove three module-level helpers that were never referenced anywhere in
the monorepo and were not part of the public API (no __all__, absent from
config/__init__.py and the top-level lazy-import map):

- parse_url_to_config
- is_numeric_string
- make_array_error

All exported/used helpers remain untouched.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 17:16:10 +00:00
praisonai-triage-agent[bot] 14726713db Merge pull request #3390 from MervinPraison/claude/issue-3389-20260725-1616
perf: lazy-load pathlib in praisonai._bootstrap
2026-07-25 17:14:20 +00:00
Mervin Praison 3d2170c817 Merge pull request #3391 from Hore01/fix-ui-default-app-utf8
fix: read bundled default_app.py using UTF-8
2026-07-25 18:07:47 +01:00
praisonai-triage-agent[bot]andMervinPraison fbf6bc7c20 perf: lazy-load pathlib in _bootstrap to trim import hot path (fixes #3389)
Move the module-level `from pathlib import Path` into each
`ensure_praisonai_*` monorepo-dev fallback branch. Path is only ever
referenced after the `import praisonai_<pkg>` early-return fails, so the
installed-wheel hot path no longer pays pathlib's ~8.7ms cold-import cost.
Behaviour is byte-for-byte identical.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 16:18:23 +00:00
Iyanuoluwa007 eeedce60f8 fix: read bundled default_app.py using UTF-8 2026-07-25 17:13:39 +01:00
praisonai-triage-agent[bot] 3941398dd5 Merge pull request #3388 from MervinPraison/claude/issue-3386-20260725-0945
fix: label crash-recovered outbound messages as possible duplicates
2026-07-25 10:56:19 +00:00
MervinPraison 4252ad2ef1 docs: auto-update documentation parity trackers [skip ci] 2026-07-25 10:50:00 +00:00
praisonai-triage-agent[bot] 4c98b5fa2a Merge pull request #3387 from MervinPraison/claude/issue-3385-20260725-0944
fix: add event-loop liveness watchdog primitive
2026-07-25 10:49:28 +00:00
praisonai-triage-agent[bot] 449c65e4dc Merge pull request #3383 from MervinPraison/claude/issue-3379-20260725-0917
fix: re-drive interrupted turns + notify channel on gateway restart
2026-07-25 10:22:44 +00:00
praisonai-triage-agent[bot] 00322371d9 Merge pull request #3377 from MervinPraison/claude/issue-3376-20260725-0902
feat: interactive LLM-assisted praisonai agent create
2026-07-25 10:18:53 +00:00
praisonai-triage-agent[bot] 8f9469b5b3 Merge pull request #3382 from MervinPraison/claude/issue-3378-20260725-0916
fix: apply gateway config hot-reload instead of no-op
2026-07-25 10:15:49 +00:00
MervinPraison a890a2b40c docs: auto-update documentation parity trackers [skip ci] 2026-07-25 10:10:08 +00:00
praisonai-triage-agent[bot] eb751bba0f Merge pull request #3381 from MervinPraison/claude/issue-3380-20260725-0917
fix: add observe group_policy to retain unmentioned messages as context
2026-07-25 10:09:36 +00:00
praisonai-triage-agent[bot] 3c62a3b76b Merge pull request #3375 from MervinPraison/claude/issue-3374-20260725-0821
fix: eager shim walk, blocking AgentOS chat, CLI integration races (#3374)
2026-07-25 10:05:51 +00:00
praisonai-triage-agent[bot]andMervin Praison 5480b67d44 fix: preserve recovery label across annotator failures and transient re-send retries
Addresses two correctness gaps in the crash-recovery labelling (PR #3388):

- CodeRabbit: hand recovery_annotator its own fresh payload copy and only
  adopt a dict result, so a mutate-then-raise no longer leaks a half-labelled
  payload; validate non-dict returns.
- Greptile P1: keep a crash-recovered entry in the 'recovered' state on a
  transient re-send failure (mark_failed keep_recovered) so the duplicate
  label survives the retry instead of being demoted to 'failed' and dropped.

Adds 3 regression tests (mutation-then-raise fallback, non-dict return,
sticky-recovered retry). All 69 outbox/delivery/reconcile tests pass.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:57:39 +00:00
praisonai-triage-agent[bot]andMervin Praison 4a77f2daa8 fix: harden loop watchdog (disarm race + non-finite interval)
- disarm racing an in-flight wedge no longer triggers os._exit (re-check
  _stop before the destructive exit) so a deliberate disarm never causes a
  supervisor restart (Greptile P1)
- reject NaN/inf probe_interval_s to avoid a dead watchdog worker or a
  hung shutdown via Event.wait/Thread.join (Greptile P2)
- add tests for both cases

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:54:43 +00:00
praisonai-triage-agent[bot]andMervinPraison 962c9f5e70 fix: label crash-recovered outbound messages as possible duplicates (fixes #3386)
Add an optional recovery_annotator hook to OutboundQueue.drain, applied only
on the unreconciled 'recovered' branch, so a mid-send-crash message re-sent
at-least-once can be visibly marked as a possible duplicate instead of being
re-delivered silently. DurableDelivery gains a backward-compatible
mark_recovered flag (off by default) that prefixes recovered string replies
via _annotate_recovered_payload, threaded through setup_durable_delivery.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 09:49:07 +00:00
praisonai-triage-agent[bot]andMervinPraison 69e8c7a26d fix: add event-loop liveness watchdog primitive (fixes #3385)
Add a pure-stdlib, fail-open LoopWatchdog primitive to core
(praisonaiagents.gateway) that runs on a dedicated OS thread, probes the
asyncio loop via call_soon_threadsafe, and after N missed probes dumps
all-thread stacks (faulthandler) and hands the process back to the
supervisor via os._exit(EX_TEMPFAIL). Opt-in and fail-open by design.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 09:48:28 +00:00
praisonai-triage-agent[bot]andMervin Praison 5597cc2a2b fix: route passive observe context to per_chat session key (fixes #3380)
Passive-recorded group messages now land on the same shared per_chat
group key that a subsequent addressed turn reads from, so under
session_scope="per_chat" the bot can actually see the preceding
conversation (Greptile P1 / CodeRabbit Major). record_passive() threads
chat_id/thread_id/account routing and appends directly under a per-key
threading lock instead of the cross-thread mirror bridge, which would
dead-lock when called inline on the inbound handler's own event loop.

Strengthened the observe test to assert routing is threaded and added a
real BotSessionManager per_chat persistence test proving the passive
entry is visible under the group key and does not leak into the sender's
per_user history.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:33:48 +00:00
praisonai-triage-agent[bot]andMervin Praison cb768259f3 fix: raise restart-scan cap + derive channel origin from client_id (#3379)
Address reviewer P1s on the restart-continuation path:
- boot scan requested an explicit large limit so interrupted turns beyond
  the store's 50-session default window are no longer silently skipped
- channel_target now falls back to the persisted client_id when it encodes
  a channel:target origin, so the field is a live consumer of existing
  state rather than dead code for sessions the setter never touched

Adds tests for client_id-derived origin and >50-session scan coverage.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:33:06 +00:00
praisonai-triage-agent[bot]andMervin Praison fa787990e5 fix: preserve live drain timeout on malformed hot-reload edit (#3378)
A malformed gateway.drain_timeout / gateway.reload_drain_timeout in a
hot-reload edit made _coerce_timeout() return None, which was assigned
unconditionally and silently cleared a previously-configured live drain
window. Distinguish malformed (keep live value via _KEEP sentinel) from
explicit disable (None/absent -> None). Update/extend tests accordingly.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:28:41 +00:00
MervinPraison 9817d97c15 docs: auto-update feature parity trackers [skip ci] 2026-07-25 09:24:05 +00:00
praisonai-triage-agent[bot] f4d47052c9 Merge pull request #3373 from MervinPraison/claude/issue-3369-20260725-0719
feat: add trials engine to eval (K isolated attempts, pass-rate + frontier)
2026-07-25 09:23:42 +00:00
praisonai-triage-agent[bot]andMervinPraison 47f8b5e286 fix: re-drive interrupted turns + notify channel on gateway restart (fixes #3379)
On boot, before serving traffic, scan persisted sessions for an in-flight
turn (is_executing / non-empty pending_inbox) lost to a restart. For
channel-originated sessions, deliver an exactly-once "interrupted — resuming"
notice via the existing durable delivery router (idempotency keyed on
(session_id, event_cursor)) and re-drive the turn when the agent is still
registered — independent of any client reconnect.

Reuses the existing durable session store + delivery router rather than
adding new core protocol machinery, keeping the change lightweight and
backward-compatible.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 09:23:40 +00:00
praisonai-triage-agent[bot]andMervinPraison 6a05873c1e fix: apply gateway config hot-reload instead of no-op (fixes #3378)
Add a core HOT_APPLIABLE_KEYS registry + SupportsHotReload protocol in
praisonaiagents/gateway/config.py declaring the closed set of config paths
safe to apply in place. The bot gateway now classifies those paths as HOT in
_build_reload_plan (unknown keys still fall back to a restart plan — fail-safe)
and implements apply_hot_reload to mutate live state (logging level, drain /
reload_drain timeouts) without restarting channels or agents. Applied paths are
already reflected in the existing reload status/health.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 09:22:43 +00:00
praisonai-triage-agent[bot]andMervinPraison a9d11f9e63 fix: add observe group_policy to retain unmentioned messages as context (fixes #3380)
Under the observe policy, group messages that do not mention the bot are
recorded into the session transcript as passive user context (no agent run)
so the bot has memory of the conversation when it is next addressed.

Reuses the existing thread-safe mirror append path via a new
BotSessionManager.record_passive() instead of adding a new core enum /
classifier, keeping the surface area minimal.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 09:22:35 +00:00
praisonai-triage-agent[bot]andMervin Praison 70d6221c72 fix: contain agent name to dir + validate exact written file on --global
- Reject path-separator/traversal agent names (validate_agent_name) so
  writes stay inside .praisonai/agents/ (Greptile Security P1).
- Post-write validation now re-parses the exact file written instead of a
  precedence lookup, and warns when a higher-precedence definition shadows
  the name so the reported `run --agent` step is never misleading (P1).
- Add tests for traversal rejection and global/project shadow warning.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:16:43 +00:00
praisonai-triage-agent[bot]andMervinPraison 329c6fda47 feat: interactive LLM-assisted praisonai agent create (fixes #3376)
Add a `create` command beside `list`/`show` on the agent Typer app that
authors a valid, permission-scoped .praisonai/agents/<name>.md from a one-line
description. Interactive prompts plus a scriptable
--describe/--model/--permission/--global/--yes form. Permission presets reuse
the existing `mode` shorthands (MODE_RULES) so authored agents round-trip
losslessly through CustomDefinitionsDiscovery and inherit the runtime's
permission grammar. System-prompt drafting reuses the plain Agent path proven
by `init --generate`, degrading to an editable stub on any failure.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 09:07:37 +00:00
praisonai-triage-agent[bot]andMervin Praison 0688d12a42 fix: guard None sys.modules aliases; codex output_file sentinel
- _shim.py: skip None placeholders in sys.modules when pre-aliasing the
  moved subtree so an unloaded optional module can't poison the old dotted
  name (import old.sub -> "None in sys.modules"); _AliasFinder still resolves
  it on demand.
- codex_cli.py: use an _UNSET sentinel in _build_command so an explicit
  output_file=None disables the instance default and parses stdout, instead
  of silently falling back to self.output_file (execute_with_schema).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 09:06:50 +00:00
praisonai-triage-agent[bot]andMervin Praison a6e02a50aa fix: restore eager shim registration to preserve module identity; defensive CLI overrides
Restores eager subtree pre-registration in _shim._register_submodules. The
lazy-only variant broke module identity: a combined `from praisonai.mcp_server.cli
import X` imported the parent shim, then resolved `.cli` through _AliasFinder,
whose nested import_module re-entered mid-import under the import lock and
double-loaded the moved file — producing duplicate classes and breaking the
15 mcp/doctor CI tests that patch the shim path.

Also make the forced-format integration helpers (gemini stream/execute_with_stats,
codex stream, cursor stream) pop caller-supplied override keys before threading
the forced value, matching claude_code.py, so callers can't trigger a duplicate-
keyword TypeError (greptile P2).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 08:42:40 +00:00
praisonai-triage-agent[bot] 2cd71ec7fc Merge pull request #3372 from MervinPraison/claude/issue-3370-20260725-0720
feat: trials→SFT export + data from-trials CLI for praisonai-train
2026-07-25 08:37:12 +00:00
praisonai-triage-agent[bot]andMervinPraison 4cb028e20c fix: remove eager shim walk, async AgentOS chat, race-free CLI integrations (fixes #3374)
1. _shim.py: drop the eager pkgutil.walk_packages/import_module pass in
   _register_submodules; _AliasFinder.find_spec already resolves lazily while
   preserving module identity, restoring the shim's laziness guarantee.
2. agentos.py /chat: prefer agent.achat, else offload agent.chat via
   asyncio.to_thread so the sync LLM round-trip no longer blocks the event loop.
3. gemini/codex/cursor CLI integrations: thread per-call output overrides
   through _build_command instead of mutating shared self.* state, eliminating
   the concurrent-call race (matches the existing claude_code.py pattern).

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 08:25:38 +00:00
praisonai-triage-agent[bot]andMervin Praison 976d921637 fix: harden trials engine (isolation, scorer errors, timeout, dup names)
Address 4 P1 review findings in eval/trials.py:
- Isolation: rebind clone.chat_history to a fresh list and give the clone its
  own system-prompt cache so per-attempt state resets never mutate/evict the
  caller's live agent state.
- Scorer safety: a raising EvalCase.verify (and any scorer path) is now
  recorded as a failed TrialScore instead of propagating through gather and
  aborting the whole report.
- Timeout: run attempts on a dedicated ThreadPoolExecutor shut down with
  wait=False so a wedged agent call cannot block run_trials past the timeout;
  documented that a leaked worker thread cannot be force-killed.
- Duplicate case names: merge/extend attempts (with re-numbered indices)
  instead of overwriting, so no attempts are silently discarded.

Add 4 regression tests covering each fix.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 07:34:26 +00:00
praisonai-triage-agent[bot]andMervin Praison 989c788d2f fix: honour --all, keep Alpaca user prompt, respect score threshold
Address three P1 issues in the trials→SFT exporter:
- --all (only_passed=False) now retains unscored attempts instead of
  dropping them in _classify.
- Alpaca conversion no longer drops the user prompt when a system message
  is present; system→instruction, all user turns→input.
- Score-only pass detection compares against the report's pass_threshold/
  threshold/min_score when present, falling back to score>0 only otherwise.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 07:32:55 +00:00
praisonai-triage-agent[bot]andMervin Praison 77cbae75b7 fix: honor read-abort in hierarchical store + scope forced approval per-call
- session/hierarchy.py: mirror base loader contract so a transient OSError on
  an existing file re-raises (instead of swallowing IOError and returning an
  empty session), letting _modify_session_locked abort the write and preserve
  history. Malformed JSON still starts fresh.
- approval/registry.py + agent/tool_execution.py: add per-call `force` to
  approve_sync/approve_async so a PermissionManager `ask` rule gates only the
  current call without mutating shared registry state, fixing the leak where an
  unnamed agent's rule registered globally and gated other agents.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 07:32:00 +00:00
praisonai-triage-agent[bot]andMervinPraison 406e78480b feat: add trials engine to eval (K isolated attempts, unified scorer, pass-rate + frontier) (fixes #3369)
Implements the missing EvalRunnerProtocol as run_trials/arun_trials:
- K independent, isolated attempts per case (fresh copy, session id, severed memory/knowledge writes)
- Unified TrialScore contract: verify callable -> tool assertions -> Judge; unscored (timeout/error) excluded from stats, never coerced to 0
- Trajectory-carrying TrialAttempt records; TrialReport.pass_rates()/frontier()/summary()/save()/load()
- New optional EvalCase.verify field and optional EvalResult.record field (backward compatible)
- Fix prompt_optimizer.py EvalCase shadowing bug (rename local alias to EvalPair)

Core-only, stdlib deps (asyncio, copy, json), lazy-exported.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 07:26:29 +00:00
praisonai-triage-agent[bot]andMervinPraison db65dd401f feat: add trials→SFT export + data from-trials CLI to praisonai-train (fixes #3370)
Bridge verification to data generation: take a serialised trials report
(K scored attempts per case with captured trajectories), keep the passing
attempts via rejection sampling, and write them as a ShareGPT dataset the
existing trainer consumes unchanged. Adds export_trials() + ExportSummary,
provenance sidecar ({path}.meta.json), and a `from-trials` CLI command
beside generate/dedup/validate. Report is duck-typed over JSON (the contract
with the sibling core trials engine) so there's no hard dependency on unlanded
core code. Pure stdlib, additive, confined to the data namespace.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 07:25:01 +00:00
praisonai-triage-agent[bot]andMervinPraison 636e7fe169 fix: async-safe handoff chain, session read-error data safety, per-agent approval scoping (fixes #3368)
Gap 1: replace threading.local() handoff-chain storage with contextvars.ContextVar so concurrent asyncio handoffs no longer share one chain and corrupt each other's cycle/depth checks.

Gap 2: distinguish a transient OS read error from no-file/corrupt-JSON in the session store so a momentary read failure aborts the write (returns False) instead of silently overwriting real history with an empty session.

Gap 3: scope ApprovalRegistry tool-requirement state per agent so a per-agent PermissionManager ask rule no longer leaks an approval gate onto unrelated agents in the same process. Global registration (DEFAULT_DANGEROUS_TOOLS) is unaffected.

Co-authored-by: MervinPraison <[email protected]>
2026-07-25 07:22:43 +00:00
praisonai-triage-agent[bot]andMervin Praison 83672e1bf0 fix(train): reviewer fixes — cached HF login, CPU-only validation, OLLAMA_HOST-aware readiness, clean ollama-create errors
- Accept cached `huggingface-cli login` (get_token) in preflight, not just HF_TOKEN env (Greptile P1)
- Gate the hard CUDA check on train enabled so publish/export-only (train: false) validates on CPU (CodeRabbit Major)
- Resolve Ollama readiness endpoint from OLLAMA_HOST instead of hardcoded 127.0.0.1:11434 (Greptile P1)
- Translate `ollama create` failure into a clean RuntimeError and catch CalledProcessError in main()/export (CodeRabbit)
- Close serve_err TemporaryFile deterministically (CodeRabbit)
- Fix "Free up free space" typo (CodeRabbit)
- Guard non-mapping YAML config and require --model-dir to be a directory in export (CodeRabbit)
- Validate quantization_method in for_export too (CodeRabbit)
- Add tests for cached-login, train:false CPU, OLLAMA_HOST, and ollama-create failure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-25 07:19:57 +00:00
MervinPraisonandClaude Opus 4.8 095b004bfb feat(train): non-developer robustness — clean errors, preflight, export command, Ollama/GGUF/HF failure handling
Make praisonai-train usable by a non-developer: replace raw tracebacks with
clean actionable errors, validate the config up front, and harden the
Ollama/GGUF/HF export paths against the exact failures hit in practice.

trainer.py:
- main() wraps construction + run(); ValueError/RuntimeError print as a single
  "ERROR: <msg>" line and exit 1 (no traceback); KeyboardInterrupt exits cleanly.
- validate_config() preflight (fails fast BEFORE model/GPU load): no-CUDA GPU,
  missing HF_TOKEN when publishing, <10GB free disk, invalid quantization_method.
- check_gpu() guarded so it no longer crashes raw on a CPU-only box.
- Unknown-key warning now collects all keys and suggests the closest known key
  (difflib) in one clear block.
- Silent-behavior NOTES: num_samples head-N-before-shuffle, split_type
  validation/test contamination into training, and the max_steps=2800 default.
- HF push (merged/gguf) translates HfHubHTTPError 401/403 into actionable
  messages; rmtree guarded so a namespaced repo id ("user/model") is never
  treated as a local path to delete.
- Template fixes: warn when no known chat template matches, drop the broken empty
  DeepSeek stop tokens, and never emit an empty PARAMETER stop line.
- for_export() classmethod to build an export-only trainer (no dataset needed).

_ollama.py:
- create_and_push_ollama_model() accepts optional quantization (--quantize),
  disk pre-check on the OLLAMA_MODELS volume, and translates push 401/403 into a
  message pointing at ~/.ollama/id_ed25519.pub + ollama.com/settings/keys.
- ensure_ollama_running() waits 15s, probes GET /api/version, and surfaces serve
  stderr in the timeout message.

cli/commands/train.py:
- New `export <ollama|gguf|hf>` command to publish an already-trained model
  without re-running training.

tests: tests/unit/train/test_robustness.py (14 tests, all deps stubbed).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-25 08:08:28 +01:00
praisonai-triage-agent[bot] 309cb9710f Merge pull request #3362 from MervinPraison/claude/issue-3360-20260724-1633
fix: resolve bundled ui_*/default_app.py against praisonai wrapper
2026-07-24 17:26:56 +00:00
praisonai-triage-agent[bot]andMervinPraison 2bc80d84b7 refactor: extract duplicate MCP to_openai_tool() into shared helper (fixes #3364)
Add build_openai_tool_dict to mcp_schema_utils.py and delegate from the
three transport tool classes (HTTPStreamMCPTool, SSEMCPTool,
WebSocketMCPTool). Output dicts, including the __praisonai_deferrable__
marker, are unchanged.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 17:16:12 +00:00
praisonai-triage-agent[bot]andMervinPraison c17327f61e fix: reuse canonical token heuristic in compaction fallback (fixes #3363)
Replace flat len(text)//4 offline fallback in ContextCompactor.estimate_tokens
with the canonical estimate_tokens_heuristic from context.tokens, mirroring
context/aggregator.py. This removes duplicate logic and fixes under-counting
of non-ASCII (CJK/dense-script) text on the offline path.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 17:15:09 +00:00
praisonai-triage-agent[bot] 9762d11606 Merge pull request #3361 from MervinPraison/claude/issue-3359-20260724-1619
fix: de-duplicate agent_tools.py — collapse wrapper copy to thin re-export
2026-07-24 17:09:54 +00:00
praisonai-triage-agent[bot]andMervin Praison 4886d4c8d3 refactor: route bundled UI preset resolution through _wrapper_bridge
Move wrapper-package discovery out of the Tier 2 ui.py CLI into the lazy
_wrapper_bridge via a new wrapper_package_path() helper, per ARCHITECTURE.md
§2 cross-tier boundary. Preserves preset resolution and the None fallback
(install hint) when the wrapper is absent.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 16:42:03 +00:00
praisonai-triage-agent[bot]andMervinPraison 8f84de4dcc fix: resolve bundled ui_*/default_app.py against praisonai wrapper (fixes #3360)
The UI loader was extracted to praisonai_code but resolved the bundled
default_app.py path via __file__-relative arithmetic anchored in
praisonai_code, which has no ui_* directories. The five bundled UI presets
ship in the praisonai wrapper package. Resolve the path against the installed
wrapper via importlib.util.find_spec("praisonai"), falling back to a clear
'pip install "praisonai[ui]"' hint when the wrapper is absent.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 16:35:17 +00:00
praisonai-triage-agent[bot] 1cd6fa77b2 Merge pull request #3358 from MervinPraison/claude/issue-3061-20260724-1502
fix: repo-linked worktree auto-upgrade + lossless-only cleanup (#3061)
2026-07-24 16:30:44 +00:00
praisonai-triage-agent[bot]andMervin Praison b85f4f60b4 fix: make _run_sync timeout return promptly instead of blocking on hung worker
The executor context manager called shutdown(wait=True) on __exit__, which
re-blocked on a coroutine still hung past PRAISONAI_RUN_SYNC_TIMEOUT — defeating
the timeout (Greptile P1). Manage the pool explicitly and shutdown(wait=False)
in finally so a timed-out tool call returns immediately.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 16:29:53 +00:00
praisonai-triage-agent[bot]andMervinPraison 43cd377629 fix: de-duplicate agent_tools.py; collapse wrapper copy to thin re-export (fixes #3359)
The wrapper copy of agent_tools.py had drifted from the canonical
praisonai_code copy (missing the ACP cwd forwarding fix), and the two
resolved via different import spellings. Collapse the wrapper copy to a
thin re-export of the canonical praisonai_code implementation so both
import styles resolve to a single owner.

Reconcile the canonical module-local _run_sync bridge to keep the union
of both historical guarantees: running-loop safety (offload to a worker
thread) AND a timeout, without adding a wrapper dependency (C7 gate).

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 16:22:07 +00:00
praisonai-triage-agent[bot] 008656c524 Merge pull request #3356 from MervinPraison/claude/issue-3354-20260724-1418
fix: root code tools to --workspace and resume into session directory
2026-07-24 15:29:59 +00:00
praisonai-triage-agent[bot]andMervin Praison 1dec99f97c fix: surface failed worktree removal + preserve repo linkage in metadata
Address Greptile P1 review findings on PR #3358:

- _remove_worktree now returns a reason string when `git worktree remove`
  fails (nonzero exit or exception) instead of silently returning None.
  The caller keeps the tracking entry and records a preservation comment,
  preventing orphaned worktrees/branches with dropped tracking.

- create_task persists the resolved top-level repo_path into task metadata
  so the repo linkage that drove the worktree auto-upgrade is retained
  between create and dispatch (an explicit metadata.repo_path still wins).

Adds tests for failed/exception removal tracking and repo_path persistence.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 15:15:36 +00:00
praisonai-triage-agent[bot]andMervin Praison 491a6d9409 fix: repo-linked worktree auto-upgrade + lossless-only cleanup (fixes #3061)
Refinement 1: repo-linked tasks auto-upgrade workspace_kind to "worktree" at
create_task time (linkage-based, not content-inspecting). Explicit
workspace_kind and auto_worktree=false are respected. Derived branch
kanban/<task_id> is persisted for the dispatcher to consume.

Refinement 2: _remove_worktree is lossless by default — refuse to delete a
worktree that is dirty or has commits not in base; preserve it and record a
worktree_preserved comment. Removal with outstanding work is an explicit
force operation only.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 15:07:44 +00:00
praisonai-triage-agent[bot]andMervin Praison 97678251f6 fix: resolve resume session once and pin cwd fallback over legacy workspace var
Addresses two P1 review issues on the workspace-binding change:
- Resolve the UnifiedSession once (before workspace binding + tool load) and
  pass it into _bind_resume_workspace, eliminating a second independent
  last-session lookup that could race a concurrent CLI process and bind tools
  to a different directory than the loaded conversation.
- When a resumed session's saved workspace no longer exists, pin
  PRAISONAI_WORKSPACE to cwd instead of leaving it unset, so a stray legacy
  PRAISON_WORKSPACE cannot leak through the tool loader and contradict the
  "using current directory" warning.

Adds regressions for cwd-pinning over the legacy var and for
provided-session-without-relookup; updates the existing fallback test.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 14:32:56 +00:00
praisonai-triage-agent[bot]andMervinPraison 285894d1a4 fix: root /undo at the bot workspace, not process cwd (fixes #3355)
Bot/gateway file tools resolve against a per-session Workspace attached to
the agent after construction, but the FileSnapshot backing Agent.undo was
created rooted at os.getcwd() — so /undo tracked the wrong directory.

Add Agent.set_snapshot_root() (core, parameter-only) and call it from the
bot smart-defaults after attaching the workspace so change tracking follows
the tools. Deliberately minimal: the per-turn workspace swap (bug 3) and
policy worktrees (blocked on #3354's WorktreeService) are out of scope here.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 14:27:07 +00:00
praisonai-triage-agent[bot]andMervinPraison 903f9de695 fix: root code tools to --workspace and resume into session directory (fixes #3354)
The `praisonai code --workspace` flag was dead: it wrote PRAISONAI_WORKSPACE
but ToolConfig.from_env read PRAISON_WORKSPACE, and _load_interactive_tools
unconditionally overrode config.workspace with os.getcwd(). Fix the env-name
mismatch (honour both, prefer canonical PRAISONAI_) and resolve the workspace
as PRAISONAI_WORKSPACE -> PRAISON_WORKSPACE -> cwd instead of hardcoding cwd.

Also bind resumed sessions to their directory: --continue/--session now reads
back the persisted UnifiedSession.workspace and roots the tools there, warning
and falling back to cwd when that directory is gone.

Scope kept minimal per AGENTS.md: no new WorktreeService — worktree isolation
already exists via core GitWorktreeAdapter (wired into `praisonai run`), so a
parallel wrapper service would duplicate it.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 14:25:09 +00:00
praisonai-triage-agent[bot] 33c725ae78 Merge pull request #3351 from MervinPraison/claude/issue-3349-20260724-0914
fix: gateway restart replays persisted CLI-only start flags
2026-07-24 10:39:12 +00:00
praisonai-triage-agent[bot]andMervin Praison 819450ec07 test(gateway): assert deep=False in status call after adding --deep flag
The gateway status command now passes the additive deep flag to
handler.status(); update the assertion to match the new backward-
compatible default.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 10:36:06 +00:00
praisonai-triage-agent[bot]andMervin Praison f805090499 fix(gateway): stop leaking bearer token over plaintext HTTP, honour hook redaction, avoid first-run inbound false-fail
- Only attach GATEWAY_AUTH_TOKEN over loopback or HTTPS; never over remote
  plaintext HTTP in preflight probes and version-skew check
- Slack @mention: use hook-returned content verbatim so an intentionally
  emptied/redacted message is not silently restored to raw event text
- Inbound metrics: track whether a baseline pre-existed so the first check
  against pre-existing traffic reports "baseline established" instead of a
  false "no inbound"

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 10:36:06 +00:00
MervinPraison e9a20f0686 feat(gateway): add tiered diagnostics for runtime, inbound, and duplicates
Extend gateway test/status with --check-runtime, --check-inbound, and
--check-duplicates; add sessions list/show, enriched /health, metrics
delta, doctor deep checks, and Slack @mention liveness fixes so operators
can prove live delivery and detect competing gateways.
2026-07-24 10:36:06 +00:00
praisonai-triage-agent[bot] a8cbae8554 Merge pull request #3350 from MervinPraison/claude/issue-3348-20260724-0914
fix: make runtime channel credential/auth failure a first-class self-healing state
2026-07-24 10:32:56 +00:00
praisonai-triage-agent[bot] a785c986f8 Merge pull request #3347 from MervinPraison/claude/issue-3345-20260724-0856
feat: praisonai init --generate for repo-tailored AGENTS.md
2026-07-24 10:23:15 +00:00
praisonai-triage-agent[bot] 86bf38e4f3 Merge pull request #3346 from MervinPraison/claude/issue-3344-20260724-0855
fix: exit non-zero on praisonai run agent failure
2026-07-24 10:08:52 +00:00
praisonai-triage-agent[bot] 7b5bfb607f Merge pull request #3341 from MervinPraison/claude/issue-3340-20260724-0820
fix: bypassed AsyncBridge, dropped LiteLLM error, **kwargs adapter rejection (#3340)
2026-07-24 10:00:34 +00:00
praisonai-triage-agent[bot]andMervin Praison 932454d51e fix: re-source credential on wake from CREDENTIAL_UNAVAILABLE (#3348)
Addresses the Greptile finding that reconnect() restarts the same bot
instance still holding the rejected token. On wake from the parked
credential state the supervisor now opportunistically calls an optional,
duck-typed refresh_credentials() hook so an out-of-band credential repair
(e.g. a rotated env var) driving a bare reconnect() self-heals without a
full restart. No-op for bots without the hook (env-var tokens are already
re-resolved by start()/hot-reload). Best-effort: a failing hook cannot
wedge supervision.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 09:27:00 +00:00
praisonai-triage-agent[bot]andMervin Praison 390ebb1824 fix: guard start-flag persistence and preserve drain window on restart (#3349)
Address two P1 review findings on the gateway restart-replay change:

- Only persist the start-flags artefact AFTER startup validation passes
  (import/config/agent-file), just before the gateway binds, so a failed or
  rejected start on the same host:port no longer clobbers the running
  gateway's saved posture.
- restart --drain-timeout now defaults to None; an omitted flag replays the
  persisted drain window (and falls back to 10s only when none is persisted)
  instead of silently forcing a fixed 10s and shortening production drains.
  An explicit value still wins for both the OLD-process drain and the relaunch.

Adds 3 regression tests covering omitted/explicit drain replay and the
no-persisted-value fallback.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 09:26:22 +00:00
praisonai-triage-agent[bot]andMervinPraison 6cbef83311 fix: gateway restart replays persisted CLI-only start flags (fixes #3349)
Direct (non-service) `gateway restart` silently dropped the runtime flags
the process was started with (--openai-api, --reliability,
--max-concurrent-runs, ...), reverting production settings to defaults.

`start` now persists the non-None runtime flags to
~/.praisonai/gateway.start.<host>.<port>.json (keyed by bind host:port,
matching the PID lock), and `restart` loads and replays them so the
relaunch faithfully reproduces the running gateway. Explicit restart flags
(config / agents / drain-timeout) still win over persisted values.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 09:19:36 +00:00
praisonai-triage-agent[bot]andMervinPraison 4c50bc93e7 fix: make runtime channel credential/auth failure a first-class self-healing state (fixes #3348)
Classify runtime 401/403 (and platform text equivalents like invalid_auth/
token_revoked) as a distinct CREDENTIAL_UNAVAILABLE outcome instead of a
generic FAILED. On a runtime credential rejection the supervisor now parks in a
named, redacted degraded state (reusing the boot-time "credential unavailable"
surface from #3159 in health()), stops hammering the invalid token, and
auto-recovers on reconnect/hot-reload without a full process restart.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 09:18:57 +00:00
praisonai-triage-agent[bot]andMervin Praison b23b189b84 fix: use agent.run() and always target repo root for --generate
Address two P1 review findings on praisonai init --generate:

- Streaming stringified: _generate_agents_md used agent.start(), which
  auto-enables streaming in a TTY and returns a generator whose repr was
  written to AGENTS.md. Switch to agent.run() (always silent, returns str).
- Global mode wrote ~/AGENTS.md: with --global, base.parent is $HOME so the
  agent scanned home and wrote home-tailored rules outside the repo. Resolve
  the AGENTS.md target from git root / cwd independently of --global.

Add tests: --global still writes AGENTS.md to the repo root (not home), and
_generate_agents_md calls run() (not start()) returning the string body.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 09:08:38 +00:00
praisonai-triage-agent[bot]andMervin Praison 7138d078c1 fix: propagate run failures through YAML, warm-runtime, and profiled paths
Addresses the two Greptile P1 findings on #3346 so the non-zero-on-failure
contract holds across every reachable run path:

- _run_from_file: add `except typer.Exit: raise` so the deliberate failure
  exit is not recaught by the broad handler (fixes duplicate reporting).
- _try_attach_runtime: classify the warm-runtime result and report failure so
  an empty result exits non-zero instead of silently succeeding.
- _run_prompt_profiled / _run_from_file_profiled: apply the same failure
  contract after the profiling report so profiled runs honour it too.

Adds a regression test for the warm-runtime attach path.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 09:08:22 +00:00
praisonai-triage-agent[bot]andMervin Praison 598536413c feat: add praisonai init --generate for repo-tailored AGENTS.md (fixes #3345)
Adds an opt-in `--generate` flag to `praisonai init` that runs a short,
read-only analysis agent (reusing the existing Agent runtime) to produce a
concise, repository-tailored AGENTS.md at the repo root. Feeds the agent a
cheap pre-scan (top-level tree, detected manifests, README head) to bound cost.

Non-destructive: respects --force, never overwrites an existing AGENTS.md, and
degrades gracefully to the static scaffold when no provider credential is
present or generation fails. The output lands where rules_manager already
discovers it on the next run.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 09:01:07 +00:00
praisonai-triage-agent[bot]andMervin Praison 29f56baf02 fix: exit non-zero on praisonai run agent failure (fixes #3344)
praisonai run reported success and exited 0 regardless of whether the
agent produced a result. Wire the existing run result (None/empty ==
failure) through the CLI: emit ok=<success> to the event bridge, a
machine-readable {"status": "failed"} object under --output json, an
actionable remediation, and raise typer.Exit(1) on failure — mirroring
the existing arg-error exit convention. Successful runs are unchanged.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 08:59:10 +00:00
Dhivya-Bharathy 1cfb2bc26f fix: resolve 4 remaining E2E example failures after batch-3 merge 2026-07-24 14:25:40 +05:30
praisonai-triage-agent[bot]andMervin Praison 31f5eb4ab0 fix: propagate caller context into sync-completion runner threads
The running-loop fallback in _structured_completion/_run_coro_sync spawned a
bare threading.Thread, which does not inherit contextvars. run_sync() inside it
therefore resolved via _default_bridge() -> empty _bridge_var -> shared _BG,
bypassing an active scoped_bridge() and leaking the fallback onto the global
loop. Run the worker under contextvars.copy_context() so both paths resolve the
same AsyncBridge (scoped override, else shared default), preserving per-session
loop isolation.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 08:36:32 +00:00
praisonai-triage-agent[bot]andMervinPraison 255ba87618 fix: route sync bridge through shared AsyncBridge, chain LiteLLM error, accept **kwargs adapters (fixes #3340)
- auto.py: runner threads in _structured_completion and _run_coro_sync now
  dispatch to the shared AsyncBridge via run_sync() instead of asyncio.run(),
  reusing one process-wide loop/thread and per-loop connection pools.
- auto.py: _completion_impl preserves the original LiteLLM exception and
  chains it into the OpenAI fallback failure (raise ... from) so users see
  both provider tracebacks instead of only the masking OpenAI one.
- registry.py: _validate_adapter treats a **kwargs catch-all as satisfying
  the protocol keywords and also validates arun, unblocking third-party
  entry-point adapters that forward **kwargs.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 08:28:22 +00:00
MervinPraison e6c29a7835 docs: auto-update documentation parity trackers [skip ci] 2026-07-24 08:11:53 +00:00
praisonai-triage-agent[bot] cb9bb2b15b Merge pull request #3339 from MervinPraison/claude/issue-3337-20260724-0717
fix: agent isolation and sync/async consistency in core SDK
2026-07-24 08:11:21 +00:00
MervinPraison 7daa992605 docs: auto-update feature parity trackers [skip ci] 2026-07-24 07:31:57 +00:00
Mervin Praison 47b881b1e8 Merge pull request #3338 from MervinPraison/feat/gateway-readiness-cli
Gateway readiness CLI: shell fixes, preflight helpers, doctor checks, gateway test
2026-07-24 08:31:31 +01:00
praisonai-triage-agent[bot]andMervin Praison 4509c43d26 fix: keep gateway doctor/test --json output parseable on turn failures
Embed turn prerequisite errors into the JSON payload instead of printing a
trailing plain-text line, so --json consumers get a single valid document.
Also drop dead critical-tool branch in is_already_approved.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-24 07:25:38 +00:00
praisonai-triage-agent[bot]andMervinPraison 326693c15e fix: agent isolation and sync/async consistency in core SDK (fixes #3337)
1. Circuit breakers: register weakref.finalize at breaker creation so the
   process-global registry entry is removed when the Agent is GC'd, closing
   the CPython id-reuse window where a new agent could inherit a stale OPEN
   breaker. No longer relies on close()/aclose() being called. Uses a
   staticmethod callback so the finalizer does not keep the agent alive.

2. Global tool-registry fallback: gate the @tool registry lookup in
   execute_tool() behind ToolConfig(allow_global_tools=True) (default False).
   By default an agent is scoped strictly to its declared tools=[...] and
   cannot execute an @tool-decorated callable it was never given. Plugin-host
   style dynamic dispatch can opt in via tool_config.

3. Sync run_task(): re-raise on fail_on_callback_error / fail_on_memory_error,
   mirroring arun_task() so the documented fail-fast flags behave identically
   on the sync and async surfaces.

Co-authored-by: MervinPraison <[email protected]>
2026-07-24 07:25:36 +00:00
MervinPraison a1eea0052b Add gateway readiness CLI: preflight helpers, doctor checks, and gateway test.
Extract shared probe/shell/turn logic to praisonai_bot.gateway.preflight,
add praisonai gateway test orchestrator, doctor bots shell/probe checks,
fix doctor --json single-document output, and per-channel turn probe gate.
2026-07-24 08:17:30 +01:00
MervinPraison 812b2aebde Fix gateway shell approval and Slack @mention routing.
Critical tools honour mark_approved via the approval registry, shell enable
syncs AutoApproveBackend to the registry, @mentions run routing handlers,
and gateway doctor gains an offline --turn probe for inbound simulation.
2026-07-24 08:13:37 +01:00
Mervin Praison cb7f4821d9 Merge pull request #3335 from MervinPraison/feat/slack-allow-shell
feat(bot): opt-in shell execution for inbound Slack channels
2026-07-23 17:03:39 +01:00
praisonai-triage-agent[bot]andMervin Praison 4fa0711282 fix(bot): apply shell setup to routed agents and fail-closed manual approval
Addresses two Greptile P1 findings on the allow_shell opt-in:

1. Routed agents lose shell tools: _inject_routing_handler swapped in a raw
   agent from self._agents, stripping execute_command applied to the default
   channel clone. Re-apply enable_shell_tools to the routed agent (cloned once
   per channel+agent so non-shell channels never gain the shell tool).

2. Manual approval retained auto-approval (security): with auto_approve_shell
   false and no Slack approval channel, a pre-existing AutoApproveBackend was
   left installed, silently auto-approving shell. Now fail-closed with a
   deny-by-default backend that rejects shell commands.

Adds tests for both fail-closed approval paths.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 15:32:52 +00:00
Mervin Praison b9e16dc0da Merge pull request #3336 from MervinPraison/feat/shell-approval-all-channels
feat(bot): allow_shell with multi-channel approval wiring
2026-07-23 16:27:24 +01:00
MervinPraison 3bba1e6fd8 docs: auto-update documentation parity trackers [skip ci] 2026-07-23 15:26:23 +00:00
praisonai-triage-agent[bot] 56326b779f Merge pull request #3325 from MervinPraison/claude/issue-3311-20260723-1026
fix: surface retry/backoff status in the CLI
2026-07-23 15:25:50 +00:00
praisonai-triage-agent[bot]andMervin Praison e07424179b fix(bot): guard webhook approval url and validate approval_mode
- Fix missing approval_webhook_url becoming the literal string "None"
  which bypassed WebhookApproval's ValueError guard; now falls through
  to platform/gateway approval instead of building a broken backend
- Add fail-closed approval_mode validator (channel|gateway|http|webhook)
  so config typos are rejected at load time, matching other enum fields
- Add regression tests for webhook-mode with and without a URL

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 15:19:49 +00:00
MervinPraison 7742cf8b5f feat(bot): wire shell approvals for Telegram, Discord, and gateway
Extend allow_shell to route human-in-the-loop approvals through platform
backends (Slack/Telegram/Discord) plus gateway, HTTP, and webhook modes,
with gateway fallback for channels without native wiring.
2026-07-23 16:11:42 +01:00
MervinPraison 01bd8e1bb9 feat(bot): opt-in shell execution for inbound Slack channels
Add gateway allow_shell channel config to inject execute_command, lift permission deny, and wire auto-approve or SlackApproval.
2026-07-23 16:04:40 +01:00
Mervin Praison 686b422c00 Merge pull request #3334 from MervinPraison/feat/cli-backend-debug
feat(agents): add CLI backend debug logging
2026-07-23 16:02:52 +01:00
praisonai-triage-agent[bot]andMervin Praison 4f576a65a9 fix(cli_backend): redact prompt argv and emit hook on failure
Address reviewer feedback on the CLI_BACKEND_EXECUTE hook path:

- Security: redact prompt/system argv values (redact_command) at the
  payload serialization boundary and in the plugin bridge, so prompts and
  system instructions do not leak into downstream log sinks. The live
  in-memory command field is preserved for programmatic consumers.
- Observability: emit the hook on failure too (extracted
  _emit_cli_backend_hook helper) so subprocess startup errors and timeouts
  remain traceable via error=<message>, instead of only on success.
- Tests: cover redaction (serialization + plugin bridge) and failure-path
  hook emission.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 14:57:14 +00:00
MervinPraison 5d6a378847 docs: auto-update documentation parity trackers [skip ci] 2026-07-23 14:54:02 +00:00
Mervin Praison afa1f309df Merge pull request #3331 from Dhivya-Bharathy/fix/e2e-examples-batch3
fix: batch-3 E2E — skip non-runnable examples and fix remaining runner/example bugs
2026-07-23 15:53:19 +01:00
Mervin Praison d3457c62b7 Merge pull request #3333 from MervinPraison/feat/codex-grok-cli-backends
feat(code): add codex-cli and grok-cli agent backends
2026-07-23 15:51:45 +01:00
MervinPraison e2fe855a0a refactor(agents): emit CLI backend hook instead of inline logging
Replace agent.py debug logging with CLI_BACKEND_EXECUTE hook payload.
Logging moves to praisonai-plugins cli_backend_tracer entry point.
2026-07-23 15:51:36 +01:00
praisonai-triage-agent[bot] e2a9d9917f Merge pull request #3324 from MervinPraison/claude/issue-3308-20260723-1026
fix: harden praisonai serve agents (auth, caching, converged routes)
2026-07-23 14:49:20 +00:00
MervinPraison b78dbf907c feat(agents): add CLI backend debug logging
Log subprocess command and confirm PraisonAI skips LLM HTTP when cli_backend delegates a turn.
Enable with PRAISONAI_CLI_BACKEND_DEBUG=1 or LOGLEVEL=DEBUG.
2026-07-23 15:46:24 +01:00
praisonai-triage-agent[bot]andMervin Praison 4cbfb0d848 fix(code): gate gemini session resume on is_resume
Gemini backend forwarded --resume on every turn including the first,
which would fail resuming a non-existent session. Gate on
CliSessionBinding.is_resume for parity with codex/grok/claude.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 14:45:40 +00:00
praisonai-triage-agent[bot]andMervin Praison 22fb06595d fix(code): forward session id on codex/grok resume turns
Codex backend never forwarded the session id to `codex exec`, so
multi-turn conversations lost context (Greptile P1). Now forwards
`resume <session_id>` on resume turns. Gate both codex and grok
session forwarding on CliSessionBinding.is_resume so the first turn
does not attempt to resume a non-existent session.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 14:45:08 +00:00
MervinPraison 83dc068a08 feat(code): add gemini-cli agent backend
Delegate Agent turns to  headless mode alongside codex-cli and grok-cli.
2026-07-23 15:42:33 +01:00
Mervin Praison 8fb796e1e3 Merge pull request #3332 from MervinPraison/fix/claude-subscription-oauth-readonly
fix(agents): stop claude-code OAuth refresh invalidating shared sessions
2026-07-23 15:41:43 +01:00
MervinPraison 2bf11482d5 docs: auto-update documentation parity trackers [skip ci] 2026-07-23 14:39:58 +00:00
praisonai-triage-agent[bot] 9adeb8829a Merge pull request #3323 from MervinPraison/claude/issue-3309-20260723-1025
fix: self-repair and actionable feedback on unknown tool calls
2026-07-23 14:39:20 +00:00
MervinPraison 228c984d53 feat(code): add codex-cli and grok-cli agent backends
Enable Agent(cli_backend=...) delegation to OpenAI Codex and xAI Grok CLIs so subscription logins work without direct API auth.
2026-07-23 15:36:58 +01:00
praisonai-triage-agent[bot]andMervin Praison 7b8ec88f03 fix(tests): harden claude-code auth tests for shared-session read-only policy
- Isolate ANTHROPIC_TOKEN/CLAUDE_CODE_OAUTH_TOKEN env in the expiring-token
  test so the Keychain read-only path is deterministically exercised (was
  leaking a real CI OAuth token and returning the wrong access token).
- Assert both anthropic-beta policy changes: fine-grained-tool-streaming is
  present and the unsupported context-1m long-context beta stays absent
  (per CodeRabbit review).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 14:29:33 +00:00
MervinPraison 989e1cc872 fix(agents): stop claude-code OAuth refresh from invalidating shared sessions
PraisonAI read Keychain OAuth tokens but refreshed without persisting back,
rotating refresh tokens and breaking Claude CLI and other tools on the same
machine. Use read-only credential resolution, skip LLM auth refresh for
claude-code, fix invalid_request_error misclassification, and drop the
context-1m beta header unsupported on many subscriptions.
2026-07-23 15:13:52 +01:00
praisonai-triage-agent[bot] 5aa5943ed5 Merge pull request #3322 from MervinPraison/claude/issue-3312-20260723-1021
fix: round-trip long interactive select/reply values via durable callback store
2026-07-23 12:07:44 +00:00
MervinPraison 2b99bacd61 docs: auto-update documentation parity trackers [skip ci] 2026-07-23 12:01:50 +00:00
praisonai-triage-agent[bot] d14f6911c1 Merge pull request #3321 from MervinPraison/claude/issue-3313-20260723-1025
fix: neutralise untrusted platform metadata in prompt attribution
2026-07-23 12:01:17 +00:00
praisonai-triage-agent[bot]andMervin Praison 1aff8c7d66 fix: dispatch async retry stream events to async-only callbacks
The async retry loop emitted RETRY events via the sync emit() path, so
consumers registered through the public add_async_callback() API passed
has_callbacks but never received the event. Add an async-aware
_aemit_retry_stream_event helper (using emit_async) and share event
construction via _build_retry_stream_event. Adds tests for the async-only
callback path and the no-callback no-op case.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:58:34 +00:00
praisonai-triage-agent[bot]andMervin Praison e5e962b9bb fix: surface retry/backoff status in the CLI (fixes #3311)
Add StreamEventType.RETRY emitted alongside the existing ON_RETRY hook (guarded by has_callbacks for zero-overhead) in both sync and async retry loops, carrying attempt/max_attempts/delay/reason in metadata. Map it to a canonical run.retry NDJSON event in the CLI stream-json bridge so consumers get a live 'retrying in Ns (attempt k/N)' signal. Non-JSON/silent modes stay silent.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:57:38 +00:00
praisonai-triage-agent[bot]andMervin Praison f64c67a854 fix: only echo tool parameter hint on genuine bind failures
A TypeError/ValueError raised inside a successfully-bound tool (domain
validation) no longer receives a misleading required/optional parameter
hint. The hint is now gated on inspect.signature().bind() confirming the
failure is an argument-binding error, so runtime errors surface their
real message and the model fixes the value, not the parameter names.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:56:09 +00:00
praisonai-triage-agent[bot]andMervinPraison 70765e9761 fix: self-repair and actionable feedback on unknown tool calls (fixes #3309)
Adds a zero-overhead resilience layer to the core agent tool-dispatch path.
When a tool call cannot be resolved, the runtime now:
1. Self-repairs case/separator drift (e.g. WebSearch/web-search -> web_search)
   against the agent's active tools and executes if a unique match exists.
2. Otherwise returns a model-readable error naming the nearest valid tool
   (fuzzy) and listing the available tools so the model can self-correct.
3. On an argument-binding failure, echoes the tool's required/optional params.

No new public API or Agent params; stays on the existing dispatch path.

Co-authored-by: MervinPraison <[email protected]>
2026-07-23 11:54:56 +00:00
MervinPraison 17a19af2c4 docs: auto-update feature parity trackers [skip ci] 2026-07-23 11:53:40 +00:00
praisonai-triage-agent[bot] b5abfeebe0 Merge pull request #3317 from MervinPraison/claude/issue-3311-20260723-1021
fix: surface retry/backoff status in the CLI so rate-limit waits aren't mistaken for a hang
2026-07-23 11:53:12 +00:00
MervinPraison 6935d99c28 docs: auto-update documentation parity trackers [skip ci] 2026-07-23 11:49:58 +00:00
praisonai-triage-agent[bot]andMervin Praison b829946696 fix: harden praisonai serve agents — auth default, cached generator, converged routes (fixes #3308)
- Security: refuse non-localhost bind without --api-key/PRAISONAI_SERVE_API_KEY,
  mirroring jobs/server.py; enforce the resolved key unconditionally.
- Performance: cache one AgentsGenerator per app via FastAPI lifespan (built at
  startup, closed on shutdown) instead of rebuilding YAML parse + framework
  resolution + a 32-worker pool per request; falls back to praisonai.arun if
  caching fails.
- Correctness: /agents and /agents/{name} now run the same cached generator, so
  identical YAML gets identical lowering (ToolResolver, tool_timeout, approval,
  guardrails, retry). Removed the hand-rolled PraisonAgent registration that
  silently dropped those safety fields.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:49:30 +00:00
praisonai-triage-agent[bot] 2ccfcc41ea Merge pull request #3316 from MervinPraison/claude/issue-3309-20260723-1021
fix: self-repair and actionable feedback on unknown tool calls
2026-07-23 11:49:27 +00:00
praisonai-triage-agent[bot] 0f912b27fc Merge pull request #3318 from MervinPraison/claude/issue-3308-20260723-1021
fix: harden praisonai serve agents (auth, generator caching, route convergence)
2026-07-23 11:46:06 +00:00
praisonai-triage-agent[bot]andMervin Praison 614bd2946f chore: remove committed example run artifacts and ignore them
Remove 13 knowledge.db binaries plus managed_ids.json, blog_post.md,
tutorial.md, token_metrics_export.json, market_research_results.json that
were accidentally committed (PR notes explicitly say not to commit local
artifacts). Add .gitignore rules to prevent recurrence.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:38:54 +00:00
Dhivya-Bharathy 2895163e81 fix: batch-3 E2E — skip optional-deps failures and fix remaining example bugs 2026-07-23 17:04:42 +05:30
praisonai-triage-agent[bot]andMervin Praison 45218a4bf3 fix(security): collapse Unicode line separators + harden attribution fallback (#3313)
Address reviewer findings on PR #3321:
- Core neutralize_untrusted_text now also collapses U+2028/U+2029/U+0085,
  which render as line breaks but bypassed the ASCII control filter.
- Bot _attribute() fallback (core helper unavailable / version skew) now
  mirrors the sanitiser: collapses all newline-like separators, strips
  control chars, and bounds length.
- Added tests for Unicode separators (core + bot) and the fallback path.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:22:38 +00:00
praisonai-triage-agent[bot]andMervin Praison 40a0748155 fix: neutralise untrusted platform metadata in prompt attribution (fixes #3313)
Add a core, pure-stdlib helper neutralize_untrusted_text() in
praisonaiagents.session.context and apply it by default to the
third-party-controlled sender display name before it is interpolated into
the [{sender}] attribution prefix. Newlines/CR are collapsed, control chars
stripped and length is bounded, so a hostile name can no longer masquerade
as a fake system directive the model re-reads every turn. Well-behaved names
render byte-identically. On by default, no new config knobs.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 11:21:29 +00:00
MervinPraison dd4cfc34c8 docs: auto-update documentation parity trackers [skip ci] 2026-07-23 11:17:03 +00:00
praisonai-triage-agent[bot] fc2ddbf085 Merge pull request #3315 from MervinPraison/claude/issue-3313-20260723-1021
fix: neutralise untrusted platform metadata in prompt attribution
2026-07-23 11:16:29 +00:00
praisonai-triage-agent[bot] 19e8a96ed3 Merge pull request #3314 from MervinPraison/claude/issue-3310-20260723-1021
fix: route bare prompts through the modern Typer run engine
2026-07-23 11:10:38 +00:00
praisonai-triage-agent[bot]andMervin Praison eacd9df36f fix(skills): query MCP server registry live instead of caching stale snapshot
Addresses greptile P1: CapabilityValidator cached the first _get_available_servers()
snapshot, so a skill validated before its MCP server registered via with_tool_prefix()
stayed permanently UNAVAILABLE under STRICT even after the server connected. The MCP
registry read is a cheap set copy, so query it live and drop the dead _server_cache
field (issue #3307).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:45:56 +00:00
praisonai-triage-agent[bot]andMervin Praison 6285d02f8e fix: wire callback payload store through Telegram render + registry (#3312)
The durable-reference encoding for long interactive reply/select values only
took effect when a shared store was explicitly passed in tests; every
production renderer/registry used the no-store default and fell back to the
unrecoverable hash. This shares one InMemoryCallbackPayloadStore between the
Telegram render side (render_presentation -> adapt_presentation) and the inbound
registry so long values round-trip losslessly past the 64-byte callback cap.

- create_registry(store=): thread an optional store into the InteractiveRegistry
- TelegramPresentationRenderer.render(callback_store=): pass store to adapt
- TelegramBot: construct one shared store, inject into registry + render
- add regression test asserting production render+dispatch round-trip

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:44:29 +00:00
praisonai-triage-agent[bot]andMervin Praison 4c2560547e fix(serve): restore named-agent selection + decouple per-request generator
- POST /agents/{agent_name} now dispatches to the requested registered agent
  and returns 404 for an unknown name, instead of silently running the whole
  YAML workflow (fixes named-agent regression flagged in review).
- Both routes build a lightweight per-request AgentsGenerator that borrows the
  cached generator's shared adapter, tool-timeout pool and resolver while owning
  its own cli_config, so concurrent requests overlap without a run-length lock.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:42:16 +00:00
praisonai-triage-agent[bot]andMervin Praison d69067f60e fix: parameter hints reach model + MCP tools participate in repair/inventory
Addresses two P1 review findings on the tool self-repair path:
- Fold the bind-failure parameter schema into the error string so it survives
  conversion to ToolExecutionError (which keeps only the message) and reaches
  the model.
- Expand MCP instances into their contained tools via a shared
  _iter_active_named_tools() helper so MCP tool names participate in
  case/separator repair and appear in the corrective inventory instead of an
  empty/opaque container.

Adds 3 tests (public-path param hint, MCP inventory, MCP name repair).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:32:47 +00:00
praisonai-triage-agent[bot]andMervin Praison fe66d6935c fix: harden fallback + small-bounds in metadata neutralisation (PR #3315)
Address reviewer feedback on the prompt-injection defence:

- Greptile P1 (security): the bot's _attribute() fallback (taken when the
  core helper import fails on an older praisonaiagents still allowed by the
  >=1.6.152 range) only replaced CR/LF, leaking control chars and oversized
  display names into every shared-chat prompt. It now mirrors the core
  helper: collapse newlines, strip control chars, collapse whitespace and
  length-bound to 240 — byte-identical to neutralize_untrusted_text.
- Greptile P2: neutralize_untrusted_text with max_chars<=3 returned the
  3-char "..." string, exceeding the advertised bound. Small bounds now
  truncate hard so len(out) <= max_chars always holds.
- Tests: add small-bounds regression (core) and a fallback-path hostile-name
  regression that forces the helper import to fail (bot).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:30:48 +00:00
praisonai-triage-agent[bot]andMervin Praison 377b06c1f4 fix: join multi-token bare prompts into single run argument
An unquoted bare prompt (praisonai build a weather agent) arrives as
multiple argv tokens, but the modern `run` command takes a single
positional target. Join the flag-free tokens into one argument so the
whole prompt reaches `run` intact instead of Typer rejecting the extra
positionals. Addresses Greptile P1 (multi-token prompt).

Also adds a regression test pinning that flagless operational commands
(serve/call/realtime/debug/lsp/diag) stay Typer commands and are never
misrouted to `run` as prompts (Greptile P1 #2 was a false positive).

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:30:43 +00:00
praisonai-triage-agent[bot]andMervinPraison f3b75f5fa7 fix: round-trip long interactive select/reply values via durable callback store (fixes #3312)
Interactive reply/select values that exceed a channel's callback byte-cap
(e.g. Telegram's 64-byte limit) were hashed with no way to recover the
original value, so long option values (URLs, file paths, free-text) made
menus silently non-functional. This generalises the durable-reference
pattern already used by approvals to ordinary interactive callbacks.

- Add CallbackPayloadStoreProtocol (peer of ApprovalStoreProtocol) plus a
  bounded, zero-dependency InMemoryCallbackPayloadStore default in core.
- Encoders persist an overflowing value under a short reference and emit
  reply:@<ref> / select:<action_id>:@<ref>; inline values are unchanged.
- InteractiveRegistry(store=...) resolves @<ref> back to the exact value on
  dispatch, preserving the select action_id prefix, and fails closed on an
  unknown/expired reference. Without a store the prior hash behaviour is kept.

Additive and backward compatible: adapt_presentation gains an optional
callback_store kwarg; registry gains an optional store arg.

Co-authored-by: MervinPraison <[email protected]>
2026-07-23 10:28:22 +00:00
praisonai-triage-agent[bot]andMervin Praison 7db836da1e fix: aworkflow loop expansion, concurrent turn-tool race, MCP skill-gate discovery (fixes #3307)
Gap 1: Port sync workflow()'s loop-task pre-expansion into aworkflow() so
async CSV-driven loop start tasks run per-row instead of once.

Gap 2: Guard the per-turn tool buffer (_turn_tools_used) with a DualLock via
_reset_turn_tools/_record_turn_tool/_drain_turn_tools helpers, matching the
existing chat_history protection, so concurrent chat()/achat() turns on one
Agent no longer corrupt hook/self-improvement data.

Gap 3: Track namespaced MCP server names in a process-level registry and let
the skills CapabilityValidator discover them, so MCP-server-gated skills can
pass STRICT validation instead of always failing closed.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:27:43 +00:00
praisonai-triage-agent[bot]andMervin Praison f00e3ba60a fix: harden praisonai serve agents (auth, generator caching, route convergence) (fixes #3308)
- Refuse non-localhost bind without --api-key/PRAISONAI_SERVE_API_KEY,
  mirroring jobs/server.py policy (POST /agents can run YAML-defined tools).
- Cache one AgentsGenerator per app via FastAPI lifespan instead of rebuilding
  it (YAML re-parse, registry re-resolve, fresh 32-worker pool) per request;
  serialise the shared cli_config with an asyncio.Lock and close() on shutdown.
- Converge /agents and /agents/{agent_name} on the same generator path so both
  apply identical YAML lowering (ToolResolver, tool_timeout, approval,
  guardrails, retry) instead of the safety-stripped hand-rolled PraisonAgent.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:25:45 +00:00
praisonai-triage-agent[bot]andMervinPraison 53f3449abe fix: surface retry/backoff as a stream event so CLI waits aren't mistaken for a hang (fixes #3311)
Add StreamEventType.RETRY and emit it alongside the existing ON_RETRY hook in both the sync and async retry loops (guarded by has_callbacks, so it stays zero-overhead when no consumer is attached). The event carries attempt, max_attempts, delay and reason in metadata.

The CLI stream-event bridge maps it to a canonical run.retry NDJSON event so consumers can render a live 'retrying in Ns (attempt k/N)' status instead of a silent, hung-looking terminal. Non-JSON/silent modes stay silent.

Co-authored-by: MervinPraison <[email protected]>
2026-07-23 10:25:32 +00:00
praisonai-triage-agent[bot]andMervin Praison bcb62c832c fix: self-repair and actionable feedback on unknown tool calls (fixes #3309)
When the LLM emits an unresolvable tool call, the runtime now:
- attempts a deterministic self-repair by normalising case/separator drift
  (e.g. 'WebSearch' -> 'web_search') against the agent's active tools;
- otherwise returns a corrective, model-readable error naming the nearest
  valid tool and listing the currently available tools;
- on argument-bind failure, echoes the tool's required/optional parameters.

Reuses existing dispatch path; no new public API or Agent params.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:24:52 +00:00
praisonai-triage-agent[bot]andMervin Praison 423144d43c fix: neutralise untrusted platform metadata in prompt attribution (fixes #3313)
Add a pure-stdlib core helper neutralize_untrusted_text() in
praisonaiagents.session.context and apply it by default to the sender
display name in the bot's _attribute() prefix. Collapsing newlines/control
chars and bounding length stops a hostile group display name / title from
masquerading as a fake heading or system directive in the per-turn prompt,
while well-behaved names render byte-identically. Safe-by-default; no new
config knobs.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-23 10:24:19 +00:00
praisonai-triage-agent[bot]andMervinPraison 82f55c97b0 fix: route bare prompts through the modern Typer run engine (fixes #3310)
A bare free-text prompt (`praisonai "do something"`) now forwards to the
same modern `run` path as `praisonai run`, inheriting session continuity,
--output modes, the credential gate and permissions. `.yaml` workflows and
flag-bearing legacy invocations remain on the legacy dispatcher.

Co-authored-by: MervinPraison <[email protected]>
2026-07-23 10:24:08 +00:00
praisonai-triage-agent[bot] 7494bbadc9 Merge pull request #3306 from MervinPraison/feat/praisonai-train-gen-guard
feat(data): in-loop cost/sponsorship guard + per-row provenance stamping
2026-07-22 17:50:43 +00:00
praisonai-triage-agent[bot] 362aba4619 Merge pull request #3305 from MervinPraison/claude/issue-3304-20260722-1603
fix: async-safe serve/jobs hot paths + scheduler thread-leak
2026-07-22 17:13:56 +00:00
praisonai-triage-agent[bot]andMervin Praison 1a64808cd1 fix(train/data): emit guard trigger row + harden check interval
Address reviewer feedback on the in-loop continuation guard:
- Emit the just-completed (paid) row before the guard halts, so the
  request that trips the sponsorship check is no longer silently dropped.
- Coerce sponsor_check_rows to a safe minimum of 1 so a 0 (divide-by-zero)
  or negative (never-poll, guard disabled) value cannot break/disable the
  safety check; unset preserves the 5000 default.

Adds tests for trigger-row emission and invalid-interval handling.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 17:02:12 +00:00
MervinPraisonandClaude Opus 4.8 e363f3a43d feat(data): in-loop continuation guard + per-row provenance stamping
Two additive, backward-compatible features for the synthetic-data generator.

1. In-generator continuation guard. generate_dataset gains an optional
   should_continue() -> bool callback, re-checked every `sponsor_check_rows`
   completed requests (default 5000). When it returns False the run halts
   cleanly via the existing shutdown path (touch stop-file + cancel pending
   futures + break). If no callback is passed but `subscription_id` (or env
   AZ_SUBSCRIPTION) is set, a built-in Azure sponsorship check is wired in
   (quotaId == "Sponsored_2016-01-01"). The guard fails OPEN on transient
   errors — an external watchdog is the hard fail-closed guard; this is
   belt-and-suspenders. New public helper: azure_sponsorship_guard().

2. Per-row provenance stamping. Emitted rows are now self-describing: _call
   stamps `model` (deployment) and passes through `task_type`/`topic` from the
   prompt spec when present. The axis recipe stamps task_type/topic onto each
   spec, so QC (which already reads r["task_type"]) and downstream category
   splits key off metadata instead of brittle text. Keys are added only when a
   value is available (backward-compatible).

Tests (network stubbed): the guard halts after N rows when the predicate turns
False and never halts while True; rows carry model/task_type/topic when
provided and omit task_type/topic when absent; plus fail-open and
subscription-id wiring.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 17:54:20 +01:00
praisonai-triage-agent[bot]andMervin Praison ba1dfe413e fix: thread caller prompt/query into serve+jobs workflow input (fixes #3304 P1)
The switch to praisonai.arun() dropped the caller's required input on the
native jobs path (job.prompt) and the serve /agents fallback (query), since
arun has no prompt param and the workflow topic is read from YAML input/topic
only. Honour input/topic overrides in AgentsGenerator._merge_cli_config
(reusing the existing merge seam, no new params/exports) and pass
job.prompt / query through cli_config so per-run input drives the workflow
instead of being silently discarded. Static YAML input is preserved when no
prompt is supplied.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 16:14:58 +00:00
praisonai-triage-agent[bot]andMervinPraison ba08895393 fix: async-safe serve/jobs hot paths + scheduler thread-leak (fixes #3304)
- serve.py: route the crew fallback through praisonai.arun (owns the
  AgentsGenerator lifecycle, runs off the event loop) and replace
  asyncio.get_event_loop() with asyncio.to_thread in both agent handlers.
- jobs/executor.py: _run_praisonai_agents now delegates to praisonai.arun
  so the caller's agent_file/agent_yaml/framework/config are honoured
  instead of silently dropped by a stock Agent.
- scheduler/agent_scheduler.py: reuse an instance-owned ThreadPoolExecutor
  with leak accounting and recycling (mirrors AgentsGenerator), unify the
  timeout branch into the backoff path, and close() the pool on stop().

Co-authored-by: MervinPraison <[email protected]>
2026-07-22 16:07:17 +00:00
praisonai-triage-agent[bot] 4aa4480051 Merge pull request #3303 from MervinPraison/feat/praisonai-train-dedup
feat(train/data): scalable MinHash+LSH near-dedup + cross-file global dedup
2026-07-22 15:57:03 +00:00
praisonai-triage-agent[bot]andMervin Praison fef83097b8 fix(train/data): correct dedup edge cases from review
- reuse a supplied empty shared MinHashLSH index (is not None, not `or`)
  so cross-batch near-dedup works on the first call
- treat empty MinHash signatures as non-similar (0.0) and reject
  minhash_perm/ngram_n < 1, so degenerate config can't collapse a dataset
- global_dedup honours near_dup_method='sliding' and raises a clear
  FileNotFoundError for missing paths instead of a cryptic AttributeError
- sliding look-back treats window<=0 as intentional unbounded
- dedup CLI writes to a temp file + atomic replace, so an --out that
  aliases an input is never truncated and a malformed line never leaves
  a partial output

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 15:10:04 +00:00
MervinPraisonandClaude Opus 4.8 4910fa9d23 feat(train/data): scalable MinHash+LSH near-dedup + cross-file global dedup
The QC near-dup pass was O(n·3000) sliding-window char-4gram Jaccard, which is
both slow at scale and structurally blind to near-duplicates more than 3000 rows
apart — and score() rebuilds its dedup state per call, so it cannot remove dups
that span multiple batch files (the common case when merging parallel runs).

Add praisonai_train.data.dedup (pure stdlib, no datasketch/numpy):
- MinHasher / MinHashLSH: seeded, deterministic MinHash signatures over the same
  normalized char-4gram shingles the sliding engine uses (so near_dup_jaccard
  keeps identical semantics), with LSH banding for sub-linear candidate lookup
  and no bounded look-back window.
- near_dedup(rows, cfg): one interface, YAML-tunable near_dup_method
  ("sliding" default = unchanged, or "minhash"). qc.score() now delegates to it
  (DRY); default path behaviour is byte-for-byte the same. near_dup_window is now
  configurable too.
- global_dedup(sources, cfg): dedup ACROSS many JSONL files / row-lists with ONE
  shared exact+LSH index — what per-file score() cannot do.
- CLI: `praisonai-train dedup batch_*.jsonl --out merged.jsonl`.

Backward compatible: no new deps, default engine and outputs unchanged; MinHash
and cross-file dedup are opt-in.

Tests: 13 new (deterministic) — MinHash catches a far near-dup the window misses,
preserves genuinely-distinct rows, cross-file exact+near removal, exact-only, and
default-still-sliding. Full data suite 60 passed.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 16:02:01 +01:00
praisonai-triage-agent[bot] 6646dcc0cb Merge pull request #3302 from MervinPraison/feat/praisonai-train-benchmark
feat(praisonai-train): speed-benchmark SDK feature + CLI
2026-07-22 14:47:26 +00:00
MervinPraison 70fddb587d docs: auto-update documentation parity trackers [skip ci] 2026-07-22 14:38:18 +00:00
praisonai-triage-agent[bot] 2f3d9bda70 Merge pull request #3301 from MervinPraison/claude/issue-3297-20260722-1323
fix: close the loop on permanently-undelivered gateway replies
2026-07-22 14:37:46 +00:00
praisonai-triage-agent[bot] 23ebb6ee13 Merge pull request #3300 from MervinPraison/claude/issue-3298-20260722-1323
fix: coalesce inbound media albums into a single agent turn
2026-07-22 14:32:34 +00:00
MervinPraison c82d4ab033 docs: auto-update feature parity trackers [skip ci] 2026-07-22 14:32:16 +00:00
praisonai-triage-agent[bot] 883e8c5c71 Merge pull request #3299 from MervinPraison/claude/issue-3296-20260722-1322
fix: surface turn-completion reason to gateway users
2026-07-22 14:31:50 +00:00
praisonai-triage-agent[bot]andMervin Praison 9e476750eb fix(praisonai-train): benchmark metric consistency, JSON-mode toggle, input validation
- Count completion tokens only for successful (ok) responses so token
  throughput and avg_out_tok stay consistent with the success count.
- Thread a json_mode flag through _timed_call/_measure_target/
  benchmark_deployments and expose --json-mode/--no-json-mode + yaml key,
  so OpenAI-compatible endpoints without JSON mode aren't ranked as failures.
- Validate prompt dicts (require non-empty 'user') and reject n<1 /
  concurrency<1 with a clear ValueError instead of KeyError / silent
  zero-request runs miscounted as endpoint failures.
- Add 4 tests; existing stubs updated for the new json_mode arg. 102 passed.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 13:43:38 +00:00
MervinPraisonandClaude Opus 4.8 148880c88b feat(praisonai-train): add speed-benchmark SDK feature + CLI
Add a first-class, protocol-driven speed benchmark to the praisonai-train
data SDK, mirroring the generate/validate idiom. It sends N identical
requests per deployment at a fixed concurrency and reports throughput
(rows/min, completion-tokens/sec), latency (avg/p50/p95), success count
and average output tokens, then ranks deployments fastest-first.

DRY: extract the generator's HTTP call path into shared helpers
(`build_chat_request`, `resolve_cfg`) so benchmarking reuses the exact
same Azure/OpenAI-compatible request construction and credential
resolution as real generation — no duplicated HTTP code. The default
prompt reuses a registered Recipe so benchmarks reflect the real workload.

- data/benchmark.py: `benchmark_deployments(...) -> list[BenchResult]`,
  pure `aggregate()`, and network confined to a `_timed_call` seam.
- cli/commands/benchmark.py: `praisonai-train benchmark` (YAML/flags),
  ranked table + JSON output.
- setup/benchmark.yaml: documented sample config.
- tests: aggregation math, ranking, success/failure counting, real
  threaded path, per-target endpoint override (network stubbed).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 13:43:38 +00:00
praisonai-triage-agent[bot] 3601fba539 Merge pull request #3294 from MervinPraison/feat/praisonai-train-taskaware-qc
feat(train/data): task-aware script purity + translation-share metric
2026-07-22 13:40:49 +00:00
praisonai-triage-agent[bot]andMervin Praison 62f7fa599e fix: wire gateway.notify_on_undelivered opt-in end-to-end (#3297)
The documented gateway.notify_on_undelivered / undelivered_template YAML
opt-in was a dead path: GatewayServerSchema (extra="forbid") rejected the
keys at load time, and neither start_with_config nor from_config_file
propagated them onto self.config, so the delivery router's getattr always
saw the OFF default.

- Accept both keys in GatewayServerSchema (kept optional, lightweight).
- Stamp them onto self.config in start_with_config (primary CLI path) and
  from_config_file, honouring the "no new core GatewayConfig field" design.
- Add a regression test covering schema acceptance + propagation.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 13:40:47 +00:00
praisonai-triage-agent[bot]andMervin Praison 705e848154 fix: wire gateway to surface turn-completion note (fixes #3296)
Connect the previously-inert completion path (Greptile P1): BotSessionManager
now reads the agent's last_stop_reason after each turn and, when the new opt-in
surface_completion_reason flag is set, appends a concise user-safe note for
early stops (max_steps / cancelled / error). Off by default so clean
completions and existing deployments are unchanged.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 13:38:35 +00:00
praisonai-triage-agent[bot]andMervin Praison e1527911af fix: reclaim orphaned album temp files on owner cancellation (#3298)
Address greptile P1 review feedback on the inbound media-album coalescer:
when the owning Telegram update is cancelled (e.g. during shutdown) after
sibling updates already folded their media in, the buffered temp files could
leak. Add an on_orphan cleanup hook invoked whenever a flushed album has no
live owner awaiting it, wired to a shared _remove_inbound_media helper in the
Telegram bot. Also clarify the max_items cap semantics (bounded, intentional).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 13:37:13 +00:00
praisonai-triage-agent[bot]andMervinPraison d6c846c058 fix: close the loop on permanently-undelivered gateway replies (fixes #3297)
On a confirmed-permanent outbound failure the reply was parked in the DLQ /
the target marked dead but the user heard nothing. Add an opt-in last-resort
notice: a short plain-text delivery-failure message on the same channel plus a
MESSAGE_UNDELIVERED lifecycle hook so operators can route the failure.

Core (protocol only): add HookEvent.MESSAGE_UNDELIVERED and
MessageUndeliveredInput. Wrapper (praisonai-bot): DeliveryRouter fires the hook
and best-effort sends the notice on permanent failure; default OFF, wired from
gateway.notify_on_undelivered.

Co-authored-by: MervinPraison <[email protected]>
2026-07-22 13:29:17 +00:00
praisonai-triage-agent[bot]andMervinPraison 9067531313 fix: coalesce inbound media albums into a single agent turn (fixes #3298)
Telegram delivers a media album (multiple photos/files sent together) as N
separate updates sharing one media_group_id, so the agent saw each part as
its own turn. Add an AlbumCoalescer that buffers media parts by group key
and flushes them as one multimodal turn, mirroring the existing
InboundDebouncer text pattern.

- New praisonai_bot/bots/_album.py: bounded per-group buffer (window +
  max_items), operator-tunable via config.metadata (media_group_window_ms /
  media_group_max), disabled by default so behaviour is unchanged.
- Wire into TelegramBot.handle_message (sibling updates fold into one turn)
  and flush pending buffers on stop().
- Tests in tests/unit/test_bot_album.py.

Co-authored-by: MervinPraison <[email protected]>
2026-07-22 13:27:36 +00:00
praisonai-triage-agent[bot]andMervinPraison b2627dd8b9 fix: surface turn-completion reason to gateway users (fixes #3296)
Add an optional, backward-compatible TurnCompletion contract to the bot
reply path so a chat user learns *why* a turn stopped early instead of
seeing a silently truncated/empty reply.

- TurnCompletion wraps the existing coarse Agent.last_stop_reason
  (completed | max_steps | cancelled | error) into a portable value with
  a user-safe, localisable .note(); completed turns surface nothing.
- AgentReply gains an optional `completion` field (defaults None).
- extract_completion() reads it off any result (incl. a bare Agent via
  last_stop_reason); append_completion_note() lets a gateway optionally
  append the note, off by default so existing deployments are unchanged.

Reuses the existing runtime stop reason rather than adding new detection
or Agent params — no new module, no wrapper knobs.

Co-authored-by: MervinPraison <[email protected]>
2026-07-22 13:26:40 +00:00
MervinPraison 6aa9f4cb51 docs: auto-update api.md [skip ci] 2026-07-22 13:25:43 +00:00
Mervin Praison f70a9c8a09 Merge pull request #3285 from Dhivya-Bharathy/fix/e2e-examples-batch2
fix: batch-2 E2E example failures (workflow results, imports, skip stale examples)
2026-07-22 14:25:17 +01:00
Mervin Praison 9cd15b2e99 Merge pull request #3295 from MervinPraison/feat/praisonai-train-gen-progress
feat(praisonai-train): optional progress_callback for synthetic-data generation
2026-07-22 14:24:12 +01:00
praisonai-triage-agent[bot]andMervin Praison 589b20afed fix(praisonai-train): report progress kept after yield so it never leads emitted rows
Move progress_callback below the yield in generate_dataset so 'kept' reflects
rows the consumer has actually received (Greptile P1). Docstring clarified.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 13:18:03 +00:00
MervinPraisonandClaude Opus 4.8 a21e825300 feat(praisonai-train): optional progress_callback for synthetic-data generation
generate_dataset() gains an optional progress_callback(done, total, kept)
invoked as teacher requests complete, so a CLI/monitor/notebook can show
completion and remaining work. Backward compatible: default None keeps the
original behaviour (no callback). Fires once up-front with (0, total, 0) then
after each completed request; done is monotonic up to total, kept counts unique
rows emitted.

The `generate` CLI command wires a default reporter (_Progress): a tqdm bar when
tqdm is importable, else throttled done/total prints. tqdm stays optional — the
import is guarded and never becomes a hard dependency.

Adds unit tests asserting the callback fires with monotonic done up to total,
that kept tracks dedup, and that the default (no callback) path is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 14:12:23 +01:00
praisonai-triage-agent[bot]andMervin Praison 903d1c6d31 fix(train/data): correct unknown-metadata fallback + exemption-count semantics
- intent.translation_intent: an unrecognised non-empty task_type no longer
  short-circuits to non-translation; it falls through to the documented text
  fallback so an explicit "translate into English" instruction is honoured and
  its English output is not dropped as low_script_purity (greptile P1).
- qc.score: the translation `exempted` metric now counts only rows the
  English-target exemption ACTUALLY rescued from LowScriptPurity (task-awareness
  on AND output below the purity floor), so it reconciles with check behaviour
  instead of over-counting failed translations and task_aware_purity=false runs
  (greptile P1).
- Add 4 regression tests (29 passed total).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 12:28:12 +00:00
MervinPraisonandClaude Opus 4.8 c86780a911 feat(train/data): task-aware script purity + translation-share metric
Add two dataset-QC features to the praisonai-train data SDK, wired in the
SDK's protocol-driven idiom (registered RowChecks + a corpus metric) and
sharing ONE translation-intent detector so they can never disagree (DRY).

1. Task-aware script purity: the script-purity checks no longer delete an
   output that is legitimately in another script because the instruction
   asked to translate INTO that language (e.g. a Tamil->English row's
   correct output is English). LowScriptPurity/ScriptReview now exempt a
   resolved English-target row; a new WrongTargetScript flag catches the
   inverse failure (asked for English, output still Tamil). Only a resolved
   English target exempts — en->ta / ambiguous / native rows stay strict.

2. Translation-share corpus metric: metrics.translation reports the fraction
   of kept rows that are translation tasks, by direction (en_ta/ta_en/unknown)
   and an exempted count, computed with the SAME detector so it reconciles
   with the per-row exemptions.

New single source of truth: data/intent.translation_intent(); metadata
(task_type) is authoritative, instruction-text detection is the external-row
fallback, ambiguous direction yields no exemption (safe default).

17 new unit tests (mirroring the modeltrain reference); full data suite green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-22 13:21:36 +01:00
Leebana efda323b78 Merge pull request #3287 from MervinPraison/feat/praisonai-train-data-sdk
praisonai-train: protocol-driven data SDK — generate + validate (YAML-driven)
2026-07-22 12:09:36 +01:00
Leebana 0621bb878d Merge pull request #3292 from MervinPraison/fix/claude-triage-bug-before-howto
fix: triage bug reports before "how to" question label
2026-07-22 12:09:03 +01:00
Leebana 81f95686d4 Merge pull request #3291 from MervinPraison/claude/issue-3244-20260722-1032
fix: never load profile legacy .praison/config.toml as project source
2026-07-22 12:08:05 +01:00
Leebana 25653af0ea Merge pull request #3290 from MervinPraison/claude/issue-3280-20260722-1032
fix: remove nonexistent self.env from terminal_bench adapters
2026-07-22 12:06:07 +01:00
praisonai-triage-agent[bot]andMervin Praison 52c729d4c6 fix: exclude [question] titles from bug label to prevent false auto-claude
Addresses Greptile P1: an issue such as '[QUESTION] How do I handle this
API error?' matched 'error' before the question marker was checked,
receiving 'bug' + auto 'claude'. Guard bug detection on \!title.includes('[question]').

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 11:05:56 +00:00
Leebana a6f680eeb3 Merge pull request #3289 from MervinPraison/claude/issue-3282-20260722-1032
fix: pass required logs_dir to external agent integration tests
2026-07-22 12:05:37 +01:00
Leebana ef3a64751a Merge pull request #3288 from MervinPraison/claude/issue-3281-20260722-1032
fix: make test_code_agent_command_shape compatible with Harbor pipefail wrapper
2026-07-22 12:04:48 +01:00
MervinPraison 65f8903d60 fix: triage bug reports before "how to" question label
Bug issues with a "## How to fix" section were labelled question first,
which blocked autoClaude. Check bug/error/crash before how-to heuristics,
ignore "how to fix" for question detection, and let bug label win over
a stale question label for auto-triage.
2026-07-22 12:02:34 +01:00
praisonai-triage-agent[bot]andMervin Praison 74bbe562c0 fix(praisonai-train): address data SDK review bugs (dedup, chat pairing, safe output, validate robustness)
- qc: include output in exact-dedup key so distinct answers to the same
  prompt are not silently dropped
- _util.fields: pair the final assistant turn with the user turn that
  precedes it (never a trailing unanswered user turn)
- cli generate: forward --snapshot-every override; defer output truncation
  until the first row is produced (a failed run no longer destroys an
  existing file / self-referential dedup source); exit non-zero when 0 rows
  are generated instead of reporting empty success
- cli validate: skip malformed JSONL lines (with line numbers) instead of
  aborting the whole run
- generate: configurable request_timeout; accurate stop-file docstring
- tests: cover distinct-answer dedup and multi-turn chat pairing

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:40:22 +00:00
praisonai-triage-agent[bot]andMervin Praison dfaa319895 fix: strip Harbor pipefail prefix then assert command start (Greptile P2)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:37:36 +00:00
praisonai-triage-agent[bot]andMervin Praison ba679a1ca3 fix: never load profile legacy .praison/config.toml as project source (fixes #3244)
Remove the legacy `.praison/config.toml` from PROJECT_CONFIG_NAMES so the
walk-up discovery never mislabels a profile-level legacy global config as a
`project:` source. The legacy file is owned exclusively by
_load_global_config() with a `global:` label. Removes the now-dead
search_dir == home skip guard and adds a regression test.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:35:16 +00:00
praisonai-triage-agent[bot]andMervin Praison 2d915a3151 fix: pass required logs_dir to external agent integration tests (fixes #3282)
Harbor 0.20's BaseAgent.__init__ requires logs_dir as first positional
arg. The TestPraisonAIExternalAgent tests constructed the agent with zero
args, causing a TypeError. Pass logs_dir via pytest tmp_path to match the
existing pattern used by TestPraisonAICodeAgent and TestPraisonAIInstalledAgent.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:33:59 +00:00
praisonai-triage-agent[bot]andMervin Praison a7dcfe3a5d fix: remove nonexistent self.env from terminal_bench adapters (fixes #3280)
Harbor 0.20 agents expose extra_env (wired into the container exec
context by Trial), not self.env. Passing env=self.env crashed
PraisonAICodeAgent.run() with AttributeError. Omit the per-exec env=
so Harbor's trial-scoped injection applies. Same fix applied to
praisonai_installed_agent.py.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:33:52 +00:00
praisonai-triage-agent[bot]andMervin Praison 99b5193260 fix: make test_code_agent_command_shape compatible with Harbor pipefail wrapper (fixes #3281)
Harbor's BaseInstalledAgent._exec always prefixes commands with
'set -o pipefail; ', so the .startswith assertion failed even when the
adapter command was correct. Switch to a substring match.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:33:42 +00:00
MervinPraisonandClaude Fable 5 fe2f08fcbc praisonai-train: add protocol-driven data SDK (generate + validate), YAML-driven
Adds dataset tooling to praisonai-train, following the SDK principles (protocol-
driven, DRY, extendable, YAML-configurable):

- praisonai_train/data/: registry + protocols (Recipe, RowCheck) + pluggable
  recipes (tamil, extendable) and QC checks (dedup, boilerplate/refusal, script
  purity, truncation, restates-question) + shared helpers. Add a language/domain
  or a QC rule by registering one class — the CLI picks it up automatically.
- generate: teacher-LLM synthetic generation (Azure OpenAI / OpenAI-compatible),
  JSON mode for high yield, diversity axes so large runs don't collapse,
  start_offset for disjoint parallel workers, dedup-on-write, incremental
  snapshots, and a stop-file circuit-breaker (halts instantly, e.g. on a billing
  guard). Stdlib HTTP, no new deps.
- validate: research-backed QC (LIMA/AlpaGasus/Deita/Self-Instruct thresholds) —
  exact + near-dedup, per-row drop/flag checks, and diversity metrics (distinct-2,
  length CV, template concentration) with warnings.
- CLI: 'praisonai-train generate --config generate.yaml' and
  'praisonai-train validate data.jsonl --out clean.jsonl'; example YAMLs shipped.
- Tests: tests/unit/data/test_data.py (6 tests). Validated end-to-end live:
  YAML generate -> 19 rows (distinct-2 0.93); validate on 500 real rows kept 81%,
  caught low-purity/near-dup, warned on template concentration.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 11:33:17 +01:00
Mervin Praison 3a7abaea27 Merge pull request #3286 from MervinPraison/fix/praisonai-train-complete
praisonai-train: land auto-resume + reconciliation (missed #3283 merge) + finish P2 hygiene
2026-07-22 11:27:18 +01:00
praisonai-triage-agent[bot]andMervin Praison 6a373d0efa praisonai-train: address final review — boolean PRAISON_DEBUG, checkpoint filtering, GGUF push default, passthrough cadence reconcile
- PRAISON_DEBUG now parsed as a boolean (0/false/no disable it, not just unset)
- auto-resume filters to real numeric checkpoint-* dirs and passes the validated
  path to the trainer (instead of leaving resume=True and re-discovering); also
  accepts 1/yes/on/off spellings before treating a string as a literal path
- push_model_gguf honors quantization_method default (q4_k_m) matching save path
- final save/eval cadence reconciliation after training_arguments passthrough so
  load_best_model_at_end can't reach SFTConfig with mismatched strategies/steps

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 10:10:40 +00:00
MervinPraisonandClaude Fable 5 fa9d6e2cca praisonai-train: restore tokenize_function (public re-export by praisonai.train)
Reverts the removal of tokenize_function — it is imported and re-exported in
praisonai/train.py __all__, so deleting it breaks that public API. Kept it (now
uncalled by the training path but retained for backward compat) and removed only
the internal, unreferenced tokenize_dataset method.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 09:39:32 +01:00
MervinPraisonandClaude Fable 5 70a0ba70a4 praisonai-train: log epochs-vs-max_steps precedence (final P2 item)
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 09:35:58 +01:00
MervinPraisonandClaude Fable 5 ac03570b91 praisonai-train: finish P2 hygiene (dead code, gguf quant, debug noise)
- Remove dead tokenize_function/tokenize_dataset (unused since TRL tokenizes
  internally; used padding='max_length' which would waste compute if ever rewired).
- save_model_gguf now honors config quantization_method (was hardcoded 'q4_k_m',
  inconsistent with push_model_gguf).
- Gate the per-batch DEBUG prints behind PRAISON_DEBUG so normal runs stay readable.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 09:34:49 +01:00
MervinPraison 569e0d7ebc docs: auto-update feature parity trackers [skip ci] 2026-07-22 08:21:19 +00:00
Mervin Praison deef1053df Merge pull request #3284 from Dhivya-Bharathy/fix/e2e-examples-failures
fix: E2E examples failures (Windows timeout, missing modules, broken examples)
2026-07-22 09:20:53 +01:00
MervinPraisonandClaude Fable 5 32d648ce7d praisonai-train: auto-reconcile save_steps/eval_steps for load_best_model_at_end
HF requires save_steps to be a multiple of eval_steps when load_best_model_at_end
is on. A config with save_steps=100, eval_steps=500 (both valid-looking) crashed.
Now the trainer aligns eval_steps to save_steps (preserving the user's checkpoint
frequency) with a warning, instead of erroring out.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 08:12:20 +01:00
MervinPraisonandClaude Fable 5 9e59148167 praisonai-train: crash-safe auto-resume from latest checkpoint
resume_from_checkpoint: true now auto-finds the latest checkpoint in output_dir
and resumes from it; if none exists yet (fresh run) it starts fresh instead of
erroring. So after any crash (OOM, GPU reclaim) you just relaunch the SAME
command and training continues from the last saved step. Validated on GPU:
fresh run -> checkpoint-2/4; relaunch -> resumed from checkpoint-4, continued 5->8.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 08:06:33 +01:00
praisonai-triage-agent[bot]andMervin Praison dd297fe56f fix: C7 boundary, timeout process group, and command cwd in agent tools
- Remove wrapper import from praisonai-code agent_tools.py (C7 gate
  regression): use a module-local _run_sync bridge instead of
  `from praisonai._async_bridge import run_sync` so the Tier-2 package
  no longer depends on the praisonai wrapper at the hot path.
- suite_runner: start child processes with start_new_session=True on
  POSIX so timeout killpg reaps only the child tree, never the runner.
- agent_tools/orchestrator: honor acp_execute_command cwd by forwarding
  it into the plan step; orchestrator validates it stays in workspace.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 06:34:24 +00:00
praisonai-triage-agent[bot] 8a6097c584 Merge pull request #3283 from MervinPraison/fix/praisonai-train-flexibility
praisonai-train: multi-GPU (DDP), checkpointing/resume, eval, and full training flexibility
2026-07-22 06:19:54 +00:00
MervinPraisonandClaude Fable 5 bcd6e64a61 praisonai-train: default ddp_find_unused_parameters=True for multimodal/MoE models
Gemma 4 E4B (and other multimodal/MoE/elastic models) have LoRA-adapted params
that don't fire every step (vision/audio towers in text-only training), which
crashes DDP with 'Expected to have finished reduction' when find_unused=False.
Default True works universally; set false for a small speedup on dense-text models.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 06:26:51 +01:00
praisonai-triage-agent[bot]andMervin Praison 52a9c48fed fix(praisonai-train): resolve 4 P1 DDP/full-FT/reload/early-stop bugs
- Set UNSLOTH_USE_NEW_MODEL before unsloth import (DDP non-reentrant path)
- Skip LoRA when full_finetuning: true (train base weights directly)
- Reload model with trained precision (dtype/8bit/full_finetuning), not 4bit-only
- Re-align save/eval strategy when early stopping enables load_best_model_at_end

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-22 05:20:23 +00:00
MervinPraisonandClaude Fable 5 4069b585cc praisonai-train: guard final save + HF/Ollama publish to rank 0 under DDP
Only the main process merges/pushes and writes the final adapter, so multi-GPU
runs don't race to write the same repo/dir.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 06:14:54 +01:00
MervinPraisonandClaude Fable 5 5c38677af1 praisonai-train: multi-GPU (DDP), checkpointing/resume, eval, and full flexibility
Validated end-to-end on 2x A6000 (unsloth 2026.7.4 / trl 0.24 / torch 2.10):
multi-GPU DDP trains (Data Parallel GPUs = 2, no 'marked ready twice'),
checkpointing + eval + best-model + final_model_dir all work.

Multi-GPU (DDP):
- Detect distributed (LOCAL_RANK/WORLD_SIZE); load full model per-rank
  (device_map={'':local_rank}); set UNSLOTH_USE_NEW_MODEL=1 under DDP to force
  Unsloth's non-reentrant checkpointing (the legacy path hard-codes reentrant,
  which double-fires autograd hooks and crashes DDP). Set ddp_find_unused_parameters
  =False (LoRA freezes the base). Launch: torchrun --nproc_per_node=N.

Checkpointing / resume:
- Config-driven save_strategy/save_steps/save_total_limit (was only under an env var);
  resume_from_checkpoint (bool=latest, or a path); final_model_dir (fixes the old
  lora_model vs output_dir mismatch that broke load_model).

Evaluation / early stopping:
- val_split_ratio carves an eval set; eval_strategy/eval_steps/load_best_model_at_end/
  metric_for_best_model; EarlyStoppingCallback via early_stopping_patience.

Flexibility:
- Generic training_arguments passthrough (any raw SFTConfig field), auto-filtered to
  what the installed TRL accepts (version-proof; e.g. save_safetensors/group_by_length
  differ by version) — warns instead of crashing.
- Knobs: max_grad_norm, warmup_ratio, neftune_noise_alpha, dataloader_num_workers,
  data_seed, adam betas, report_to/run_name (config, not just env), push_to_hub.
- Quantization: load_in_8bit, dtype, full_finetuning. LoRA: modules_to_save,
  rank_pattern, alpha_pattern, use_dora. Data: local files, shuffle, rename, filter.

Correctness fixes:
- load_in_4bit KeyError when omitted; inference().to(cuda) -> self.device;
  drop empty-formatted rows instead of silently training on blanks.

All new keys optional with prior defaults; existing configs unchanged.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-22 06:12:38 +01:00
816 changed files with 49895 additions and 6684 deletions

No files matched your search

@@ -1,5 +1,5 @@
name: Install PraisonAI monorepo packages
description: Install praisonai-agents, praisonai-code, praisonai-bot, praisonai-train, praisonai-browser, praisonai-mcp, praisonai-sandbox, and praisonai wrapper from local paths (mirrors PyPI eight-package install order).
description: Install praisonai-agents, praisonai-code, praisonai-bot, praisonai-train, praisonai-browser, praisonai-mcp, praisonai-sandbox, praisonai-deploy, and praisonai wrapper from local paths (mirrors PyPI nine-package install order).
inputs:
repo-root:
@@ -40,6 +40,7 @@ runs:
BROWSER_PKG="${BASE}src/praisonai-browser"
MCP_PKG="${BASE}src/praisonai-mcp"
SANDBOX_PKG="${BASE}src/praisonai-sandbox"
DEPLOY_PKG="${BASE}src/praisonai-deploy"
WRAPPER_PKG="${BASE}src/praisonai"
normalise_extras() {
@@ -69,6 +70,8 @@ runs:
uv pip install --system -e .
cd "$SANDBOX_PKG"
uv pip install --system -e .
cd "$DEPLOY_PKG"
uv pip install --system -e .
cd "$WRAPPER_PKG"
uv pip install --system "${WRAPPER_SUFFIX}"
else
@@ -86,6 +89,8 @@ runs:
pip install -e .
cd "$SANDBOX_PKG"
pip install -e .
cd "$DEPLOY_PKG"
pip install -e .
cd "$WRAPPER_PKG"
pip install -e "${WRAPPER_SUFFIX}"
fi
+28 -4
View File
@@ -36,8 +36,10 @@ assert.strictEqual(dayStart.toISOString(), '2026-07-08T00:00:00.000Z');
},
},
};
assert.strictEqual(rg.PATCH_RELEASE_INTERVAL_DAYS, 3);
assert.strictEqual(
await rg.hasSuccessfulReleaseToday(mockGithub, 'o', 'r', noonUtc),
await rg.hasSuccessfulReleaseWithinDays(mockGithub, 'o', 'r', noonUtc),
true
);
@@ -46,12 +48,34 @@ assert.strictEqual(dayStart.toISOString(), '2026-07-08T00:00:00.000Z');
{ headSha: 'abc', isCiTrigger: false, bump: 'patch', now: noonUtc },
null
);
assert.ok(result.reasons.some((r) => r.includes('already released today')));
assert.ok(result.reasons.some((r) => r.includes('every 3 days')));
const oldReleaseGithub = {
rest: {
actions: {
listWorkflowRuns: async () => ({
data: {
workflow_runs: [
{
conclusion: 'success',
created_at: '2026-07-04T09:00:00Z',
status: 'completed',
},
],
},
}),
},
},
};
assert.strictEqual(
await rg.hasSuccessfulReleaseWithinDays(oldReleaseGithub, 'o', 'r', noonUtc),
false
);
console.log('ok: bumpPatch');
console.log('ok: readVersionsFromTree');
console.log('ok: pypiVersionExists missing version');
console.log('ok: utcDayStart');
console.log('ok: hasSuccessfulReleaseToday');
console.log('ok: daily dedupe blocks second release');
console.log('ok: hasSuccessfulReleaseWithinDays');
console.log('ok: 3-day dedupe blocks second release');
})();
+28 -6
View File
@@ -5,6 +5,8 @@
const https = require('https');
const PACKAGE_PATHS = ['src/praisonai', 'src/praisonai-agents', 'src/praisonai-code'];
/** Minimum days between successful patch auto-releases. */
const PATCH_RELEASE_INTERVAL_DAYS = 3;
const ACTIVE_RELEASE_STATUSES = new Set([
'queued', 'in_progress', 'waiting', 'pending', 'requested',
]);
@@ -79,8 +81,18 @@ function utcDayStart(now = new Date()) {
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
}
async function hasSuccessfulReleaseToday(github, owner, repo, now = new Date()) {
const dayStart = utcDayStart(now);
function releaseIntervalStart(now = new Date(), intervalDays = PATCH_RELEASE_INTERVAL_DAYS) {
return new Date(now.getTime() - intervalDays * 24 * 60 * 60 * 1000);
}
async function hasSuccessfulReleaseWithinDays(
github,
owner,
repo,
now = new Date(),
intervalDays = PATCH_RELEASE_INTERVAL_DAYS,
) {
const windowStart = releaseIntervalStart(now, intervalDays);
const runs = await github.rest.actions.listWorkflowRuns({
owner,
repo,
@@ -89,10 +101,15 @@ async function hasSuccessfulReleaseToday(github, owner, repo, now = new Date())
per_page: 30,
});
return runs.data.workflow_runs.some(
(r) => r.conclusion === 'success' && new Date(r.created_at) >= dayStart
(r) => r.conclusion === 'success' && new Date(r.created_at) >= windowStart
);
}
/** @deprecated Use hasSuccessfulReleaseWithinDays — kept for selftests. */
async function hasSuccessfulReleaseToday(github, owner, repo, now = new Date()) {
return hasSuccessfulReleaseWithinDays(github, owner, repo, now, 1);
}
async function lastGreenCoreTestsSha(github, owner, repo) {
const runs = await github.rest.actions.listWorkflowRuns({
owner,
@@ -135,9 +152,11 @@ async function evaluateReleasePreflight(github, owner, repo, options, core) {
}
const referenceTime = options.now instanceof Date ? options.now : new Date();
if (await hasSuccessfulReleaseToday(github, owner, repo, referenceTime)) {
const day = referenceTime.toISOString().slice(0, 10);
reasons.push(`already released today (UTC ${day}); max one patch release per day`);
if (await hasSuccessfulReleaseWithinDays(github, owner, repo, referenceTime)) {
reasons.push(
`already released within last ${PATCH_RELEASE_INTERVAL_DAYS} days; `
+ `max one patch release every ${PATCH_RELEASE_INTERVAL_DAYS} days`
);
return out;
}
@@ -222,6 +241,9 @@ module.exports = {
bumpPatch,
readVersionsFromTree,
pypiVersionExists,
PATCH_RELEASE_INTERVAL_DAYS,
releaseIntervalStart,
hasSuccessfulReleaseWithinDays,
hasSuccessfulReleaseToday,
utcDayStart,
evaluateReleasePreflight,
+8 -5
View File
@@ -49,13 +49,13 @@ jobs:
// --- Label triage ---
const labels = [];
// Kind labels
// Kind labels (bug before "how to" — bug reports often include "## How to fix")
if (content.includes('feature request') || content.includes('[feature')) {
labels.push('enhancement');
} else if (title.includes('[question]') || content.includes('how do i') || content.includes('how to')) {
labels.push('question');
} else if (content.includes('bug') || content.includes('error') || content.includes('crash') || content.includes('traceback')) {
} else if (!title.includes('[question]') && (content.includes('bug') || content.includes('error') || content.includes('crash') || content.includes('traceback'))) {
labels.push('bug');
} else if (title.includes('[question]') || content.includes('how do i') || (content.includes('how to') && !content.includes('how to fix'))) {
labels.push('question');
} else if (content.includes('question')) {
labels.push('question');
}
@@ -108,7 +108,10 @@ jobs:
// --- Auto-trigger Claude for owner issues and actionable external bug/enhancement reports ---
const titleLower = (issue.title || '').toLowerCase();
const hasActionableTitle = /^(\[[^\]]+\]|bug:|fix[:(]|feat:|ux:|enhancement:)/i.test(titleLower);
const autoClaude = isOwner || (hasActionableTitle && (labels.includes('bug') || labels.includes('enhancement')) && !labels.includes('question'));
const autoClaude = isOwner || (hasActionableTitle && (
labels.includes('bug') ||
(labels.includes('enhancement') && !labels.includes('question'))
));
if (autoClaude) {
await github.rest.issues.addLabels({
issue_number: issue.number,
+3 -3
View File
@@ -1,12 +1,12 @@
name: Nightly Release Gate
# Preflight before PyPI Release (patch bump).
# Triggers: Core Tests success on main (workflow_run) or nightly cron at 00:00 UTC.
# Dedupe: max one successful patch release per UTC day (see release-gate.js).
# Triggers: Core Tests success on main (workflow_run) or cron every 3 days at 00:00 UTC.
# Dedupe: max one successful patch release every 3 days (see release-gate.js).
on:
schedule:
- cron: '0 0 * * *'
- cron: '0 0 */3 * *'
workflow_dispatch:
inputs:
dry_run:
+181 -94
View File
@@ -61,6 +61,11 @@ on:
required: false
default: false
type: boolean
skip_deploy:
description: 'Skip praisonai-deploy publish (recovery if already on PyPI)'
required: false
default: false
type: boolean
agents_version:
description: 'Override agents version (empty = auto bump from pyproject.toml)'
required: false
@@ -101,6 +106,11 @@ on:
required: false
default: ''
type: string
deploy_version:
description: 'Override praisonai-deploy version (empty = auto bump from pyproject.toml)'
required: false
default: ''
type: string
source:
description: 'Trigger source (audit trail)'
required: false
@@ -134,15 +144,35 @@ jobs:
'pypi-auto' || 'pypi'
}}
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN || secrets.PYPI_API_TOKEN }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
# PyPI API token auth: username __token__, password = pypi-… token (see pypi.org/help/#invalid-auth)
UV_PUBLISH_USERNAME: __token__
UV_PUBLISH_PASSWORD: ${{ secrets.PYPI_TOKEN || secrets.PYPI_API_TOKEN }}
# GH_TOKEN is NOT set here: it is a GitHub App installation token minted in
# "Generate GitHub App token" and exported via $GITHUB_ENV, so releases are
# authored by praisonai-triage-agent[bot] rather than MervinPraison.
steps:
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
# Scope to this repo only. Without it the token is minted for every
# repository the owner has; this job never leaves PraisonAI (checkout,
# push to origin, and gh release create all target it).
repositories: ${{ github.event.repository.name }}
- name: Checkout main
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: main
fetch-depth: 0
token: ${{ secrets.GH_TOKEN }}
token: ${{ steps.app-token.outputs.token }}
# Do not bake the token into .git/config: an http.extraheader would
# outrank the remote URL set in "Configure git" and pin this first
# (1h) token, defeating the refresh before the wrapper release.
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
@@ -153,10 +183,19 @@ jobs:
uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4
- name: Configure git
env:
APP_TOKEN: ${{ steps.app-token.outputs.token }}
REPO: ${{ github.repository }}
run: |
git config user.name "MervinPraison"
git config user.email "[email protected]"
gh auth setup-git
set -euo pipefail
git config user.name "praisonai-triage-agent[bot]"
git config user.email "272766704+praisonai-triage-agent[bot]@users.noreply.github.com"
# persist-credentials:false left the remote unauthenticated; push auth
# comes from the app token embedded here (masked in logs, and the
# token dies with the runner).
git remote set-url origin "https://x-access-token:${APP_TOKEN}@github.com/${REPO}.git"
echo "GH_TOKEN=${APP_TOKEN}" >> "$GITHUB_ENV"
GH_TOKEN="${APP_TOKEN}" gh auth setup-git
- name: Release summary
run: |
@@ -178,6 +217,7 @@ jobs:
BROWSER_OVERRIDE: ${{ inputs.browser_version }}
MCP_OVERRIDE: ${{ inputs.mcp_version }}
SANDBOX_OVERRIDE: ${{ inputs.sandbox_version }}
DEPLOY_OVERRIDE: ${{ inputs.deploy_version }}
SKIP_AGENTS: ${{ inputs.skip_agents }}
SKIP_CODE: ${{ inputs.skip_code }}
SKIP_BOT: ${{ inputs.skip_bot }}
@@ -185,6 +225,7 @@ jobs:
SKIP_BROWSER: ${{ inputs.skip_browser }}
SKIP_MCP: ${{ inputs.skip_mcp }}
SKIP_SANDBOX: ${{ inputs.skip_sandbox }}
SKIP_DEPLOY: ${{ inputs.skip_deploy }}
run: |
python <<'PY'
import os
@@ -221,6 +262,7 @@ jobs:
browser_override = os.environ.get("BROWSER_OVERRIDE", "").strip()
mcp_override = os.environ.get("MCP_OVERRIDE", "").strip()
sandbox_override = os.environ.get("SANDBOX_OVERRIDE", "").strip()
deploy_override = os.environ.get("DEPLOY_OVERRIDE", "").strip()
validate_version("agents_version", agents_override)
validate_version("wrapper_version", wrapper_override)
validate_version("code_version", code_override)
@@ -229,6 +271,7 @@ jobs:
validate_version("browser_version", browser_override)
validate_version("mcp_version", mcp_override)
validate_version("sandbox_version", sandbox_override)
validate_version("deploy_version", deploy_override)
agents_pyproject = root / "src/praisonai-agents/pyproject.toml"
agents_content = agents_pyproject.read_text()
@@ -286,6 +329,14 @@ jobs:
sys.exit(1)
current_sandbox = sandbox_match.group(1)
deploy_pyproject = root / "src/praisonai-deploy/pyproject.toml"
deploy_content = deploy_pyproject.read_text()
deploy_match = re.search(r'^version\s*=\s*"([^"]+)"', deploy_content, re.MULTILINE)
if not deploy_match:
print("Could not read praisonai-deploy version from pyproject.toml", file=sys.stderr)
sys.exit(1)
current_deploy = deploy_match.group(1)
wrapper_version_py = root / "src/praisonai/praisonai/version.py"
wrapper_content = wrapper_version_py.read_text()
wrapper_match = re.search(r'__version__ = "([^"]+)"', wrapper_content)
@@ -302,6 +353,7 @@ jobs:
("browser", current_browser),
("mcp", current_mcp),
("sandbox", current_sandbox),
("deploy", current_deploy),
("wrapper", current_wrapper),
):
if not SEMVER.match(value):
@@ -315,6 +367,7 @@ jobs:
skip_browser = os.environ.get("SKIP_BROWSER", "false").lower() == "true"
skip_mcp = os.environ.get("SKIP_MCP", "false").lower() == "true"
skip_sandbox = os.environ.get("SKIP_SANDBOX", "false").lower() == "true"
skip_deploy = os.environ.get("SKIP_DEPLOY", "false").lower() == "true"
if agents_override:
agents_version = agents_override
@@ -365,6 +418,13 @@ jobs:
else:
sandbox_version = bump_version(current_sandbox)
if deploy_override:
deploy_version = deploy_override
elif skip_deploy:
deploy_version = current_deploy
else:
deploy_version = bump_version(current_deploy)
if wrapper_override:
wrapper_version = wrapper_override
else:
@@ -379,6 +439,7 @@ jobs:
fh.write(f"browser_version={browser_version}\n")
fh.write(f"mcp_version={mcp_version}\n")
fh.write(f"sandbox_version={sandbox_version}\n")
fh.write(f"deploy_version={deploy_version}\n")
fh.write(f"wrapper_version={wrapper_version}\n")
fh.write(f"current_agents={current_agents}\n")
fh.write(f"current_code={current_code}\n")
@@ -387,6 +448,7 @@ jobs:
fh.write(f"current_browser={current_browser}\n")
fh.write(f"current_mcp={current_mcp}\n")
fh.write(f"current_sandbox={current_sandbox}\n")
fh.write(f"current_deploy={current_deploy}\n")
fh.write(f"current_wrapper={current_wrapper}\n")
print(f"Agents: {current_agents} -> {agents_version}")
@@ -396,6 +458,7 @@ jobs:
print(f"Browser: {current_browser} -> {browser_version}")
print(f"MCP: {current_mcp} -> {mcp_version}")
print(f"Sandbox: {current_sandbox} -> {sandbox_version}")
print(f"Deploy: {current_deploy} -> {deploy_version}")
print(f"Wrapper: {current_wrapper} -> {wrapper_version}")
PY
@@ -410,6 +473,7 @@ jobs:
BROWSER_VERSION: ${{ steps.versions.outputs.browser_version }}
MCP_VERSION: ${{ steps.versions.outputs.mcp_version }}
SANDBOX_VERSION: ${{ steps.versions.outputs.sandbox_version }}
DEPLOY_VERSION: ${{ steps.versions.outputs.deploy_version }}
WRAPPER_VERSION: ${{ steps.versions.outputs.wrapper_version }}
INPUT_SKIP_AGENTS: ${{ inputs.skip_agents }}
INPUT_SKIP_CODE: ${{ inputs.skip_code }}
@@ -418,6 +482,7 @@ jobs:
INPUT_SKIP_BROWSER: ${{ inputs.skip_browser }}
INPUT_SKIP_MCP: ${{ inputs.skip_mcp }}
INPUT_SKIP_SANDBOX: ${{ inputs.skip_sandbox }}
INPUT_SKIP_DEPLOY: ${{ inputs.skip_deploy }}
INPUT_SKIP_WRAPPER: ${{ inputs.skip_wrapper }}
run: |
set -euo pipefail
@@ -428,6 +493,7 @@ jobs:
skip_browser="${INPUT_SKIP_BROWSER}"
skip_mcp="${INPUT_SKIP_MCP}"
skip_sandbox="${INPUT_SKIP_SANDBOX}"
skip_deploy="${INPUT_SKIP_DEPLOY}"
skip_wrapper="${INPUT_SKIP_WRAPPER}"
if [ "$skip_agents" != "true" ]; then
curl -fsSL "https://pypi.org/pypi/praisonaiagents/${AGENTS_VERSION}/json" >/dev/null && skip_agents=true || true
@@ -450,6 +516,9 @@ jobs:
if [ "$skip_sandbox" != "true" ]; then
curl -fsSL "https://pypi.org/pypi/praisonai-sandbox/${SANDBOX_VERSION}/json" >/dev/null && skip_sandbox=true || true
fi
if [ "$skip_deploy" != "true" ]; then
curl -fsSL "https://pypi.org/pypi/praisonai-deploy/${DEPLOY_VERSION}/json" >/dev/null && skip_deploy=true || true
fi
if [ "$skip_wrapper" != "true" ]; then
curl -fsSL "https://pypi.org/pypi/praisonai/${WRAPPER_VERSION}/json" >/dev/null && skip_wrapper=true || true
fi
@@ -460,8 +529,9 @@ jobs:
echo "skip_browser=${skip_browser}" >> "$GITHUB_OUTPUT"
echo "skip_mcp=${skip_mcp}" >> "$GITHUB_OUTPUT"
echo "skip_sandbox=${skip_sandbox}" >> "$GITHUB_OUTPUT"
echo "skip_deploy=${skip_deploy}" >> "$GITHUB_OUTPUT"
echo "skip_wrapper=${skip_wrapper}" >> "$GITHUB_OUTPUT"
if [ "$skip_agents" = "true" ] && [ "$skip_code" = "true" ] && [ "$skip_bot" = "true" ] && [ "$skip_train" = "true" ] && [ "$skip_browser" = "true" ] && [ "$skip_mcp" = "true" ] && [ "$skip_sandbox" = "true" ] && [ "$skip_wrapper" = "true" ]; then
if [ "$skip_agents" = "true" ] && [ "$skip_code" = "true" ] && [ "$skip_bot" = "true" ] && [ "$skip_train" = "true" ] && [ "$skip_browser" = "true" ] && [ "$skip_mcp" = "true" ] && [ "$skip_sandbox" = "true" ] && [ "$skip_deploy" = "true" ] && [ "$skip_wrapper" = "true" ]; then
echo "All target versions already on PyPI — nothing to publish."
fi
@@ -475,6 +545,7 @@ jobs:
steps.pypi_exists.outputs.skip_browser == 'true' &&
steps.pypi_exists.outputs.skip_mcp == 'true' &&
steps.pypi_exists.outputs.skip_sandbox == 'true' &&
steps.pypi_exists.outputs.skip_deploy == 'true' &&
steps.pypi_exists.outputs.skip_wrapper == 'true'
run: echo "Idempotent skip — target versions already on PyPI."
@@ -566,19 +637,6 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit agents version bump
if: >-
inputs.dry_run != true &&
inputs.skip_agents != true &&
steps.pypi_exists.outputs.skip_agents != 'true'
run: |
set -euo pipefail
git add src/praisonai-agents/pyproject.toml src/praisonai-agents/uv.lock
git diff --cached --quiet && { echo "No agents files to commit"; exit 0; }
git commit -m "Bump praisonaiagents to ${{ steps.versions.outputs.agents_version }}"
git pull --rebase origin main
git push origin main
- name: Publish praisonai-code
if: >-
inputs.dry_run != true &&
@@ -636,19 +694,6 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit praisonai-code version bump
if: >-
inputs.dry_run != true &&
inputs.skip_code != true &&
steps.pypi_exists.outputs.skip_code != 'true'
run: |
set -euo pipefail
git add src/praisonai-code/pyproject.toml src/praisonai-code/uv.lock src/praisonai-code/praisonai_code/__init__.py
git diff --cached --quiet && { echo "No code files to commit"; exit 0; }
git commit -m "Bump praisonai-code to ${{ steps.versions.outputs.code_version }}"
git pull --rebase origin main
git push origin main
- name: Publish praisonai-bot
if: >-
inputs.dry_run != true &&
@@ -706,19 +751,6 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit praisonai-bot version bump
if: >-
inputs.dry_run != true &&
inputs.skip_bot != true &&
steps.pypi_exists.outputs.skip_bot != 'true'
run: |
set -euo pipefail
git add src/praisonai-bot/pyproject.toml src/praisonai-bot/uv.lock src/praisonai-bot/praisonai_bot/_version.py
git diff --cached --quiet && { echo "No bot files to commit"; exit 0; }
git commit -m "Bump praisonai-bot to ${{ steps.versions.outputs.bot_version }}"
git pull --rebase origin main
git push origin main
- name: Publish praisonai-train
if: >-
inputs.dry_run != true &&
@@ -776,19 +808,6 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit praisonai-train version bump
if: >-
inputs.dry_run != true &&
inputs.skip_train != true &&
steps.pypi_exists.outputs.skip_train != 'true'
run: |
set -euo pipefail
git add src/praisonai-train/pyproject.toml src/praisonai-train/uv.lock src/praisonai-train/praisonai_train/_version.py
git diff --cached --quiet && { echo "No train files to commit"; exit 0; }
git commit -m "Bump praisonai-train to ${{ steps.versions.outputs.train_version }}"
git pull --rebase origin main
git push origin main
- name: Publish praisonai-browser
if: >-
inputs.dry_run != true &&
@@ -846,19 +865,6 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit praisonai-browser version bump
if: >-
inputs.dry_run != true &&
inputs.skip_browser != true &&
steps.pypi_exists.outputs.skip_browser != 'true'
run: |
set -euo pipefail
git add src/praisonai-browser/pyproject.toml src/praisonai-browser/uv.lock src/praisonai-browser/praisonai_browser/_version.py
git diff --cached --quiet && { echo "No browser files to commit"; exit 0; }
git commit -m "Bump praisonai-browser to ${{ steps.versions.outputs.browser_version }}"
git pull --rebase origin main
git push origin main
- name: Publish praisonai-mcp
if: >-
inputs.dry_run != true &&
@@ -916,19 +922,6 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit praisonai-mcp version bump
if: >-
inputs.dry_run != true &&
inputs.skip_mcp != true &&
steps.pypi_exists.outputs.skip_mcp != 'true'
run: |
set -euo pipefail
git add src/praisonai-mcp/pyproject.toml src/praisonai-mcp/uv.lock src/praisonai-mcp/praisonai_mcp/_version.py
git diff --cached --quiet && { echo "No mcp files to commit"; exit 0; }
git commit -m "Bump praisonai-mcp to ${{ steps.versions.outputs.mcp_version }}"
git pull --rebase origin main
git push origin main
- name: Publish praisonai-sandbox
if: >-
inputs.dry_run != true &&
@@ -986,18 +979,89 @@ jobs:
sleep "$INTERVAL"
done
- name: Commit praisonai-sandbox version bump
- name: Publish praisonai-deploy
if: >-
inputs.dry_run != true &&
inputs.skip_sandbox != true &&
steps.pypi_exists.outputs.skip_sandbox != 'true'
inputs.skip_deploy != true &&
steps.pypi_exists.outputs.skip_deploy != 'true'
working-directory: src/praisonai-deploy
env:
NEW_VERSION: ${{ steps.versions.outputs.deploy_version }}
CURRENT: ${{ steps.versions.outputs.current_deploy }}
run: |
set -euo pipefail
git add src/praisonai-sandbox/pyproject.toml src/praisonai-sandbox/uv.lock src/praisonai-sandbox/praisonai_sandbox/_version.py
git diff --cached --quiet && { echo "No sandbox files to commit"; exit 0; }
git commit -m "Bump praisonai-sandbox to ${{ steps.versions.outputs.sandbox_version }}"
git pull --rebase origin main
git push origin main
python <<'PY'
import os
import re
from pathlib import Path
new = os.environ["NEW_VERSION"]
current = os.environ["CURRENT"]
pyproject = Path("pyproject.toml")
content = pyproject.read_text()
pyproject.write_text(content.replace(f'version = "{current}"', f'version = "{new}"', 1))
version_py = Path("praisonai_deploy/_version.py")
version_content = version_py.read_text()
version_py.write_text(re.sub(r'__version__ = "[^"]+"', f'__version__ = "{new}"', version_content, count=1))
PY
rm -rf dist
uv lock
uv build
uv publish
- name: Wait for praisonai-deploy on PyPI
if: >-
inputs.dry_run != true &&
inputs.skip_deploy != true &&
steps.pypi_exists.outputs.skip_deploy != 'true'
run: |
set -euo pipefail
PACKAGE="praisonai-deploy"
VERSION="${{ steps.versions.outputs.deploy_version }}"
MAX_WAIT=600
INTERVAL=30
START=$(date +%s)
while true; do
if curl -fsSL "https://pypi.org/pypi/${PACKAGE}/${VERSION}/json" >/dev/null; then
echo "✅ ${PACKAGE}==${VERSION} is available on PyPI"
exit 0
fi
ELAPSED=$(( $(date +%s) - START ))
if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then
echo "❌ Timeout waiting for ${PACKAGE}==${VERSION} on PyPI"
exit 1
fi
echo "⏳ Waiting for ${PACKAGE}==${VERSION} ($(( MAX_WAIT - ELAPSED ))s remaining...)"
sleep "$INTERVAL"
done
# All per-package version bumps are still uncommitted at this point: the
# wrapper release below stages every one of them (bump_and_release.py's
# release_files list) into a SINGLE "Release v…" commit.
# App tokens expire after 1h and this job can exceed that (9 packages ×
# up to a 600s PyPI wait). Re-mint so the final commit/tag/push/release
# never runs on an expired token.
- name: Refresh GitHub App token
id: app-token-final
if: ${{ !cancelled() && inputs.dry_run != true }}
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ github.event.repository.name }}
- name: Use refreshed GitHub App token
if: ${{ !cancelled() && inputs.dry_run != true }}
env:
APP_TOKEN: ${{ steps.app-token-final.outputs.token }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
git remote set-url origin "https://x-access-token:${APP_TOKEN}@github.com/${REPO}.git"
echo "GH_TOKEN=${APP_TOKEN}" >> "$GITHUB_ENV"
- name: Bump and release wrapper
if: >-
@@ -1014,7 +1078,8 @@ jobs:
--browser-pin "${{ steps.versions.outputs.browser_version }}" \
--mcp-pin "${{ steps.versions.outputs.mcp_version }}" \
--sandbox-pin "${{ steps.versions.outputs.sandbox_version }}" \
--wait --max-wait 600 --no-add-all
--deploy-pin "${{ steps.versions.outputs.deploy_version }}" \
--wait --max-wait 600 --no-add-all --force
- name: Publish praisonai wrapper to PyPI
if: >-
@@ -1062,6 +1127,7 @@ jobs:
BROWSER="${{ steps.versions.outputs.browser_version }}"
MCP="${{ steps.versions.outputs.mcp_version }}"
SANDBOX="${{ steps.versions.outputs.sandbox_version }}"
DEPLOY="${{ steps.versions.outputs.deploy_version }}"
WRAPPER="${{ steps.versions.outputs.wrapper_version }}"
if [ "${{ inputs.skip_agents }}" != "true" ]; then
@@ -1092,6 +1158,27 @@ jobs:
echo "✅ praisonai-sandbox==${SANDBOX}"
fi
if [ "${{ inputs.skip_deploy }}" != "true" ]; then
echo "✅ praisonai-deploy==${DEPLOY}"
fi
if [ "${{ inputs.skip_wrapper }}" != "true" ]; then
echo "✅ praisonai==${WRAPPER}"
fi
# Safety net. On a clean run the wrapper's "Release v…" commit already
# carries every bump and this is a no-op. It only fires when the single
# commit could not happen: a package publish failed midway (those versions
# are already live on PyPI, so the bumps must not be lost), skip_wrapper
# was set, or the wrapper itself failed.
- name: Persist any uncommitted version bumps
if: ${{ !cancelled() && inputs.dry_run != true }}
run: |
set -euo pipefail
# -u = tracked modifications only; uv build output under dist/ is
# untracked and stays out of the commit.
git add -u
git diff --cached --quiet && { echo "Nothing left to commit"; exit 0; }
git commit -m "chore(release): persist version bumps [skip ci]"
git pull --rebase origin main
git push origin main
+38 -4
View File
@@ -5,6 +5,9 @@ on:
branches: [ main, develop ]
paths:
- 'src/**'
- 'src/praisonai-deploy/infra/**'
- 'src/praisonai-bot/infra/**'
- 'scripts/check_helm_charts.sh'
- 'pyproject.toml'
- '.github/workflows/test-core.yml'
- '.github/actions/install-monorepo-packages/**'
@@ -12,6 +15,9 @@ on:
branches: [ main, develop ]
paths:
- 'src/**'
- 'src/praisonai-deploy/infra/**'
- 'src/praisonai-bot/infra/**'
- 'scripts/check_helm_charts.sh'
- 'pyproject.toml'
- '.github/workflows/test-core.yml'
- '.github/actions/install-monorepo-packages/**'
@@ -114,11 +120,17 @@ jobs:
extra_ignore: ""
pythonpath: >-
${{ github.workspace }}/src/praisonai-agents
- shard: deploy
workdir: src/praisonai-deploy
paths: >-
tests/
extra_ignore: ""
pythonpath: >-
${{ github.workspace }}/src/praisonai-agents
- shard: subdirs
paths: >-
tests/unit/scheduler/
tests/unit/integrations/
tests/unit/deploy/
tests/unit/mcp/
tests/unit/knowledge/
tests/unit/llm/
@@ -183,6 +195,9 @@ jobs:
if [ "$WORKDIR" = "src/praisonai-sandbox" ]; then
bash "$GITHUB_WORKSPACE/scripts/check_c13_sandbox_imports.sh"
fi
if [ "$WORKDIR" = "src/praisonai-deploy" ]; then
bash "$GITHUB_WORKSPACE/scripts/check_c14_deploy_imports.sh"
fi
if [ "$WORKDIR" = "src/praisonai-mcp" ]; then
bash "$GITHUB_WORKSPACE/scripts/check_c12_mcp_imports.sh"
fi
@@ -268,9 +283,27 @@ jobs:
--ignore=tests/integration/test_tracker_complex_tasks.py \
--ignore=tests/integration/test_serve_integration.py
helm-charts:
name: helm-charts
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: v3.14.4
- name: Lint and template Helm charts
shell: bash
run: |
set -euo pipefail
bash "$GITHUB_WORKSPACE/scripts/check_helm_charts.sh"
test-core:
name: test-core
needs: [test-core-collect, test-core-unit, test-core-integration]
needs: [test-core-collect, test-core-unit, test-core-integration, helm-charts]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
@@ -282,8 +315,9 @@ jobs:
collect='${{ needs.test-core-collect.result }}'
unit='${{ needs.test-core-unit.result }}'
integration='${{ needs.test-core-integration.result }}'
echo "collect=$collect unit=$unit integration=$integration"
if [ "$collect" != "success" ] || [ "$unit" != "success" ] || [ "$integration" != "success" ]; then
helm='${{ needs.helm-charts.result }}'
echo "collect=$collect unit=$unit integration=$integration helm=$helm"
if [ "$collect" != "success" ] || [ "$unit" != "success" ] || [ "$integration" != "success" ] || [ "$helm" != "success" ]; then
echo "Core Tests failed"
exit 1
fi
+21 -1
View File
@@ -86,6 +86,7 @@ jobs:
tests/unit/test_c11_browser_backward_compat.py \
tests/unit/test_c12_mcp_backward_compat.py \
tests/unit/test_c13_sandbox_backward_compat.py \
tests/unit/test_c14_deploy_backward_compat.py \
-q --tb=line --timeout=30 --maxfail=5
python -m pytest tests/unit/cli/ \
../praisonai-bot/tests/unit/cli/test_onboard_command.py \
@@ -269,10 +270,26 @@ jobs:
bash "$GITHUB_WORKSPACE/scripts/check_c13_sandbox_imports.sh"
python -m pytest src/praisonai-sandbox/tests -q -m "not network"
- name: Standalone praisonai-deploy smoke (C14)
run: |
set -euo pipefail
python -m venv /tmp/praisonai-deploy-standalone
/tmp/praisonai-deploy-standalone/bin/pip install -q -e src/praisonai-agents -e src/praisonai-deploy
/tmp/praisonai-deploy-standalone/bin/python -c "
from praisonai_deploy._version import __version__ as pkg_version
import praisonai_deploy
assert praisonai_deploy.__version__ == pkg_version
assert 'main' not in __import__('sys').modules
print('deploy standalone ok', praisonai_deploy.__version__)
"
/tmp/praisonai-deploy-standalone/bin/praisonai-deploy --help
bash "$GITHUB_WORKSPACE/scripts/check_c14_deploy_imports.sh"
python -m pytest src/praisonai-deploy/tests -q -m "not network"
- name: Audit hybrid module imports (C8 full stack)
run: |
set -euo pipefail
pip install -q -e src/praisonai-agents -e src/praisonai-code -e src/praisonai-bot -e src/praisonai-train -e src/praisonai-browser -e src/praisonai-mcp -e src/praisonai-sandbox -e src/praisonai
pip install -q -e src/praisonai-agents -e src/praisonai-code -e src/praisonai-bot -e src/praisonai-train -e src/praisonai-browser -e src/praisonai-mcp -e src/praisonai-sandbox -e src/praisonai-deploy -e src/praisonai
python scripts/audit_hybrid_modules.py
- name: Smoke Test Summary
@@ -782,6 +799,9 @@ jobs:
tests/unit/test_decorator_simple.py
tests/unit/test_db_adapter_tracing_init.py
../praisonai-bot/tests/unit/test_bot_wiring.py
../praisonai-bot/tests/unit/bots/test_enable_shell.py
../praisonai-bot/tests/unit/gateway/test_preflight.py
../praisonai-bot/tests/unit/gateway/test_gateway_doctor.py
../praisonai-bot/tests/unit/test_bot_history.py
../praisonai-bot/tests/unit/test_bot_fixes.py
tests/unit/test_auto_lazy_loading.py
+9
View File
@@ -29,6 +29,15 @@ output
threads.db
threads.db-journal
# Example run artifacts (generated at runtime, must not be committed)
examples/**/knowledge.db
examples/**/knowledge.db-journal
examples/python/managed-agents/managed_ids.json
examples/python/save_output/blog_post.md
examples/python/save_output/generated/
examples/python/token-metrics/token_metrics_export.json
examples/python/usecases/market_research_results.json
.chainlit
!praisonai/ui/config/.chainlit
+2 -2
View File
@@ -7,9 +7,9 @@ You are working on the PraisonAI project.
- Be concise and helpful in responses
- Test implementation thoroughly
- Ensure backward compatibility with existing APIs
- Follow protocol-driven design across the eight packages: core protocols in `praisonaiagents/`, agentic terminal CLI in `praisonai-code/`, bots/gateway in `praisonai-bot/`, LLM fine-tuning + agent training in `praisonai-train/`, browser automation in `praisonai-browser/`, MCP server host in `praisonai-mcp/`, sandbox backends in `praisonai-sandbox/`, integrations/serve/dashboard in the `praisonai/` wrapper
- Follow protocol-driven design across the nine packages: core protocols in `praisonaiagents/`, agentic terminal CLI in `praisonai-code/`, bots/gateway in `praisonai-bot/`, LLM fine-tuning + agent training in `praisonai-train/`, browser automation in `praisonai-browser/`, MCP server host in `praisonai-mcp/`, sandbox backends in `praisonai-sandbox/`, deployment in `praisonai-deploy/`, integrations/serve/dashboard in the `praisonai/` wrapper
- Preserve old `praisonai.*` import paths via shims when moving code between packages (see §2.3 in `src/praisonai-agents/AGENTS.md`; shim helpers in `src/praisonai/praisonai/cli/_shim.py`)
- Package boundaries and dependency rules: `ARCHITECTURE.md` §2 (Tier 2 packages must never PyPI-depend on the wrapper; cross-tier access goes through lazy `_*_bridge` modules)
- Boundary manifests: `src/praisonai/tests/PRAISONAI_BOT_MANIFEST.md` (C9), `src/praisonai/tests/PRAISONAI_TRAIN_MANIFEST.md` (C10), `src/praisonai/tests/PRAISONAI_BROWSER_MANIFEST.md` (C11), `src/praisonai/tests/PRAISONAI_MCP_MANIFEST.md` (C12), `src/praisonai/tests/PRAISONAI_SANDBOX_MANIFEST.md` (C13)
- Boundary manifests: `src/praisonai/tests/PRAISONAI_BOT_MANIFEST.md` (C9), `src/praisonai/tests/PRAISONAI_TRAIN_MANIFEST.md` (C10), `src/praisonai/tests/PRAISONAI_BROWSER_MANIFEST.md` (C11), `src/praisonai/tests/PRAISONAI_MCP_MANIFEST.md` (C12), `src/praisonai/tests/PRAISONAI_SANDBOX_MANIFEST.md` (C13), `src/praisonai/tests/PRAISONAI_DEPLOY_MANIFEST.md` (C14)
- When reviewing a PR or an issue, evaluate whether the change addresses a framework concern or a user goal, and design its surface (params, naming, defaults) accordingly
- The aim of this package is to stay **lightweight and powerful**. Do a critical review at each stage — when triaging an issue, when planning a fix, and when reviewing/implementing a PR. Reject scope creep for the sake of adding features: if a capability already exists (e.g. via existing Agent params like `instructions`/`backstory`/`tools`/`hooks`/`memory`), prefer it over a new API surface. A change must genuinely strengthen the SDK (simpler, more robust, more user-friendly) — do not add knobs, params, modules, or exports that have no live consumer or that merely duplicate existing behaviour.
+29 -10
View File
@@ -1,6 +1,6 @@
# PraisonAI Architecture
> **Last updated:** 2026-07-17 (C13 — eight-package tiered model)
> **Last updated:** 2026-07-31 (C14 — nine-package tiered model)
>
> Strategic architecture document for PraisonAI — a multi-agent AI framework.
> Covers **Python tiered package model (C7.1 + C9 + C10)**, system design, runtime
@@ -11,7 +11,7 @@
## Table of Contents
1. [Executive Summary](#1-executive-summary)
2. [Python Tiered Package Model (C7.1 + C9 + C10 + C11 + C12 + C13)](#2-python-tiered-package-model-c71--c9--c10--c11--c12--c13)
2. [Python Tiered Package Model (C7.1 + C9 + C10 + C11 + C12 + C13 + C14)](#2-python-tiered-package-model-c71--c9--c10--c11--c12--c13--c14)
3. [System Overview](#3-system-overview)
4. [Layered Architecture](#4-layered-architecture)
5. [Core Data Contracts](#5-core-data-contracts)
@@ -51,17 +51,18 @@ Orchestration + Observability** core to unlock adoption and trust:
---
## 2. Python Tiered Package Model (C7.1 + C9 + C10 + C11 + C12 + C13)
## 2. Python Tiered Package Model (C7.1 + C9 + C10 + C11 + C12 + C13 + C14)
**Release:** v4.6.110+ · `praisonaiagents` · `praisonai-code` · `praisonai-bot` · `praisonai-train` · `praisonai-browser` · `praisonai-mcp` · `praisonai-sandbox` · `praisonai`
**Release:** v4.6.110+ · `praisonaiagents` · `praisonai-code` · `praisonai-bot` · `praisonai-train` · `praisonai-browser` · `praisonai-mcp` · `praisonai-sandbox` · `praisonai-deploy` · `praisonai`
The Python monorepo publishes eight packages in three tiers with strict dependency
The Python monorepo publishes nine packages in three tiers with strict dependency
direction. C7 delivered a standalone agentic hot path; C7.1 formalised
code/wrapper ownership; C9 extracted bots, gateway, and channel CLI into
`praisonai-bot`; C10 extracted LLM fine-tuning and agent training into
`praisonai-train`; C11 extracted browser automation into `praisonai-browser`;
C12 extracted the heavy MCP host into `praisonai-mcp`.
C13 extracted sandbox backends into `praisonai-sandbox`.
C14 extracted deployment (API, Docker, cloud) into `praisonai-deploy`.
```mermaid
flowchart TB
@@ -69,13 +70,14 @@ flowchart TB
Agents["praisonaiagents<br/>Agent, tools, memory, hooks, protocols"]
end
subgraph tier2 [Tier 2 — Terminal + Bot + Train + Browser + MCP + Sandbox]
subgraph tier2 [Tier 2 — Terminal + Bot + Train + Browser + MCP + Sandbox + Deploy]
Code["praisonai-code<br/>run, chat, code, Typer, runtime, LLM"]
Bot["praisonai-bot<br/>bots, gateway, channel CLI, OS daemon"]
Train["praisonai-train<br/>LLM fine-tuning, agent training"]
Browser["praisonai-browser<br/>extension bridge, CDP, Playwright"]
MCP["praisonai-mcp<br/>MCP server host, auth, capability adapters"]
Sandbox["praisonai-sandbox<br/>Docker, E2B, Modal, Sandlock backends"]
Deploy["praisonai-deploy<br/>API, Docker, AWS/Azure/GCP deploy"]
end
subgraph tier3 [Tier 3 — Wrapper]
@@ -88,36 +90,53 @@ flowchart TB
Agents --> Browser
Agents --> MCP
Agents --> Sandbox
Agents --> Deploy
Agents --> Wrapper
Code -.->|"lazy _bot_bridge"| Bot
Code -.->|"lazy _train_bridge"| Train
Code -.->|"lazy _browser_bridge"| Browser
Code -.->|"lazy _mcp_bridge"| MCP
Code -.->|"lazy _sandbox_bridge"| Sandbox
Code -.->|"lazy _deploy_bridge"| Deploy
Code -.->|"lazy _wrapper_bridge"| Wrapper
Bot -.->|"lazy _code_bridge / _wrapper_bridge"| Code
Bot -.->|"lazy _wrapper_bridge"| Wrapper
Train -.->|"lazy _code_bridge / _wrapper_bridge"| Code
```
**PyPI publish order:** `praisonaiagents` → `praisonai-code` + `praisonai-bot` + `praisonai-train` + `praisonai-browser` + `praisonai-mcp` + `praisonai-sandbox` → `praisonai`
**PyPI publish order:** `praisonaiagents` → `praisonai-code` + `praisonai-bot` + `praisonai-train` + `praisonai-browser` + `praisonai-mcp` + `praisonai-sandbox` + `praisonai-deploy` → `praisonai`
**Backward compatibility:** `praisonai.bots`, `praisonai.gateway`, `praisonai.train`,
`praisonai.browser`, `praisonai.mcp_server`, `praisonai.sandbox`, and related CLI paths remain as
`praisonai.browser`, `praisonai.mcp_server`, `praisonai.sandbox`, `praisonai.deploy`, and related CLI paths remain as
`alias_package` shims to `praisonai_bot.*` / `praisonai_train.*` /
`praisonai_browser.*` / `praisonai_mcp.*` / `praisonai_sandbox.*`.
`praisonai_browser.*` / `praisonai_mcp.*` / `praisonai_sandbox.*` / `praisonai_deploy.*`.
| Tier | Package | Owns | Must not depend on |
|------|---------|------|-------------------|
| 1 | `src/praisonai-agents/` | Agent, tools, memory, hooks, `frameworks/` protocols, sandbox protocols | `praisonai`, `praisonai-code`, `praisonai-bot`, `praisonai-train`, `praisonai-browser`, `praisonai-mcp`, `praisonai-sandbox` |
| 1 | `src/praisonai-agents/` | Agent, tools, memory, hooks, `frameworks/` protocols, sandbox protocols | `praisonai`, `praisonai-code`, `praisonai-bot`, `praisonai-train`, `praisonai-browser`, `praisonai-mcp`, `praisonai-sandbox`, `praisonai-deploy` |
| 2a | `src/praisonai-code/` | `run`/`chat`/`code`, Typer, runtime, LLM, tool resolution | **`praisonai` as a PyPI dependency** (optional lazy imports via `_wrapper_bridge` only) |
| 2b | `src/praisonai-bot/` | Bots, gateway, channel CLI, OS daemon, gateway scheduler tick | **`praisonai` as a PyPI dependency** (optional lazy `_wrapper_bridge` for jobs/UI) |
| 2c | `src/praisonai-train/` | LLM fine-tuning (Unsloth), agent training, `train` CLI, conda env setup | **`praisonai` as a PyPI dependency** (lazy `_code_bridge` for legacy dispatch) |
| 2d | `src/praisonai-browser/` | Extension bridge, CDP/hybrid automation, `browser` CLI | **`praisonai` as a PyPI dependency** (none required; depends on `praisonaiagents` only) |
| 2e | `src/praisonai-mcp/` | MCP server host, auth, transports, `mcp` CLI | **`praisonai` as a PyPI dependency** (lazy `_wrapper_bridge` for full capability registry) |
| 2f | `src/praisonai-sandbox/` | Sandbox backends (Docker, E2B, Modal, Sandlock, SSH), `SandboxRegistry` | **`praisonai` as a PyPI dependency** (lazy `_code_bridge` for `PluginRegistry`) |
| 2g | `src/praisonai-deploy/` | Deploy API/Docker/cloud, `deploy` CLI, scheduler integration | **`praisonai` as a PyPI dependency** (lazy `_plugin_registry` via `_code_bridge`) |
| 3 | `src/praisonai/` | `framework_adapters/`, serve, dashboard, async jobs API | — |
### Repo infra (not PyPI)
Deployment packaging that stays in the git checkout, not in any tier-2 wheel:
| Path | Runtime owner | Orchestration |
|------|---------------|---------------|
| `src/praisonai-bot/infra/helm/praisonai-gateway/` | `praisonai-bot` (gateway) | C14 `deploy helm` wrapper |
| `src/praisonai-deploy/infra/helm/praisonai-agents-api/` | Generated API from C14 | C14 cross-link |
| `src/praisonai-deploy/infra/compose/agents-stack/` | Docker Compose | `praisonai deploy compose up/down` |
| `src/praisonai-deploy/infra/starters/` | Starter scaffolds | `praisonai deploy create --template` |
| `docker/` | Mixed (wrapper/bot dev stacks) | Not C14 — see bot manifest for `docker/bots/` |
Same boundary as C14: Helm/K8s manifests are **repo infra**, not `pip install praisonai-deploy` content.
**Config kernel:** Phase 0 `praisonai/common/` was skipped; shared config lives in
`praisonai_code/cli/configuration/` and is reached by the bot tier via lazy
`_code_bridge` (see `src/praisonai/tests/CONFIG_KERNEL.md`).
+8 -9
View File
@@ -83,6 +83,7 @@ Methods:
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run_autonomous_async</a>(prompt: str, max_iterations: Optional[int] = None, timeout_seconds: Optional[float] = None, completion_promise: Optional[str] = None, clear_context: bool = False)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run_until</a>(prompt: str, criteria: str = '', threshold: float = 8.0, max_iterations: int = 5, mode: str = 'optimize', on_iteration: Optional[Callable[[Any], None]] = None, verbose: bool = False, goal: Optional[str] = None, goal_criteria: Optional[Any] = None, judge_model: Optional[str] = None) -> 'EvaluationLoopResult'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run_until_async</a>(prompt: str, criteria: str, threshold: float = 8.0, max_iterations: int = 5, mode: str = 'optimize', on_iteration: Optional[Callable[[Any], None]] = None, verbose: bool = False) -> 'EvaluationLoopResult'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">set_snapshot_root</a>(project_path: str) -> bool</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">skill_manager</a>() -> Optional[Any]</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">store_memory</a>(content: str, memory_type: str = 'short_term', action: str = 'add', **kwargs: Any) -> None</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">stream_emitter</a>() -> Optional[Any]</code>
@@ -232,13 +233,6 @@ Methods:
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">repeat</a>(step: Any, until: Optional[Callable[[WorkflowContext], bool]] = None, max_iterations: int = 10) -> Repeat</code>
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">route</a>(routes: Dict[str, List], default: Optional[List] = None) -> Route</code>
# DB
Types:
```python
from praisonaiagents import db
```
# Memory
Types:
@@ -575,6 +569,7 @@ Methods:
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">get_prompts</a>() -> List[dict]</code>
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">get_resources</a>() -> List[dict]</code>
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">get_tools</a>() -> List[Callable]</code>
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">list_active_server_names</a>() -> set</code>
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">shutdown</a>()</code>
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">to_openai_tool</a>()</code>
* <code title="class MCP">MCP.<a href="./src/praisonai-agents/praisonaiagents/mcp/mcp.py">with_tool_prefix</a>(prefix: str) -> 'MCP'</code>
@@ -738,7 +733,7 @@ Methods:
Types:
```python
from praisonaiagents import AgentAppConfig, AgentAppProtocol, AgentFlow, AgentManager, AgentOSConfig, AgentOSProtocol, AgentTeam, AutoApproveBackend, EmbeddingResult, RetryBackoffConfig, __version__, aembedding, aembeddings, embedding, embeddings, get_dimensions
from praisonaiagents import AgentAppConfig, AgentAppProtocol, AgentFlow, AgentManager, AgentOSConfig, AgentOSProtocol, AgentTeam, AutoApproveBackend, EmbeddingResult, RetryBackoffConfig, RunOutcome, __version__, aembedding, aembeddings, embedding, embeddings, get_dimensions
```
Methods:
@@ -806,12 +801,16 @@ Methods:
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">set_state</a>(key: str, value: Any) -> None</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">spawn_sub_agent</a>(agent: Agent, task: Any, completion_callback: Optional[Callable[[SubAgentCompletionEvent], Any]] = None, metadata: Optional[Dict[str, Any]] = None) -> SpawnedSubAgent</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">start</a>(content = None, return_dict = False, output = None, **kwargs)</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">stream_emitter</a>()</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">todo_list</a>()</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">update_plan_step_status</a>(step_id: str, status: str) -> bool</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">update_state</a>(updates: Dict) -> None</code>
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">wait_for_completions</a>(timeout: Optional[float] = None, agent_ids: Optional[List[str]] = None) -> List[SubAgentCompletionEvent]</code>
* <code title="class AutoApproveBackend">AutoApproveBackend.<a href="./src/praisonai-agents/praisonaiagents/approval/backends.py">request_approval</a>(request: ApprovalRequest) -> ApprovalDecision</code>
* <code title="class AutoApproveBackend">AutoApproveBackend.<a href="./src/praisonai-agents/praisonaiagents/approval/backends.py">request_approval_sync</a>(request: ApprovalRequest) -> ApprovalDecision</code>
* <code title="class RunOutcome">RunOutcome.<a href="./src/praisonai-agents/praisonaiagents/agent/run_outcome.py">completed</a>(output: Optional[str] = None) -> 'RunOutcome'</code>
* <code title="class RunOutcome">RunOutcome.<a href="./src/praisonai-agents/praisonaiagents/agent/run_outcome.py">from_exception</a>(exc: BaseException, output: Optional[str] = None) -> 'RunOutcome'</code>
* <code title="class RunOutcome">RunOutcome.<a href="./src/praisonai-agents/praisonaiagents/agent/run_outcome.py">succeeded</a>() -> bool</code>
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/embedding/embed.py">aembedding</a>(input: Union[str, List[str]], model: str = 'text-embedding-3-small', dimensions: Optional[int] = None, encoding_format: str = 'float', timeout: float = 600.0, api_key: Optional[str] = None, api_base: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, **kwargs) -> EmbeddingResult</code>
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/embedding/embed.py">aembeddings</a>(input: Union[str, List[str]], model: str = 'text-embedding-3-small', dimensions: Optional[int] = None, encoding_format: str = 'float', timeout: float = 600.0, api_key: Optional[str] = None, api_base: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, **kwargs) -> EmbeddingResult</code>
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/embedding/dimensions.py">get_dimensions</a>(model_name: str) -> int</code>
@@ -820,7 +819,7 @@ Methods:
Types:
```python
from praisonai import Agent, AgentApp, AgentOS, AnthropicManagedAgent, CloudProvider, DB, Deploy, DeployConfig, DeployType, HostedAgent, HostedAgentConfig, LocalAgent, LocalAgentConfig, LocalManagedAgent, LocalManagedConfig, ManagedAgent, ManagedConfig, __version__, arun, run
from praisonai import Agent, AgentApp, AgentOS, AnthropicManagedAgent, DB, HostedAgent, HostedAgentConfig, LocalAgent, LocalAgentConfig, LocalManagedAgent, LocalManagedConfig, ManagedAgent, ManagedConfig, __version__, arun, run
```
# CLI
+10
View File
@@ -0,0 +1,10 @@
# Deployment infra has moved
Deployment assets are no longer at the monorepo root.
| Asset | New location |
|-------|----------------|
| Gateway Helm chart | [`src/praisonai-bot/infra/helm/praisonai-gateway/`](../src/praisonai-bot/infra/helm/praisonai-gateway/) |
| Agents API Helm, Compose, Starters | [`src/praisonai-deploy/infra/`](../src/praisonai-deploy/infra/) |
See [`src/praisonai-deploy/infra/README.md`](../src/praisonai-deploy/infra/README.md).
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=4.6.155" \
"praisonai>=4.6.159" \
"praisonai[chat]" \
"embedchain[github,youtube]"
+1 -1
View File
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=4.6.155" \
"praisonai>=4.6.159" \
"praisonai[ui]" \
"praisonai[chat]" \
"praisonai[realtime]" \
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=4.6.155" \
"praisonai>=4.6.159" \
"praisonai[ui]" \
"praisonai[crewai]"
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
HTTP Approval Example
=====================
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Slack Approval Example
======================
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Completions Capability Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Embeddings Capability Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Images Capability Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Moderations Capability Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Energy Industry Template
========================
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Transportation Industry Template
================================
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
CI Integration Example - Using Doctor in CI/CD pipelines
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Agent-centric Embedding Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
PraisonAI Endpoints Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
Fixed example demonstrating proper guardrail usage with PraisonAI Agents.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
ManagedAgent + ClickHouse Persistence — Real conversation with session resume.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
ManagedAgent + MongoDB Persistence — Real conversation with session resume.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
ManagedAgent + MySQL Persistence — Real conversation with session resume.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
ManagedAgent + PostgreSQL Persistence — Real conversation with session resume.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
ManagedAgent + Redis Persistence — Real conversation with session resume.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
ManagedAgent + SQLite Persistence — Real conversation with session resume.
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
Custom Tools MCP Server Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
HTTP Stream MCP Server Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
MCP Client Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""Multi-Agent Shared Session Demo"""
from praisonaiagents import Agent
from praisonai.persistence import create_conversation_store
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Langfuse Integration Example (Updated for TraceSinkProtocol)
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""MLflow Local Observability Demo (no API key needed)"""
import mlflow
import time
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
ClickHouse — Persistence Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Minimal Agent with Database Persistence
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
MongoDB StateStore — Full Persistence Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
MySQL ConversationStore — Full Persistence Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
PostgreSQL ConversationStore — Full Persistence Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
PostgreSQL with Runs and Traces
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Redis StateStore — Full Persistence Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Session Resume Example
+2 -1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Redis State Store - Agent-First Example
@@ -27,7 +28,7 @@ my_db = db(
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant.",
db=my_db,
memory=my_db,
session_id="redis-state-example"
)
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
PraisonAI A2A Server Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Agent-Centric Autonomy Example.
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
AutoAgents Workflow Patterns Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
Context Agent Example - Basic Usage
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Math Agent Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, MCP
qa_agent = Agent(
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, AgentTeam, Tools
research_agent = Agent(name="Research", instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search])
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, AgentTeam, Tools
research_agent = Agent(name="Research", instructions="You are a research agent to search internet about AI 2024", tools=[Tools.internet_search])
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Secondary Market Research FastAPI Application
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, MCP
search_agent = Agent(
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, AgentTeam
from duckduckgo_search import DDGS
+11 -1
View File
@@ -1,5 +1,15 @@
import threading
import time
from praisonaiagents import Agent
if __name__ == "__main__":
agent = Agent(name="TweetAgent", instructions="Create a Tweet based on the topic provided")
agent.launch(port=8080, protocol="mcp", path="/")
server = threading.Thread(
target=lambda: agent.launch(port=8080, protocol="mcp", path="/mcp"),
daemon=True,
)
server.start()
time.sleep(2)
print("MCP server started on http://127.0.0.1:8080/mcp")
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import AudioAgent
# Text to Speech
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import AudioAgent
agent = AudioAgent(llm="openai/tts-1-hd")
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
# Text-to-Speech with OpenAI
# Requires: export OPENAI_API_KEY=your-key
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import AudioAgent
agent = AudioAgent(llm="elevenlabs/eleven_multilingual_v2")
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import AudioAgent
agent = AudioAgent(llm="gemini/gemini-2.5-flash-preview-tts")
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import AudioAgent
agent = AudioAgent(llm="openai/tts-1")
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Bot Commands Example — Built-in /status, /new, /help commands.
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Bot Gateway Example — Run multiple bots from one gateway server.
+2 -2
View File
@@ -102,7 +102,7 @@ async def demo_with_run_control():
from praisonai.bots._run_control import SessionRunControl
from praisonai.bots._session import BotSessionManager
from praisonai.bots._commands import handle_stop_command
from praisonai.bots._commands import handle_stop_command_async
# Session manager with run control
run_control = SessionRunControl(
@@ -136,7 +136,7 @@ async def demo_with_run_control():
print("\n3. User decides to stop current task:")
print(" User: '/stop'")
stop_response = await handle_stop_command(user_id, run_control)
stop_response = await handle_stop_command_async(user_id, run_control)
print(f" Bot: {stop_response}")
# Wait for first task to complete (it should be cancelled)
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Standalone gateway example (praisonai-bot first).
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""HTTP Approval — serve a local web dashboard for tool approvals."""
from praisonaiagents import Agent
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Basic Camera Integration Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Continuous Camera Monitoring Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Multi-Agent Camera Analysis Example
@@ -46,6 +46,6 @@ custom_cmd = SlashCommand(
alt_names=["mc"]
)
handler.register(custom_cmd)
handler.register_command(custom_cmd)
result = handler.execute("/mycommand arg1 arg2")
print(f"\n=== Custom Command ===\n{result.get('message', '')}")
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Claude Code CLI Integration Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Codex CLI Integration Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Cursor CLI Integration Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
External Agents Integration Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Gemini CLI Integration Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
CSV Processing with PraisonAI Agents
@@ -10,6 +10,18 @@ import os
from praisonaiagents import Agent
from praisonaiagents.knowledge import Knowledge
def _result_items(results):
items = results.results if hasattr(results, "results") else results
return list(items)[:3]
def _result_text(result):
if isinstance(result, dict):
return result.get("memory", result.get("text", str(result)))
return getattr(result, "text", None) or getattr(result, "memory", None) or str(result)
def main():
"""
Demonstrates knowledge search with and without reranking.
@@ -82,9 +94,9 @@ def main():
basic_results = basic_knowledge.search(query, rerank=False)
print(f"Query: {query}")
print(f"Results (limit=3):")
for i, result in enumerate(basic_results[:3]):
text = result.get('memory', result.get('text', str(result)))
score = result.get('score', 'N/A')
for i, result in enumerate(_result_items(basic_results)):
text = _result_text(result)
score = result.get('score', 'N/A') if isinstance(result, dict) else getattr(result, 'score', 'N/A')
print(f" {i+1}. Score: {score}")
print(f" Text: {text[:100]}...")
print()
@@ -94,9 +106,9 @@ def main():
rerank_results = basic_knowledge.search(query, rerank=True)
print(f"Query: {query}")
print(f"Results (limit=3):")
for i, result in enumerate(rerank_results[:3]):
text = result.get('memory', result.get('text', str(result)))
score = result.get('score', 'N/A')
for i, result in enumerate(_result_items(rerank_results)):
text = _result_text(result)
score = result.get('score', 'N/A') if isinstance(result, dict) else getattr(result, 'score', 'N/A')
print(f" {i+1}. Score: {score}")
print(f" Text: {text[:100]}...")
print()
@@ -106,9 +118,9 @@ def main():
default_results = rerank_knowledge.search(query) # Will use default_rerank=True
print(f"Query: {query}")
print(f"Results (limit=3):")
for i, result in enumerate(default_results[:3]):
text = result.get('memory', result.get('text', str(result)))
score = result.get('score', 'N/A')
for i, result in enumerate(_result_items(default_results)):
text = _result_text(result)
score = result.get('score', 'N/A') if isinstance(result, dict) else getattr(result, 'score', 'N/A')
print(f" {i+1}. Score: {score}")
print(f" Text: {text[:100]}...")
print()
@@ -125,9 +137,9 @@ def main():
)
print(f"Query: {query}")
print(f"Advanced results with keyword_search=True, filter_memories=True:")
for i, result in enumerate(advanced_results[:3]):
text = result.get('memory', result.get('text', str(result)))
score = result.get('score', 'N/A')
for i, result in enumerate(_result_items(advanced_results)):
text = _result_text(result)
score = result.get('score', 'N/A') if isinstance(result, dict) else getattr(result, 'score', 'N/A')
print(f" {i+1}. Score: {score}")
print(f" Text: {text[:100]}...")
print()
@@ -138,7 +150,7 @@ def main():
agent = Agent(
name="AI Research Assistant",
instructions="You are an AI research assistant. Use your knowledge base to answer questions about artificial intelligence topics.",
knowledge={**rerank_config, "sources": sample_documents},
knowledge={"sources": sample_documents, "rerank": True},
llm="gpt-4o-mini"
)
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Reasoning Extraction Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
agent = Agent(
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Routing Patterns Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Self-Reflection Details Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Simple CSV URL Processor
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Example: Using Latency Tracking Tool with PraisonAI
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
MCP Server with Latency Tracking Example
@@ -1,3 +1,4 @@
# praisonai: skip=true
#!/usr/bin/env python3
"""
Minimal Example: Latency Tracking for MCP Server
+9 -9
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Model Failover Example - Automatic Provider Switching
@@ -43,9 +44,8 @@ failover_config = FailoverConfig(
retry_delay=1.0,
exponential_backoff=True,
max_retry_delay=60.0,
failover_on_rate_limit=True,
failover_on_timeout=True,
failover_on_error=True,
cooldown_on_rate_limit=60.0,
cooldown_on_error=30.0,
)
# Create failover manager
@@ -62,11 +62,11 @@ def demonstrate_failover():
# Get current status
status = manager.status()
for name, info in status.items():
print(f" {name}:")
print(f" Status: {info.get('status', 'unknown')}")
print(f" Priority: {info.get('priority', 'N/A')}")
print(f" Failures: {info.get('failure_count', 0)}")
for profile_info in status.get("profiles", []):
print(f" {profile_info.get('name', 'unknown')}:")
print(f" Status: {profile_info.get('status', 'unknown')}")
print(f" Priority: {profile_info.get('priority', 'N/A')}")
print(f" Failures: {profile_info.get('failure_count', 0)}")
print()
# Get next available profile
@@ -163,7 +163,7 @@ if __name__ == "__main__":
print(f" {profile.name}:")
print(f" Provider: {profile.provider}")
print(f" Priority: {profile.priority}")
print(f" Rate limit: {profile.rate_limit} req/min")
print(f" Rate limit: {profile.rate_limit_rpm} req/min")
print()
demonstrate_failover()
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Advanced Callback Systems Example
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
import asyncio
import time
from typing import List, Dict
@@ -1,3 +1,4 @@
# praisonai: skip=true
import asyncio
import time
from typing import List, Dict
@@ -1,3 +1,4 @@
# praisonai: skip=true
import asyncio
import time
from typing import List, Dict
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
import json
from e2b_code_interpreter import Sandbox
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import (
Agent,
Task,
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
from typing import List, Dict, Union
from duckduckgo_search import DDGS
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam, error_logs
from duckduckgo_search import DDGS
Loaded 100 of 816 files, more files were not shown because too many files have changed in this diff. Show more