Compare commits

...
Author SHA1 Message Date
praisonai-triage-agent[bot]andMervin Praison 6c41174888 fix: restore test safety plugins and correct core SDK path in conftest
Register the test_gating and network_guard plugins via
config.pluginmanager.import_plugin() in pytest_configure, which is the
supported mechanism for non-top-level conftest files under pytest 9.1.1+.
This restores test gating and network-guard enforcement that was dropped
when pytest_plugins was removed.

Also fix the core SDK sys.path insertion: praisonaiagents lives at
src/praisonai-agents, so traverse two parents ('..','..') to reach
<root>/src, not three.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 13:43:05 +00:00
Hore01 02c1c87d58 fix: Remove pytest_plugins from conftest to resolve pytest error 2026-07-27 14:30:07 +01:00
Hore01 62827f708c fix: stop project config discovery at home directory 2026-07-26 09:14:43 +01: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]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] 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] 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 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] 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
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 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 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
376 changed files with 15585 additions and 1689 deletions

No files matched your search

+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
View File
@@ -782,6 +782,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
-7
View File
@@ -232,13 +232,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:
+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
+1 -1
View File
@@ -2,4 +2,4 @@ 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="/")
agent.launch(port=8080, protocol="mcp", path="/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()
@@ -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
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
from langchain_community.tools import YouTubeSearchTool
from langchain_community.utilities import WikipediaAPIWrapper
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
from datetime import datetime
import asyncio
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent
from pydantic import BaseModel
from typing import List, Optional
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
from praisonaiagents.tools import get_article, get_news_sources, get_articles_from_source, get_trending_topics
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import Agent, Task, AgentTeam
from typing import List, Dict
from duckduckgo_search import DDGS
@@ -12,8 +12,7 @@ Features demonstrated:
- Quality assurance workflows
"""
from praisonaiagents import Agent, Task, AgentTeam
from praisonaiagents.task import TaskOutput
from praisonaiagents import Agent, Task, AgentTeam, TaskOutput
from typing import Tuple, Any
import re
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Production Guardrails Patterns Example
-3
View File
@@ -31,7 +31,6 @@ billing_agent = Agent(
role="Billing Specialist",
goal="Handle all billing-related inquiries and tasks using structured data",
backstory="I am an expert in billing systems, payment processing, and invoice management.",
input_payload_schema=BillingPayload # hypothetical but consistent with design
)
refund_agent = Agent(
@@ -39,7 +38,6 @@ refund_agent = Agent(
role="Refund Specialist",
goal="Process refund requests and handle refund-related issues with validated data",
backstory="I specialize in processing refunds, evaluating refund eligibility, and ensuring customer satisfaction.",
input_payload_schema=RefundPayload
)
technical_support_agent = Agent(
@@ -47,7 +45,6 @@ technical_support_agent = Agent(
role="Technical Support Specialist",
goal="Resolve technical issues and provide technical assistance with structured context",
backstory="I am skilled in troubleshooting technical problems and providing solutions.",
input_payload_schema=TechnicalPayload
)
# Create a triage agent with typed handoffs
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Unified Handoff Configuration Example.
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
from praisonaiagents import ImageAgent
agent = ImageAgent(llm="openai/dall-e-3", style="vivid")
+1
View File
@@ -1,3 +1,4 @@
# praisonai: skip=true
# Image Generation with DALL-E
# Requires: export OPENAI_API_KEY=your-key
@@ -1,3 +1,4 @@
# praisonai: skip=true
"""
Streamlit UI Input Example for PraisonAI
Loaded 100 of 376 files, more files were not shown because too many files have changed in this diff. Show more